diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cf0e5fba537..8032154a7365 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: defaults: run: shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} - timeout-minutes: 600 + timeout-minutes: 240 env: CI_JOB_NAME: ${{ matrix.image }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse diff --git a/Cargo.lock b/Cargo.lock index afeb9faec097..cafc623c185a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3420,6 +3420,7 @@ version = "0.2.0" dependencies = [ "ar", "bstr", + "build_helper", "gimli 0.28.1", "object 0.34.0", "regex", @@ -3514,6 +3515,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" +[[package]] +name = "rustc-stable-hash" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2" + [[package]] name = "rustc-std-workspace-alloc" version = "1.99.0" @@ -3852,6 +3859,7 @@ dependencies = [ "portable-atomic", "rustc-hash", "rustc-rayon", + "rustc-stable-hash", "rustc_arena", "rustc_graphviz", "rustc_index", diff --git a/INSTALL.md b/INSTALL.md index 1c2cecf8ef9b..ded0b59fc6cd 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -215,7 +215,7 @@ python x.py build Right now, building Rust only works with some known versions of Visual Studio. If you have a more recent version installed and the build system doesn't -understand, you may need to force rustbuild to use an older version. +understand, you may need to force bootstrap to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. diff --git a/RELEASES.md b/RELEASES.md index 305da6a3550e..0ecd472efb6e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,161 @@ +Version 1.80 (2024-07-25) +========================== + + + +Language +-------- +- [Document maximum allocation size](https://github.com/rust-lang/rust/pull/116675/) +- [Allow zero-byte offsets and ZST read/writes on arbitrary pointers](https://github.com/rust-lang/rust/pull/117329/) +- [Support C23's variadics without a named parameter](https://github.com/rust-lang/rust/pull/124048/) +- [Stabilize `exclusive_range_pattern` feature](https://github.com/rust-lang/rust/pull/124459/) +- [Guarantee layout and ABI of `Result` in some scenarios](https://github.com/rust-lang/rust/pull/124870) + + + +Compiler +-------- +- [Update cc crate to v1.0.97 allowing additional spectre mitigations on MSVC targets](https://github.com/rust-lang/rust/pull/124892/) +- [Allow field reordering on types marked `repr(packed(1))`](https://github.com/rust-lang/rust/pull/125360/) +- [Add a lint against never type fallback affecting unsafe code](https://github.com/rust-lang/rust/pull/123939/) +- [Disallow cast with trailing braced macro in let-else](https://github.com/rust-lang/rust/pull/125049/) +- [Expand `for_loops_over_fallibles` lint to lint on fallibles behind references.](https://github.com/rust-lang/rust/pull/125156/) +- [self-contained linker: retry linking without `-fuse-ld=lld` on CCs that don't support it](https://github.com/rust-lang/rust/pull/125417/) +- [Do not parse CVarArgs (`...`) as a type in trait bounds](https://github.com/rust-lang/rust/pull/125863/) +- Improvements to LLDB formatting [#124458](https://github.com/rust-lang/rust/pull/124458) [#124500](https://github.com/rust-lang/rust/pull/124500) +- [For the wasm32-wasip2 target default to PIC and do not use `-fuse-ld=lld`](https://github.com/rust-lang/rust/pull/124858/) +- [Add x86_64-unknown-linux-none as a tier 3 target](https://github.com/rust-lang/rust/pull/125023/) +- [Lint on `foo.into_iter()` resolving to `&Box<[T]>: IntoIterator`](https://github.com/rust-lang/rust/pull/124097/) + + + +Libraries +--------- +- [Add `size_of` and `size_of_val` and `align_of` and `align_of_val` to the prelude](https://github.com/rust-lang/rust/pull/123168/) +- [Abort a process when FD ownership is violated](https://github.com/rust-lang/rust/pull/124210/) +- [io::Write::write_fmt: panic if the formatter fails when the stream does not fail](https://github.com/rust-lang/rust/pull/125012/) +- [Panic if `PathBuf::set_extension` would add a path separator](https://github.com/rust-lang/rust/pull/125070/) +- [Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods](https://github.com/rust-lang/rust/pull/121571/) +- [Update `c_char` on AIX to use the correct type](https://github.com/rust-lang/rust/pull/122986/) +- [`offset_of!` no longer returns a temporary](https://github.com/rust-lang/rust/pull/124484/) +- [Handle sigma in `str.to_lowercase` correctly](https://github.com/rust-lang/rust/pull/124773/) +- [Raise `DEFAULT_MIN_STACK_SIZE` to at least 64KiB](https://github.com/rust-lang/rust/pull/126059/) + + + +Stabilized APIs +--------------- +- [`impl Default for Rc`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3CCStr%3E) +- [`impl Default for Rc`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3Cstr%3E) +- [`impl Default for Rc<[T]>`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3C%5BT%5D%3E) +- [`impl Default for Arc`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3Cstr%3E) +- [`impl Default for Arc`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E) +- [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E) +- [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E) +- [`impl FromIterator for Box`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) +- [`impl FromIterator for Box`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E) +- [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html) +- [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html) +- [`Duration::div_duration_f32`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f32) +- [`Duration::div_duration_f64`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f64) +- [`Option::take_if`](https://doc.rust-lang.org/beta/std/option/enum.Option.html#method.take_if) +- [`Seek::seek_relative`](https://doc.rust-lang.org/beta/std/io/trait.Seek.html#method.seek_relative) +- [`BinaryHeap::as_slice`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.as_slice) +- [`NonNull::offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset) +- [`NonNull::byte_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset) +- [`NonNull::add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.add) +- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add) +- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub) +- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub) +- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) +- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from) +- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read) +- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile) +- [`NonNull::read_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_unaligned) +- [`NonNull::write`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write) +- [`NonNull::write_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_volatile) +- [`NonNull::write_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_unaligned) +- [`NonNull::write_bytes`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_bytes) +- [`NonNull::copy_to`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to) +- [`NonNull::copy_to_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to_nonoverlapping) +- [`NonNull::copy_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from) +- [`NonNull::copy_from_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from_nonoverlapping) +- [`NonNull::replace`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.replace) +- [`NonNull::swap`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.swap) +- [`NonNull::drop_in_place`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.drop_in_place) +- [`NonNull::align_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.align_offset) +- [`<[T]>::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_checked) +- [`<[T]>::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_mut_checked) +- [`str::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_checked) +- [`str::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_mut_checked) +- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii) +- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start) +- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end) +- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) +- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) +- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) +- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS) +- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits) +- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits) +- [`Ipv6Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#associatedconstant.BITS) +- [`Ipv6Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.to_bits) +- [`Ipv6Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.from_bits) +- [`Vec::<[T; N]>::into_flattened`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html#method.into_flattened) +- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened) +- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened_mut) + +These APIs are now stable in const contexts: + +- [`<[T]>::last_chunk`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.last_chunk) +- [`BinaryHeap::new`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.new) + + + +Cargo +----- +- [Stabilize `-Zcheck-cfg` as always enabled](https://github.com/rust-lang/cargo/pull/13571/) +- [Warn, rather than fail publish, if a target is excluded](https://github.com/rust-lang/cargo/pull/13713/) +- [Add special `check-cfg` lint config for the `unexpected_cfgs` lint](https://github.com/rust-lang/cargo/pull/13913/) +- [Stabilize `cargo update --precise `](https://github.com/rust-lang/cargo/pull/13974/) +- [Don't change file permissions on `Cargo.toml` when using `cargo add`](https://github.com/rust-lang/cargo/pull/13898/) +- [Support using `cargo fix` on IPv6-only networks](https://github.com/rust-lang/cargo/pull/13907/) + + + +Rustdoc +----- + +- [Allow searching for references](https://github.com/rust-lang/rust/pull/124148/) +- [Stabilize `custom_code_classes_in_docs` feature](https://github.com/rust-lang/rust/pull/124577/) +- [fix: In cross-crate scenarios show enum variants on type aliases of enums](https://github.com/rust-lang/rust/pull/125300/) + + + +Compatibility Notes +------------------- +- [rustfmt estimates line lengths differently when using non-ascii characters](https://github.com/rust-lang/rustfmt/issues/6203) +- [Type aliases are now handled correctly in orphan check](https://github.com/rust-lang/rust/pull/117164/) +- [Allow instructing rustdoc to read from stdin via `-`](https://github.com/rust-lang/rust/pull/124611/) +- [`std::env::{set_var, remove_var}` can no longer be converted to safe function pointers and no longer implement the `Fn` family of traits](https://github.com/rust-lang/rust/pull/124636) +- [Warn (or error) when `Self` constructor from outer item is referenced in inner nested item](https://github.com/rust-lang/rust/pull/124187/) +- [Turn `indirect_structural_match` and `pointer_structural_match` lints into hard errors](https://github.com/rust-lang/rust/pull/124661/) +- [Make `where_clause_object_safety` lint a regular object safety violation](https://github.com/rust-lang/rust/pull/125380/) +- [Turn `proc_macro_back_compat` lint into a hard error.](https://github.com/rust-lang/rust/pull/125596/) +- [Detect unused structs even when implementing private traits](https://github.com/rust-lang/rust/pull/122382/) +- [`std::sync::ReentrantLockGuard` is no longer `Sync` if `T: !Sync`](https://github.com/rust-lang/rust/pull/125527) which means [`std::io::StdoutLock` and `std::io::StderrLock` are no longer Sync](https://github.com/rust-lang/rust/issues/127340) + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- Misc improvements to size of generated html by rustdoc e.g. [#124738](https://github.com/rust-lang/rust/pull/124738/) and [#123734](https://github.com/rust-lang/rust/pull/123734/) +- [MSVC targets no longer depend on libc](https://github.com/rust-lang/rust/pull/124050/) + Version 1.79.0 (2024-06-13) ========================== diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 088ae9ba4410..d2c7b1c0753d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -202,21 +202,18 @@ impl Attribute { } } - // Named `get_tokens` to distinguish it from the `::tokens` method. - pub fn get_tokens(&self) -> TokenStream { - match &self.kind { - AttrKind::Normal(normal) => TokenStream::new( - normal - .tokens - .as_ref() - .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) - .to_attr_token_stream() - .to_token_trees(), - ), - &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( + pub fn token_trees(&self) -> Vec { + match self.kind { + AttrKind::Normal(ref normal) => normal + .tokens + .as_ref() + .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) + .to_attr_token_stream() + .to_token_trees(), + AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone( token::DocComment(comment_kind, self.style, data), self.span, - ), + )], } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index ee068f19332a..a92ef575777c 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -16,7 +16,7 @@ use crate::ast::{AttrStyle, StmtKind}; use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; -use crate::AttrVec; +use crate::{AttrVec, Attribute}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, Lrc}; @@ -179,11 +179,10 @@ impl AttrTokenStream { AttrTokenStream(Lrc::new(tokens)) } - /// Converts this `AttrTokenStream` to a plain `Vec`. - /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened' - /// back to a `TokenStream` of the form `outer_attr attr_target`. - /// If there are inner attributes, they are inserted into the proper - /// place in the attribute target tokens. + /// Converts this `AttrTokenStream` to a plain `Vec`. During + /// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a + /// `TokenStream`, as described in the comment on + /// `attrs_and_tokens_to_token_trees`. pub fn to_token_trees(&self) -> Vec { let mut res = Vec::with_capacity(self.0.len()); for tree in self.0.iter() { @@ -200,51 +199,7 @@ impl AttrTokenStream { )) } AttrTokenTree::AttrsTarget(target) => { - let idx = target - .attrs - .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = target.attrs.split_at(idx); - - let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees(); - if !inner_attrs.is_empty() { - let mut found = false; - // Check the last two trees (to account for a trailing semi) - for tree in target_tokens.iter_mut().rev().take(2) { - if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { - // Inner attributes are only supported on extern blocks, functions, - // impls, and modules. All of these have their inner attributes - // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr] } - // - // Therefore, we can insert them back into the right location - // without needing to do any extra position tracking. - // - // Note: Outline modules are an exception - they can - // have attributes like `#![my_attr]` at the start of a file. - // Support for custom attributes in this position is not - // properly implemented - we always synthesize fake tokens, - // so we never reach this code. - - let mut stream = TokenStream::default(); - for inner_attr in inner_attrs { - stream.push_stream(inner_attr.get_tokens()); - } - stream.push_stream(delim_tokens.clone()); - *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); - found = true; - break; - } - } - - assert!( - found, - "Failed to find trailing delimited group in: {target_tokens:?}" - ); - } - for attr in outer_attrs { - res.extend(attr.get_tokens().0.iter().cloned()); - } - res.extend(target_tokens); + attrs_and_tokens_to_token_trees(&target.attrs, &target.tokens, &mut res); } } } @@ -252,15 +207,76 @@ impl AttrTokenStream { } } +// Converts multiple attributes and the tokens for a target AST node into token trees, and appends +// them to `res`. +// +// Example: if the AST node is "fn f() { blah(); }", then: +// - Simple if no attributes are present, e.g. "fn f() { blah(); }" +// - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }" +// - Trickier if inner attributes are present, because they must be moved within the AST node's +// tokens, e.g. "#[outer] fn f() { #![inner] blah() }" +fn attrs_and_tokens_to_token_trees( + attrs: &[Attribute], + target_tokens: &LazyAttrTokenStream, + res: &mut Vec, +) { + let idx = attrs.partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); + let (outer_attrs, inner_attrs) = attrs.split_at(idx); + + // Add outer attribute tokens. + for attr in outer_attrs { + res.extend(attr.token_trees()); + } + + // Add target AST node tokens. + res.extend(target_tokens.to_attr_token_stream().to_token_trees()); + + // Insert inner attribute tokens. + if !inner_attrs.is_empty() { + let mut found = false; + // Check the last two trees (to account for a trailing semi) + for tree in res.iter_mut().rev().take(2) { + if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { + // Inner attributes are only supported on extern blocks, functions, + // impls, and modules. All of these have their inner attributes + // placed at the beginning of the rightmost outermost braced group: + // e.g. fn foo() { #![my_attr] } + // + // Therefore, we can insert them back into the right location + // without needing to do any extra position tracking. + // + // Note: Outline modules are an exception - they can + // have attributes like `#![my_attr]` at the start of a file. + // Support for custom attributes in this position is not + // properly implemented - we always synthesize fake tokens, + // so we never reach this code. + let mut tts = vec![]; + for inner_attr in inner_attrs { + tts.extend(inner_attr.token_trees()); + } + tts.extend(delim_tokens.0.iter().cloned()); + let stream = TokenStream::new(tts); + *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); + found = true; + break; + } + } + assert!(found, "Failed to find trailing delimited group in: {res:?}"); + } +} + /// Stores the tokens for an attribute target, along /// with its attributes. /// /// This is constructed during parsing when we need to capture -/// tokens. +/// tokens, for `cfg` and `cfg_attr` attributes. /// /// For example, `#[cfg(FALSE)] struct Foo {}` would /// have an `attrs` field containing the `#[cfg(FALSE)]` attr, /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` +/// +/// The `cfg`/`cfg_attr` processing occurs in +/// `StripUnconfigured::configure_tokens`. #[derive(Clone, Debug, Encodable, Decodable)] pub struct AttrsTarget { /// Attributes, both outer and inner. @@ -437,18 +453,10 @@ impl TokenStream { } pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream { - let Some(tokens) = node.tokens() else { - panic!("missing tokens for node: {:?}", node); - }; - let attrs = node.attrs(); - let attr_stream = if attrs.is_empty() { - tokens.to_attr_token_stream() - } else { - let target = - AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)]) - }; - TokenStream::new(attr_stream.to_token_trees()) + let tokens = node.tokens().unwrap_or_else(|| panic!("missing tokens for node: {:?}", node)); + let mut tts = vec![]; + attrs_and_tokens_to_token_trees(node.attrs(), tokens, &mut tts); + TokenStream::new(tts) } pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9cf3182daea5..2178b65727d0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -607,8 +607,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) // does not check the same for lib features unless there's at least one // declared lang feature if !sess.opts.unstable_features.is_nightly_build() { - let lang_features = &features.declared_lang_features; - if lang_features.len() == 0 { + if features.declared_features.is_empty() { return; } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { @@ -624,7 +623,8 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { let name = ident.name; - let stable_since = lang_features + let stable_since = features + .declared_lang_features .iter() .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 00a30dc2240a..59b3c6916cbd 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -553,7 +553,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> { panic!("could not find BorrowIndex for location {location:?}"); }); - trans.gen(index); + trans.gen_(index); } // Make sure there are no remaining borrows for variables diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b1e302e5e27d..c7f6840e401c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4,7 +4,7 @@ #![allow(rustc::untranslatable_diagnostic)] use either::Either; -use hir::ClosureKind; +use hir::{ClosureKind, Path}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; @@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::VarDebugInfoContents; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, @@ -445,6 +446,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } else { (None, &[][..], 0) }; + let mut can_suggest_clone = true; if let Some(def_id) = def_id && let node = self.infcx.tcx.hir_node_by_def_id(def_id) && let Some(fn_sig) = node.fn_sig() @@ -452,24 +454,73 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this parameter takes ownership of the value".to_string(), - ); - let descr = match node.fn_kind() { - Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", - Some(hir::intravisit::FnKind::Method(..)) => "method", - Some(hir::intravisit::FnKind::Closure) => "closure", - }; - span.push_span_label(ident.span, format!("in this {descr}")); - err.span_note( - span, - format!( - "consider changing this parameter type in {descr} `{ident}` to borrow \ - instead if owning the value isn't necessary", - ), - ); + let mut is_mut = false; + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = arg.kind + && let Res::Def(DefKind::TyParam, param_def_id) = path.res + && self + .infcx + .tcx + .predicates_of(def_id) + .instantiate_identity(self.infcx.tcx) + .predicates + .into_iter() + .any(|pred| { + if let ty::ClauseKind::Trait(predicate) = pred.kind().skip_binder() + && [ + self.infcx.tcx.get_diagnostic_item(sym::AsRef), + self.infcx.tcx.get_diagnostic_item(sym::AsMut), + self.infcx.tcx.get_diagnostic_item(sym::Borrow), + self.infcx.tcx.get_diagnostic_item(sym::BorrowMut), + ] + .contains(&Some(predicate.def_id())) + && let ty::Param(param) = predicate.self_ty().kind() + && let generics = self.infcx.tcx.generics_of(def_id) + && let param = generics.type_param(*param, self.infcx.tcx) + && param.def_id == param_def_id + { + if [ + self.infcx.tcx.get_diagnostic_item(sym::AsMut), + self.infcx.tcx.get_diagnostic_item(sym::BorrowMut), + ] + .contains(&Some(predicate.def_id())) + { + is_mut = true; + } + true + } else { + false + } + }) + { + // The type of the argument corresponding to the expression that got moved + // is a type parameter `T`, which is has a `T: AsRef` obligation. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "borrow the value to avoid moving it", + format!("&{}", if is_mut { "mut " } else { "" }), + Applicability::MachineApplicable, + ); + can_suggest_clone = is_mut; + } else { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this parameter takes ownership of the value".to_string(), + ); + let descr = match node.fn_kind() { + Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", + Some(hir::intravisit::FnKind::Method(..)) => "method", + Some(hir::intravisit::FnKind::Closure) => "closure", + }; + span.push_span_label(ident.span, format!("in this {descr}")); + err.span_note( + span, + format!( + "consider changing this parameter type in {descr} `{ident}` to \ + borrow instead if owning the value isn't necessary", + ), + ); + } } let place = &self.move_data.move_paths[mpi].place; let ty = place.ty(self.body, self.infcx.tcx).ty; @@ -487,15 +538,23 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)), .. } = move_spans + && can_suggest_clone { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); - } else if self.suggest_hoisting_call_outside_loop(err, expr) { + } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone { // The place where the type moves would be misleading to suggest clone. // #121466 self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } } - if let Some(pat) = finder.pat { + + self.suggest_ref_for_dbg_args(expr, place, move_span, err); + + // it's useless to suggest inserting `ref` when the span don't comes from local code + if let Some(pat) = finder.pat + && !move_span.is_dummy() + && !self.infcx.tcx.sess.source_map().is_imported(move_span) + { *in_pattern = true; let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; if let Some(pat) = finder.parent_pat { @@ -510,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } + // for dbg!(x) which may take ownership, suggest dbg!(&x) instead + // but here we actually do not check whether the macro name is `dbg!` + // so that we may extend the scope a bit larger to cover more cases + fn suggest_ref_for_dbg_args( + &self, + body: &hir::Expr<'_>, + place: &Place<'tcx>, + move_span: Span, + err: &mut Diag<'infcx>, + ) { + let var_info = self.body.var_debug_info.iter().find(|info| match info.value { + VarDebugInfoContents::Place(ref p) => p == place, + _ => false, + }); + let arg_name = if let Some(var_info) = var_info { + var_info.name + } else { + return; + }; + struct MatchArgFinder { + expr_span: Span, + match_arg_span: Option, + arg_name: Symbol, + } + impl Visitor<'_> for MatchArgFinder { + fn visit_expr(&mut self, e: &hir::Expr<'_>) { + // dbg! is expanded into a match pattern, we need to find the right argument span + if let hir::ExprKind::Match(expr, ..) = &e.kind + && let hir::ExprKind::Path(hir::QPath::Resolved( + _, + path @ Path { segments: [seg], .. }, + )) = &expr.kind + && seg.ident.name == self.arg_name + && self.expr_span.source_callsite().contains(expr.span) + { + self.match_arg_span = Some(path.span); + } + hir::intravisit::walk_expr(self, e); + } + } + + let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name }; + finder.visit_expr(body); + if let Some(macro_arg_span) = finder.match_arg_span { + err.span_suggestion_verbose( + macro_arg_span.shrink_to_lo(), + "consider borrowing instead of transferring ownership", + "&", + Applicability::MachineApplicable, + ); + } + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d258c68b9598..9ad941dabbe6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -821,6 +821,8 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> | TerminatorKind::Return | TerminatorKind::TailCall { .. } | TerminatorKind::CoroutineDrop => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let borrow_set = self.borrow_set.clone(); diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 15c9e9d66fac..efec5db836bb 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -16,9 +16,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -67,7 +67,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "log", "regalloc2", "rustc-hash", @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -203,9 +203,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", "indexmap", @@ -223,9 +223,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] @@ -237,20 +237,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets", @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "mach" @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "object" @@ -284,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "crc32fast", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "indexmap", "memchr", ] @@ -297,9 +297,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -382,9 +382,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.60" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -393,9 +393,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" [[package]] name = "unicode-ident" @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -470,66 +470,66 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index cfa91744a0e8..db9b551bd2a2 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-06-30" +channel = "nightly-2024-07-13" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index c1b7e4b0e076..f0550c23b177 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -34,6 +34,7 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # vendor intrinsics rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic +rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps # exotic linkages rm tests/incremental/hashes/function_interfaces.rs @@ -56,13 +57,13 @@ rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported +rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes # requires LTO rm -r tests/run-make/cdylib rm -r tests/run-make/codegen-options-parsing rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 -rm -r tests/run-make/issue-109934-lto-debuginfo rm -r tests/run-make/no-builtins-lto rm -r tests/run-make/reachable-extern-fn-available-lto @@ -109,6 +110,7 @@ rm -r tests/run-make/symbols-include-type-name rm -r tests/run-make/notify-all-emit-artifacts rm -r tests/run-make/reset-codegen-1 rm -r tests/run-make/inline-always-many-cgu +rm -r tests/run-make/intrinsic-unreachable # giving different but possibly correct results # ============================================= diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 9dc94ab33ea9..fa0de6f9de5e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -395,7 +395,6 @@ pub(crate) fn codegen_terminator_call<'tcx>( crate::intrinsics::codegen_llvm_intrinsic_call( fx, &fx.tcx.symbol_name(instance).name, - fn_args, args, ret_place, target, diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 414d3db1c51a..3f23e0d9e046 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -14,12 +14,12 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn create_dll_import_lib( &self, - _sess: &Session, + sess: &Session, _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &Path, _is_direct_dependency: bool, ) -> PathBuf { - unimplemented!("creating dll imports is not yet supported"); + sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift"); } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index fd34ed88c0b2..0ba163f50aec 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -385,15 +385,43 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant if let Some(section_name) = section_name { let (segment_name, section_name) = if tcx.sess.target.is_like_osx { - let section_name = section_name.as_str(); - if let Some(names) = section_name.split_once(',') { - names - } else { + // See https://github.com/llvm/llvm-project/blob/main/llvm/lib/MC/MCSectionMachO.cpp + let mut parts = section_name.as_str().split(','); + let Some(segment_name) = parts.next() else { tcx.dcx().fatal(format!( "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", section_name )); + }; + let Some(section_name) = parts.next() else { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", + section_name + )); + }; + if section_name.len() > 16 { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: section name bigger than 16 bytes", + section_name + )); } + let section_type = parts.next().unwrap_or("regular"); + if section_type != "regular" && section_type != "cstring_literals" { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not supported: unsupported section type {}", + section_name, section_type, + )); + } + let _attrs = parts.next(); + if parts.next().is_some() { + tcx.dcx().fatal(format!( + "#[link_section = \"{}\"] is not valid for macos target: too many components", + section_name + )); + } + // FIXME(bytecodealliance/wasmtime#8901) set S_CSTRING_LITERALS section type when + // cstring_literals is specified + (segment_name, section_name) } else { ("", section_name.as_str()) }; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs index 65f4c67b21f1..1c6e471cc870 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -39,7 +39,13 @@ impl WriteDebugInfo for ObjectProduct { let section_id = self.object.add_section( segment, name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, + if id == SectionId::DebugStr || id == SectionId::DebugLineStr { + SectionKind::DebugString + } else if id == SectionId::EhFrame { + SectionKind::ReadOnlyData + } else { + SectionKind::Debug + }, ); self.object .section_mut(section_id) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index e50c74b87f60..720a0d8fbf59 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -6,32 +6,16 @@ use crate::prelude::*; pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - generic_args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, span: Span, ) { if intrinsic.starts_with("llvm.aarch64") { - return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call( - fx, - intrinsic, - generic_args, - args, - ret, - target, - ); + return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(fx, intrinsic, args, ret, target); } if intrinsic.starts_with("llvm.x86") { - return llvm_x86::codegen_x86_llvm_intrinsic_call( - fx, - intrinsic, - generic_args, - args, - ret, - target, - span, - ); + return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, args, ret, target, span); } match intrinsic { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index e66bcbf4e40e..f0fb18608e07 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -6,7 +6,6 @@ use crate::prelude::*; pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - _args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 399518e58d8c..e1896138e487 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -10,7 +10,6 @@ use crate::prelude::*; pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, - _args: GenericArgsRef<'tcx>, args: &[Spanned>], ret: CPlace<'tcx>, target: Option, diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index a48c0a4450c2..f47bfdad1312 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -1,5 +1,5 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + no_core, lang_items, intrinsics, unboxed_closures, extern_types, decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, thread_local )] diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index cd82894af18e..e76694700263 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,7 +6,6 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFuncti use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; @@ -482,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( return; } - let mut function_features = function_features + let function_features = function_features .iter() .flat_map(|feat| { llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{f}")) @@ -504,17 +503,6 @@ pub fn from_fn_attrs<'ll, 'tcx>( let name = name.as_str(); to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name)); } - - // The `"wasm"` abi on wasm targets automatically enables the - // `+multivalue` feature because the purpose of the wasm abi is to match - // the WebAssembly specification, which has this feature. This won't be - // needed when LLVM enables this `multivalue` feature by default. - if !cx.tcx.is_closure_like(instance.def_id()) { - let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); - if abi == Abi::Wasm { - function_features.push("+multivalue".to_string()); - } - } } let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index b969fe27a99b..14a944685870 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -66,8 +66,15 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { // For each expression ID that is directly used by one or more mappings, // mark it as not-yet-seen. This indicates that we expect to see a // corresponding `ExpressionUsed` statement during MIR traversal. - for term in function_coverage_info.mappings.iter().flat_map(|m| m.kind.terms()) { - if let CovTerm::Expression(id) = term { + for mapping in function_coverage_info.mappings.iter() { + // Currently we only worry about ordinary code mappings. + // For branch and MC/DC mappings, expressions might not correspond + // to any particular point in the control-flow graph. + // (Keep this in sync with the injection of `ExpressionUsed` + // statements in the `InstrumentCoverage` MIR pass.) + if let MappingKind::Code(term) = mapping.kind + && let CovTerm::Expression(id) = term + { expressions_seen.remove(id); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 08e9e312827c..e0bf6110cdf0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2057,7 +2057,7 @@ extern "C" { AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, - ) -> &'a Value; + ); pub fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 2bd5dfdce83e..dd134ebbe6b1 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -398,7 +398,7 @@ impl<'a> GccLinker<'a> { self.link_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more + // purely to support bootstrap right now, we should get a more // principled solution at some point to force the compiler to pass // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index bcddfe9fb9cb..cea164df6173 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -80,6 +80,8 @@ pub fn from_target_feature( Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, + Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, + Some(sym::xop_target_feature) => rust_features.xop_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d86f1a7a34f2..b227565f8f91 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -20,7 +20,7 @@ use super::{ err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom, throw_ub_format, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, - Scalar, + Provenance, Scalar, }; use crate::fluent_generated as fluent; @@ -259,25 +259,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // This will always return 0. (a, b) } - (Err(_), _) | (_, Err(_)) => { - // We managed to find a valid allocation for one pointer, but not the other. - // That means they are definitely not pointing to the same allocation. + _ if M::Provenance::OFFSET_IS_ADDR && a.addr() == b.addr() => { + // At least one of the pointers has provenance, but they also point to + // the same address so it doesn't matter; this is fine. `(0, 0)` means + // we pass all the checks below and return 0. + (0, 0) + } + // From here onwards, the pointers are definitely for different addresses + // (or we can't determine their absolute address). + (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) + if a_alloc_id == b_alloc_id => + { + // Found allocation for both, and it's the same. + // Use these offsets for distance calculation. + (a_offset.bytes(), b_offset.bytes()) + } + _ => { + // Not into the same allocation -- this is UB. throw_ub_custom!( fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ); } - (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => { - // Found allocation for both. They must be into the same allocation. - if a_alloc_id != b_alloc_id { - throw_ub_custom!( - fluent::const_eval_offset_from_different_allocations, - name = intrinsic_name, - ); - } - // Use these offsets for distance calculation. - (a_offset.bytes(), b_offset.bytes()) - } }; // Compute distance. diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index baaee67e7871..33c25b746ccc 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -995,13 +995,25 @@ where } /// Returns a wide MPlace of type `str` to a new 1-aligned allocation. + /// Immutable strings are deduplicated and stored in global memory. pub fn allocate_str( &mut self, str: &str, kind: MemoryKind, mutbl: Mutability, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; + let tcx = self.tcx.tcx; + + // Use cache for immutable strings. + let ptr = if mutbl.is_not() { + // Use dedup'd allocation function. + let id = tcx.allocate_bytes_dedup(str.as_bytes()); + + // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation. + M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))? + } else { + self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)? + }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c4b2e067bbeb..e5e733439ea0 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "11" rustc-hash = "1.1.0" rustc-rayon = { version = "0.5.0", optional = true } +rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_index = { path = "../rustc_index", package = "rustc_index" } diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 1bee159489dc..30e3d6aa86ce 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -1,5 +1,5 @@ use crate::stable_hasher::impl_stable_traits_for_trivial_type; -use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult}; +use crate::stable_hasher::{FromStableHash, Hash64, StableHasherHash}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::hash::{Hash, Hasher}; @@ -154,10 +154,11 @@ impl FingerprintHasher for crate::unhash::Unhasher { } } -impl StableHasherResult for Fingerprint { +impl FromStableHash for Fingerprint { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); + fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self { Fingerprint(_0, _1) } } diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs index 1564eeb4baee..ef5d2e845ef0 100644 --- a/compiler/rustc_data_structures/src/hashes.rs +++ b/compiler/rustc_data_structures/src/hashes.rs @@ -11,7 +11,7 @@ //! connect the fact that they can only be produced by a `StableHasher` to their //! `Encode`/`Decode` impls. -use crate::stable_hasher::{StableHasher, StableHasherResult}; +use crate::stable_hasher::{FromStableHash, StableHasherHash}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::ops::BitXorAssign; @@ -56,10 +56,12 @@ impl Decodable for Hash64 { } } -impl StableHasherResult for Hash64 { +impl FromStableHash for Hash64 { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - Self { inner: hasher.finalize().0 } + fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self { + Self { inner: _0 } } } @@ -121,10 +123,11 @@ impl Decodable for Hash128 { } } -impl StableHasherResult for Hash128 { +impl FromStableHash for Hash128 { + type Hash = StableHasherHash; + #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); + fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self { Self { inner: u128::from(_0) | (u128::from(_1) << 64) } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 356ddf014bee..3f18b036940b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -24,7 +24,6 @@ #![feature(core_intrinsics)] #![feature(extend_one)] #![feature(hash_raw_entry)] -#![feature(hasher_prefixfree_extras)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -67,7 +66,6 @@ pub mod owned_slice; pub mod packed; pub mod profiling; pub mod sharded; -pub mod sip128; pub mod small_c_str; pub mod snapshot_map; pub mod sorted_map; diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs deleted file mode 100644 index 812ed410a94b..000000000000 --- a/compiler/rustc_data_structures/src/sip128.rs +++ /dev/null @@ -1,505 +0,0 @@ -//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes. - -// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. -// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 -use rustc_serialize::int_overflow::{DebugStrictAdd, DebugStrictSub}; -use std::hash::Hasher; -use std::mem::{self, MaybeUninit}; -use std::ptr; - -#[cfg(test)] -mod tests; - -// The SipHash algorithm operates on 8-byte chunks. -const ELEM_SIZE: usize = mem::size_of::(); - -// Size of the buffer in number of elements, not including the spill. -// -// The selection of this size was guided by rustc-perf benchmark comparisons of -// different buffer sizes. It should be periodically reevaluated as the compiler -// implementation and input characteristics change. -// -// Using the same-sized buffer for everything we hash is a performance versus -// complexity tradeoff. The ideal buffer size, and whether buffering should even -// be used, depends on what is being hashed. It may be worth it to size the -// buffer appropriately (perhaps by making SipHasher128 generic over the buffer -// size) or disable buffering depending on what is being hashed. But at this -// time, we use the same buffer size for everything. -const BUFFER_CAPACITY: usize = 8; - -// Size of the buffer in bytes, not including the spill. -const BUFFER_SIZE: usize = BUFFER_CAPACITY * ELEM_SIZE; - -// Size of the buffer in number of elements, including the spill. -const BUFFER_WITH_SPILL_CAPACITY: usize = BUFFER_CAPACITY + 1; - -// Size of the buffer in bytes, including the spill. -const BUFFER_WITH_SPILL_SIZE: usize = BUFFER_WITH_SPILL_CAPACITY * ELEM_SIZE; - -// Index of the spill element in the buffer. -const BUFFER_SPILL_INDEX: usize = BUFFER_WITH_SPILL_CAPACITY - 1; - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct SipHasher128 { - // The access pattern during hashing consists of accesses to `nbuf` and - // `buf` until the buffer is full, followed by accesses to `state` and - // `processed`, and then repetition of that pattern until hashing is done. - // This is the basis for the ordering of fields below. However, in practice - // the cache miss-rate for data access is extremely low regardless of order. - nbuf: usize, // how many bytes in buf are valid - buf: [MaybeUninit; BUFFER_WITH_SPILL_CAPACITY], // unprocessed bytes le - state: State, // hash State - processed: usize, // how many bytes we've processed -} - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -struct State { - // v0, v2 and v1, v3 show up in pairs in the algorithm, - // and simd implementations of SipHash will use vectors - // of v02 and v13. By placing them in this order in the struct, - // the compiler can pick up on just a few simd optimizations by itself. - v0: u64, - v2: u64, - v1: u64, - v3: u64, -} - -macro_rules! compress { - ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }}; - ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ - $v0 = $v0.wrapping_add($v1); - $v2 = $v2.wrapping_add($v3); - $v1 = $v1.rotate_left(13); - $v1 ^= $v0; - $v3 = $v3.rotate_left(16); - $v3 ^= $v2; - $v0 = $v0.rotate_left(32); - - $v2 = $v2.wrapping_add($v1); - $v0 = $v0.wrapping_add($v3); - $v1 = $v1.rotate_left(17); - $v1 ^= $v2; - $v3 = $v3.rotate_left(21); - $v3 ^= $v0; - $v2 = $v2.rotate_left(32); - }}; -} - -// Copies up to 8 bytes from source to destination. This performs better than -// `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real -// workloads since all of the copies have fixed sizes and avoid calling memcpy. -// -// This is specifically designed for copies of up to 8 bytes, because that's the -// maximum of number bytes needed to fill an 8-byte-sized element on which -// SipHash operates. Note that for variable-sized copies which are known to be -// less than 8 bytes, this function will perform more work than necessary unless -// the compiler is able to optimize the extra work away. -#[inline] -unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { - debug_assert!(count <= 8); - - unsafe { - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); - return; - } - - let mut i = 0; - if i.debug_strict_add(3) < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i = i.debug_strict_add(4); - } - - if i.debug_strict_add(1) < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i = i.debug_strict_add(2) - } - - if i < count { - *dst.add(i) = *src.add(i); - i = i.debug_strict_add(1); - } - - debug_assert_eq!(i, count); - } -} - -// # Implementation -// -// This implementation uses buffering to reduce the hashing cost for inputs -// consisting of many small integers. Buffering simplifies the integration of -// integer input--the integer write function typically just appends to the -// buffer with a statically sized write, updates metadata, and returns. -// -// Buffering also prevents alternating between writes that do and do not trigger -// the hashing process. Only when the entire buffer is full do we transition -// into hashing. This allows us to keep the hash state in registers for longer, -// instead of loading and storing it before and after processing each element. -// -// When a write fills the buffer, a buffer processing function is invoked to -// hash all of the buffered input. The buffer processing functions are marked -// `#[inline(never)]` so that they aren't inlined into the append functions, -// which ensures the more frequently called append functions remain inlineable -// and don't include register pushing/popping that would only be made necessary -// by inclusion of the complex buffer processing path which uses those -// registers. -// -// The buffer includes a "spill"--an extra element at the end--which simplifies -// the integer write buffer processing path. The value that fills the buffer can -// be written with a statically sized write that may spill over into the spill. -// After the buffer is processed, the part of the value that spilled over can be -// written from the spill to the beginning of the buffer with another statically -// sized write. This write may copy more bytes than actually spilled over, but -// we maintain the metadata such that any extra copied bytes will be ignored by -// subsequent processing. Due to the static sizes, this scheme performs better -// than copying the exact number of bytes needed into the end and beginning of -// the buffer. -// -// The buffer is uninitialized, which improves performance, but may preclude -// efficient implementation of alternative approaches. The improvement is not so -// large that an alternative approach should be disregarded because it cannot be -// efficiently implemented with an uninitialized buffer. On the other hand, an -// uninitialized buffer may become more important should a larger one be used. -// -// # Platform Dependence -// -// The SipHash algorithm operates on byte sequences. It parses the input stream -// as 8-byte little-endian integers. Therefore, given the same byte sequence, it -// produces the same result on big- and little-endian hardware. -// -// However, the Hasher trait has methods which operate on multi-byte integers. -// How they are converted into byte sequences can be endian-dependent (by using -// native byte order) or independent (by consistently using either LE or BE byte -// order). It can also be `isize` and `usize` size dependent (by using the -// native size), or independent (by converting to a common size), supposing the -// values can be represented in 32 bits. -// -// In order to make `SipHasher128` consistent with `SipHasher` in libstd, we -// choose to do the integer to byte sequence conversion in the platform- -// dependent way. Clients can achieve platform-independent hashing by widening -// `isize` and `usize` integers to 64 bits on 32-bit systems and byte-swapping -// integers on big-endian systems before passing them to the writing functions. -// This causes the input byte sequence to look identical on big- and little- -// endian systems (supposing `isize` and `usize` values can be represented in 32 -// bits), which ensures platform-independent results. -impl SipHasher128 { - #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { - let mut hasher = SipHasher128 { - nbuf: 0, - buf: [MaybeUninit::uninit(); BUFFER_WITH_SPILL_CAPACITY], - state: State { - v0: key0 ^ 0x736f6d6570736575, - // The XOR with 0xee is only done on 128-bit algorithm version. - v1: key1 ^ (0x646f72616e646f6d ^ 0xee), - v2: key0 ^ 0x6c7967656e657261, - v3: key1 ^ 0x7465646279746573, - }, - processed: 0, - }; - - unsafe { - // Initialize spill because we read from it in `short_write_process_buffer`. - *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); - } - - hasher - } - - #[inline] - pub fn short_write(&mut self, bytes: [u8; LEN]) { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - if nbuf.debug_strict_add(LEN) < BUFFER_SIZE { - unsafe { - // The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - } - - self.nbuf = nbuf.debug_strict_add(LEN); - - return; - } - - unsafe { self.short_write_process_buffer(bytes) } - } - - // A specialized write function for values with size <= 8 that should only - // be called when the write would cause the buffer to fill. - // - // SAFETY: the write of `x` into `self.buf` starting at byte offset - // `self.nbuf` must cause `self.buf` to become fully initialized (and not - // overflow) if it wasn't already. - #[inline(never)] - unsafe fn short_write_process_buffer(&mut self, bytes: [u8; LEN]) { - unsafe { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN >= BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - // Copy first part of input into end of buffer, possibly into spill - // element. The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - - // Process buffer. - for i in 0..BUFFER_CAPACITY { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Copy remaining input into start of buffer by copying LEN - 1 - // elements from spill (at most LEN - 1 bytes could have overflowed - // into the spill). The memcpy call is optimized away because the size - // is known. And the whole copy is optimized away for LEN == 1. - let dst = self.buf.as_mut_ptr() as *mut u8; - let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, dst, LEN - 1); - - // This function should only be called when the write fills the buffer. - // Therefore, when LEN == 1, the new `self.nbuf` must be zero. - // LEN is statically known, so the branch is optimized away. - self.nbuf = - if LEN == 1 { 0 } else { nbuf.debug_strict_add(LEN).debug_strict_sub(BUFFER_SIZE) }; - self.processed = self.processed.debug_strict_add(BUFFER_SIZE); - } - } - - // A write function for byte slices. - #[inline] - fn slice_write(&mut self, msg: &[u8]) { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - - if nbuf.debug_strict_add(length) < BUFFER_SIZE { - unsafe { - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - - if length <= 8 { - copy_nonoverlapping_small(msg.as_ptr(), dst, length); - } else { - // This memcpy is *not* optimized away. - ptr::copy_nonoverlapping(msg.as_ptr(), dst, length); - } - } - - self.nbuf = nbuf.debug_strict_add(length); - - return; - } - - unsafe { self.slice_write_process_buffer(msg) } - } - - // A write function for byte slices that should only be called when the - // write would cause the buffer to fill. - // - // SAFETY: `self.buf` must be initialized up to the byte offset `self.nbuf`, - // and `msg` must contain enough bytes to initialize the rest of the element - // containing the byte offset `self.nbuf`. - #[inline(never)] - unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { - unsafe { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + length >= BUFFER_SIZE); - - // Always copy first part of input into current element of buffer. - // This function should only be called when the write fills the buffer, - // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE.debug_strict_sub(valid_in_elem); - - let src = msg.as_ptr(); - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - copy_nonoverlapping_small(src, dst, needed_in_elem); - - // Process buffer. - - // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / - // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. - // We know that is true, because last step ensured we have a full - // element in the buffer. - let last = (nbuf / ELEM_SIZE).debug_strict_add(1); - - for i in 0..last { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Process the remaining element-sized chunks of input. - let mut processed = needed_in_elem; - let input_left = length.debug_strict_sub(processed); - let elems_left = input_left / ELEM_SIZE; - let extra_bytes_left = input_left % ELEM_SIZE; - - for _ in 0..elems_left { - let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - processed = processed.debug_strict_add(ELEM_SIZE); - } - - // Copy remaining input into start of buffer. - let src = msg.as_ptr().add(processed); - let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, extra_bytes_left); - - self.nbuf = extra_bytes_left; - self.processed = self.processed.debug_strict_add(nbuf.debug_strict_add(processed)); - } - } - - #[inline] - pub fn finish128(mut self) -> (u64, u64) { - debug_assert!(self.nbuf < BUFFER_SIZE); - - // Process full elements in buffer. - let last = self.nbuf / ELEM_SIZE; - - // Since we're consuming self, avoid updating members for a potential - // performance gain. - let mut state = self.state; - - for i in 0..last { - let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() }; - state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= elem; - } - - // Get remaining partial element. - let elem = if self.nbuf % ELEM_SIZE != 0 { - unsafe { - // Ensure element is initialized by writing zero bytes. At most - // `ELEM_SIZE - 1` are required given the above check. It's safe - // to write this many because we have the spill and we maintain - // `self.nbuf` such that this write will start before the spill. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf); - ptr::write_bytes(dst, 0, ELEM_SIZE - 1); - self.buf.get_unchecked(last).assume_init().to_le() - } - } else { - 0 - }; - - // Finalize the hash. - let length = self.processed.debug_strict_add(self.nbuf); - let b: u64 = ((length as u64 & 0xff) << 56) | elem; - - state.v3 ^= b; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= b; - - state.v2 ^= 0xee; - Sip13Rounds::d_rounds(&mut state); - let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - state.v1 ^= 0xdd; - Sip13Rounds::d_rounds(&mut state); - let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - (_0, _1) - } -} - -impl Hasher for SipHasher128 { - #[inline] - fn write_u8(&mut self, i: u8) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.short_write((i as u8).to_ne_bytes()); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.short_write((i as u16).to_ne_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.short_write((i as u32).to_ne_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.short_write((i as u64).to_ne_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - self.short_write((i as usize).to_ne_bytes()); - } - - #[inline] - fn write(&mut self, msg: &[u8]) { - self.slice_write(msg); - } - - #[inline] - fn write_str(&mut self, s: &str) { - // This hasher works byte-wise, and `0xFF` cannot show up in a `str`, - // so just hashing the one extra byte is enough to be prefix-free. - self.write(s.as_bytes()); - self.write_u8(0xFF); - } - - fn finish(&self) -> u64 { - panic!("SipHasher128 cannot provide valid 64 bit hashes") - } -} - -#[derive(Debug, Clone, Default)] -struct Sip13Rounds; - -impl Sip13Rounds { - #[inline] - fn c_rounds(state: &mut State) { - compress!(state); - } - - #[inline] - fn d_rounds(state: &mut State) { - compress!(state); - compress!(state); - compress!(state); - } -} diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs deleted file mode 100644 index e9dd0f1176b9..000000000000 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ /dev/null @@ -1,304 +0,0 @@ -use super::*; - -use std::hash::Hash; - -// Hash just the bytes of the slice, without length prefix -struct Bytes<'a>(&'a [u8]); - -impl<'a> Hash for Bytes<'a> { - #[allow(unused_must_use)] - fn hash(&self, state: &mut H) { - for byte in self.0 { - state.write_u8(*byte); - } - } -} - -fn hash_with(mut st: SipHasher128, x: &T) -> (u64, u64) { - x.hash(&mut st); - st.finish128() -} - -fn hash(x: &T) -> (u64, u64) { - hash_with(SipHasher128::new_with_keys(0, 0), x) -} -#[rustfmt::skip] -const TEST_VECTOR: [[u8; 16]; 64] = [ - [0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01], - [0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63], - [0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95], - [0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43], - [0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25], - [0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e], - [0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8], - [0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77], - [0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99], - [0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42], - [0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4], - [0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e], - [0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65], - [0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44], - [0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78], - [0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09], - [0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93], - [0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec], - [0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b], - [0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9], - [0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7], - [0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef], - [0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79], - [0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59], - [0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a], - [0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2], - [0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64], - [0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93], - [0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14], - [0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86], - [0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06], - [0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10], - [0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3], - [0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b], - [0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9], - [0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f], - [0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40], - [0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10], - [0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93], - [0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c], - [0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38], - [0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3], - [0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02], - [0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56], - [0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a], - [0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58], - [0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8], - [0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37], - [0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08], - [0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f], - [0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66], - [0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a], - [0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca], - [0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b], - [0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b], - [0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22], - [0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84], - [0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10], - [0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69], - [0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e], - [0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61], - [0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7], - [0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18], - [0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad], -]; - -#[test] -fn test_siphash_1_3_test_vector() { - let k0 = 0x_07_06_05_04_03_02_01_00; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; - - let mut input: Vec = Vec::new(); - - for i in 0..64 { - let out = hash_with(SipHasher128::new_with_keys(k0, k1), &Bytes(&input[..])); - let expected = ( - ((TEST_VECTOR[i][0] as u64) << 0) - | ((TEST_VECTOR[i][1] as u64) << 8) - | ((TEST_VECTOR[i][2] as u64) << 16) - | ((TEST_VECTOR[i][3] as u64) << 24) - | ((TEST_VECTOR[i][4] as u64) << 32) - | ((TEST_VECTOR[i][5] as u64) << 40) - | ((TEST_VECTOR[i][6] as u64) << 48) - | ((TEST_VECTOR[i][7] as u64) << 56), - ((TEST_VECTOR[i][8] as u64) << 0) - | ((TEST_VECTOR[i][9] as u64) << 8) - | ((TEST_VECTOR[i][10] as u64) << 16) - | ((TEST_VECTOR[i][11] as u64) << 24) - | ((TEST_VECTOR[i][12] as u64) << 32) - | ((TEST_VECTOR[i][13] as u64) << 40) - | ((TEST_VECTOR[i][14] as u64) << 48) - | ((TEST_VECTOR[i][15] as u64) << 56), - ); - - assert_eq!(out, expected); - input.push(i as u8); - } -} - -#[test] -#[cfg(target_arch = "arm")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86_64")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as usize))); - assert!(hash(&(val as u32)) != hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} - -#[test] -fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); -} - -#[test] -fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - assert!(hash(&val) != hash(&zero_byte(val, 4))); - assert!(hash(&val) != hash(&zero_byte(val, 5))); - assert!(hash(&val) != hash(&zero_byte(val, 6))); - assert!(hash(&val) != hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: usize) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: usize) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert!(s != t && t != u); - assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - - let u = [1, 0, 0, 0]; - let v = (&u[..1], &u[1..3], &u[3..]); - let w = (&u[..], &u[4..4], &u[4..4]); - - assert!(v != w); - assert!(hash(&v) != hash(&w)); -} - -#[test] -fn test_short_write_works() { - let test_u8 = 0xFF_u8; - let test_u16 = 0x1122_u16; - let test_u32 = 0x22334455_u32; - let test_u64 = 0x33445566_778899AA_u64; - let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -1_i8; - let test_i16 = -2_i16; - let test_i32 = -3_i32; - let test_i64 = -4_i64; - let test_i128 = -5_i128; - let test_isize = -6_isize; - - let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write(b"bytes"); - h1.write(b"string"); - h1.write_u8(test_u8); - h1.write_u16(test_u16); - h1.write_u32(test_u32); - h1.write_u64(test_u64); - h1.write_u128(test_u128); - h1.write_usize(test_usize); - h1.write_i8(test_i8); - h1.write_i16(test_i16); - h1.write_i32(test_i32); - h1.write_i64(test_i64); - h1.write_i128(test_i128); - h1.write_isize(test_isize); - - let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(b"bytes"); - h2.write(b"string"); - h2.write(&test_u8.to_ne_bytes()); - h2.write(&test_u16.to_ne_bytes()); - h2.write(&test_u32.to_ne_bytes()); - h2.write(&test_u64.to_ne_bytes()); - h2.write(&test_u128.to_ne_bytes()); - h2.write(&test_usize.to_ne_bytes()); - h2.write(&test_i8.to_ne_bytes()); - h2.write(&test_i16.to_ne_bytes()); - h2.write(&test_i32.to_ne_bytes()); - h2.write(&test_i64.to_ne_bytes()); - h2.write(&test_i128.to_ne_bytes()); - h2.write(&test_isize.to_ne_bytes()); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); -} - -macro_rules! test_fill_buffer { - ($type:ty, $write_method:ident) => {{ - // Test filling and overfilling the buffer from all possible offsets - // for a given integer type and its corresponding write method. - const SIZE: usize = std::mem::size_of::<$type>(); - let input = [42; BUFFER_SIZE]; - let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type; - let x_bytes = &x.to_ne_bytes(); - - for i in 1..=SIZE { - let s = &input[..BUFFER_SIZE - i]; - - let mut h1 = SipHasher128::new_with_keys(7, 13); - h1.write(s); - h1.$write_method(x); - - let mut h2 = SipHasher128::new_with_keys(7, 13); - h2.write(s); - h2.write(x_bytes); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); - } - }}; -} - -#[test] -fn test_fill_buffer() { - test_fill_buffer!(u8, write_u8); - test_fill_buffer!(u16, write_u16); - test_fill_buffer!(u32, write_u32); - test_fill_buffer!(u64, write_u64); - test_fill_buffer!(u128, write_u128); - test_fill_buffer!(usize, write_usize); - - test_fill_buffer!(i8, write_i8); - test_fill_buffer!(i16, write_i16); - test_fill_buffer!(i32, write_i32); - test_fill_buffer!(i64, write_i64); - test_fill_buffer!(i128, write_i128); - test_fill_buffer!(isize, write_isize); -} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index a57f5067dd8d..83883eeba9ca 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -1,8 +1,6 @@ -use crate::sip128::SipHasher128; use rustc_index::bit_set::{self, BitSet}; use rustc_index::{Idx, IndexSlice, IndexVec}; use smallvec::SmallVec; -use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; use std::marker::PhantomData; use std::mem; @@ -13,163 +11,9 @@ mod tests; pub use crate::hashes::{Hash128, Hash64}; -/// When hashing something that ends up affecting properties like symbol names, -/// we want these symbol names to be calculated independently of other factors -/// like what architecture you're compiling *from*. -/// -/// To that end we always convert integers to little-endian format before -/// hashing and the architecture dependent `isize` and `usize` types are -/// extended to 64 bits if needed. -pub struct StableHasher { - state: SipHasher128, -} - -impl fmt::Debug for StableHasher { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.state) - } -} - -pub trait StableHasherResult: Sized { - fn finish(hasher: StableHasher) -> Self; -} - -impl StableHasher { - #[inline] - pub fn new() -> Self { - StableHasher { state: SipHasher128::new_with_keys(0, 0) } - } - - #[inline] - pub fn finish(self) -> W { - W::finish(self) - } -} - -impl StableHasher { - #[inline] - pub fn finalize(self) -> (u64, u64) { - self.state.finish128() - } -} - -impl Hasher for StableHasher { - fn finish(&self) -> u64 { - panic!("use StableHasher::finalize instead"); - } - - #[inline] - fn write(&mut self, bytes: &[u8]) { - self.state.write(bytes); - } - - #[inline] - fn write_str(&mut self, s: &str) { - self.state.write_str(s); - } - - #[inline] - fn write_length_prefix(&mut self, len: usize) { - // Our impl for `usize` will extend it if needed. - self.write_usize(len); - } - - #[inline] - fn write_u8(&mut self, i: u8) { - self.state.write_u8(i); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u128(&mut self, i: u128) { - self.write_u64(i as u64); - self.write_u64((i >> 64) as u64); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - // Always treat usize as u64 so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.state.write_i8(i); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.state.short_write((i as u16).to_le_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.state.short_write((i as u32).to_le_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i128(&mut self, i: i128) { - self.state.write(&(i as u128).to_le_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. Sign extending here is preferable as it means that the - // same negative number hashes the same on both 32 and 64 bit platforms. - let value = i as u64; - - // Cold path - #[cold] - #[inline(never)] - fn hash_value(state: &mut SipHasher128, value: u64) { - state.write_u8(0xFF); - state.short_write(value.to_le_bytes()); - } - - // `isize` values often seem to have a small (positive) numeric value in practice. - // To exploit this, if the value is small, we will hash a smaller amount of bytes. - // However, we cannot just skip the leading zero bytes, as that would produce the same hash - // e.g. if you hash two values that have the same bit pattern when they are swapped. - // See https://github.com/rust-lang/rust/pull/93014 for context. - // - // Therefore, we employ the following strategy: - // 1) When we encounter a value that fits within a single byte (the most common case), we - // hash just that byte. This is the most common case that is being optimized. However, we do - // not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8). - // 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding - // 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two - // `isize`s that fit within a different amount of bytes, they should always produce a different - // byte stream for the hasher. - if value < 0xFF { - self.state.write_u8(value as u8); - } else { - hash_value(&mut self.state, value); - } - } -} +pub use rustc_stable_hash::FromStableHash; +pub use rustc_stable_hash::SipHasher128Hash as StableHasherHash; +pub use rustc_stable_hash::StableSipHasher128 as StableHasher; /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index c8921f6a7784..aab50a13af0e 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -7,71 +7,6 @@ use super::*; // ways). The expected values depend on the hashing algorithm used, so they // need to be updated whenever StableHasher changes its hashing algorithm. -#[test] -fn test_hash_integers() { - // Test that integers are handled consistently across platforms. - let test_u8 = 0xAB_u8; - let test_u16 = 0xFFEE_u16; - let test_u32 = 0x445577AA_u32; - let test_u64 = 0x01234567_13243546_u64; - let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -100_i8; - let test_i16 = -200_i16; - let test_i32 = -300_i32; - let test_i64 = -400_i64; - let test_i128 = -500_i128; - let test_isize = -600_isize; - - let mut h = StableHasher::new(); - test_u8.hash(&mut h); - test_u16.hash(&mut h); - test_u32.hash(&mut h); - test_u64.hash(&mut h); - test_u128.hash(&mut h); - test_usize.hash(&mut h); - test_i8.hash(&mut h); - test_i16.hash(&mut h); - test_i32.hash(&mut h); - test_i64.hash(&mut h); - test_i128.hash(&mut h); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (13997337031081104755, 6178945012502239489); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_usize() { - // Test that usize specifically is handled consistently across platforms. - let test_usize = 0xABCDEF01_usize; - - let mut h = StableHasher::new(); - test_usize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (12037165114281468837, 3094087741167521712); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_isize() { - // Test that isize specifically is handled consistently across platforms. - let test_isize = -7_isize; - - let mut h = StableHasher::new(); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (3979067582695659080, 2322428596355037273); - - assert_eq!(h.finalize(), expected); -} - fn hash>(t: &T) -> Hash128 { let mut h = StableHasher::new(); let ctx = &mut (); diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs index bfcc2e603de4..160af8a65d9c 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs @@ -1,5 +1,6 @@ use std::ptr; +use crate::hashes::Hash128; use crate::stable_hasher::{HashStable, StableHasher}; use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2}; @@ -31,14 +32,13 @@ fn stable_hash_hashes_as_tuple() { let hash_packed = { let mut hasher = StableHasher::new(); tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - - hasher.finalize() + hasher.finish::() }; let hash_tupled = { let mut hasher = StableHasher::new(); (&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - hasher.finalize() + hasher.finish::() }; assert_eq!(hash_packed, hash_tupled); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 40e16b451157..9da4aa84db52 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -187,6 +187,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .filter_map(|tree| match tree.clone() { AttrTokenTree::AttrsTarget(mut target) => { + // Expand any `cfg_attr` attributes. target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&target.attrs) { @@ -195,6 +196,8 @@ impl<'a> StripUnconfigured<'a> { ); Some(AttrTokenTree::AttrsTarget(target)) } else { + // Remove the target if there's a `cfg` attribute and + // the condition isn't satisfied. None } } @@ -253,9 +256,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec { + pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(attr, &self.sess.psess) + rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) else { return vec![]; }; @@ -264,7 +267,7 @@ impl<'a> StripUnconfigured<'a> { if expanded_attrs.is_empty() { self.sess.psess.buffer_lint( rustc_lint_defs::builtin::UNUSED_ATTRIBUTES, - attr.span, + cfg_attr.span, ast::CRATE_NODE_ID, BuiltinLintDiag::CfgAttrNoAttributes, ); @@ -280,20 +283,21 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() + expanded_attrs + .into_iter() + .map(|item| self.expand_cfg_attr_item(cfg_attr, item)) + .collect() } } fn expand_cfg_attr_item( &self, - attr: &Attribute, + cfg_attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.get_tokens(); - // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We // have captured tokens for `attr` itself, but we need to @@ -302,11 +306,11 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let mut orig_trees = orig_tokens.trees(); + let mut orig_trees = cfg_attr.token_trees().into_iter(); let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = orig_trees.next().unwrap().clone() else { - panic!("Bad tokens for attribute {attr:?}"); + panic!("Bad tokens for attribute {cfg_attr:?}"); }; // We don't really have a good span to use for the synthesized `[]` @@ -320,12 +324,12 @@ impl<'a> StripUnconfigured<'a> { .unwrap_or_else(|| panic!("Missing tokens for {item:?}")) .to_attr_token_stream(), ); - let trees = if attr.style == AttrStyle::Inner { + let trees = if cfg_attr.style == AttrStyle::Inner { // For inner attributes, we do the same thing for the `!` in `#![some_attr]` let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = orig_trees.next().unwrap().clone() else { - panic!("Bad tokens for attribute {attr:?}"); + panic!("Bad tokens for attribute {cfg_attr:?}"); }; vec![ AttrTokenTree::Token(pound_token, Spacing::Joint), @@ -340,7 +344,7 @@ impl<'a> StripUnconfigured<'a> { &self.sess.psess.attr_id_generator, item, tokens, - attr.style, + cfg_attr.style, item_span, ); if attr.has_name(sym::crate_type) { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index f082cc2b5699..e671c7682391 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -42,6 +42,10 @@ declare_features! ( // feature-group-start: accepted features // ------------------------------------------------------------------------- + // Note that the version indicates when it got *stabilized*. + // When moving an unstable feature here, set the version number to + // `CURRENT RUSTC VERSION` with ` ` replaced by `_`. + /// Allows `#[target_feature(...)]` on aarch64 platforms (accepted, aarch64_target_feature, "1.61.0", Some(44839)), /// Allows using the `efiapi` ABI. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index bf4293643183..e9d3ce0a0749 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -31,6 +31,10 @@ use std::num::NonZero; #[derive(Debug, Clone)] pub struct Feature { pub name: Symbol, + /// For unstable features: the version the feature was added in. + /// For accepted features: the version the feature got stabilized in. + /// For removed features we are inconsistent; sometimes this is the + /// version it got added, sometimes the version it got removed. pub since: &'static str, issue: Option>, } diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index aea447b2aff1..80a108d2fc87 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -32,6 +32,12 @@ declare_features! ( // feature-group-start: removed features // ------------------------------------------------------------------------- + // Note that the version indicates when it got *removed*. + // When moving an unstable feature here, set the version number to + // `CURRENT RUSTC VERSION` with ` ` replaced by `_`. + // (But not all features below do this properly; many indicate the + // version they got originally added in.) + /// Allows using the `amdgpu-kernel` ABI. (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None), (removed, advanced_slice_patterns, "1.0.0", Some(62254), @@ -215,6 +221,9 @@ declare_features! ( /// Permits specifying whether a function should permit unwinding or abort on unwind. (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")), (removed, visible_private_types, "1.0.0", None, None), + /// Allows `extern "wasm" fn` + (removed, wasm_abi, "CURRENT_RUSTC_VERSION", Some(83788), + Some("non-standard wasm ABI is no longer supported")), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c05cac155b74..1db3774222a0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -248,6 +248,8 @@ declare_features! ( (unstable, auto_traits, "1.50.0", Some(13231)), /// Allows using `box` in patterns (RFC 469). (unstable, box_patterns, "1.0.0", Some(29641)), + /// Allows builtin # foo() syntax + (internal, builtin_syntax, "1.71.0", Some(110680)), /// Allows `#[doc(notable_trait)]`. /// Renamed from `doc_spotlight`. (unstable, doc_notable_trait, "1.52.0", Some(45040)), @@ -361,8 +363,6 @@ declare_features! ( (unstable, async_fn_track_caller, "1.73.0", Some(110011)), /// Allows `for await` loops. (unstable, async_for_loop, "1.77.0", Some(118898)), - /// Allows builtin # foo() syntax - (unstable, builtin_syntax, "1.71.0", Some(110680)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. @@ -621,8 +621,6 @@ declare_features! ( (unstable, try_blocks, "1.29.0", Some(31436)), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (unstable, type_alias_impl_trait, "1.38.0", Some(63063)), - /// Allows the use of type ascription in expressions. - (unstable, type_ascription, "1.6.0", Some(23416)), /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), @@ -640,8 +638,10 @@ declare_features! ( (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), - /// Allows `extern "wasm" fn` - (unstable, wasm_abi, "1.53.0", Some(83788)), + /// Allows use of x86 `AMX` target-feature attributes and intrinsics + (unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)), + /// Allows use of the `xop` target-feature + (unstable, xop_target_feature, "CURRENT_RUSTC_VERSION", Some(127208)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d57fad6ba4c2..3bd7b300758c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2708,6 +2708,13 @@ impl PreciseCapturingArg<'_> { PreciseCapturingArg::Param(param) => param.hir_id, } } + + pub fn name(self) -> Symbol { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.ident.name, + PreciseCapturingArg::Param(param) => param.ident.name, + } + } } /// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param @@ -3211,10 +3218,10 @@ impl<'hir> Item<'hir> { ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body); expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Const(ty, gen, body), (ty, gen, *body); + ItemKind::Const(ty, generics, body), (ty, generics, *body); expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Fn(sig, gen, body), (sig, gen, *body); + ItemKind::Fn(sig, generics, body), (sig, generics, *body); expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk); @@ -3226,25 +3233,25 @@ impl<'hir> Item<'hir> { expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm; expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), - ItemKind::TyAlias(ty, gen), (ty, gen); + ItemKind::TyAlias(ty, generics), (ty, generics); expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty; - expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, gen), (def, gen); + expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics); expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Struct(data, gen), (data, gen); + ItemKind::Struct(data, generics), (data, generics); expect_union, (&VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Union(data, gen), (data, gen); + ItemKind::Union(data, generics), (data, generics); expect_trait, (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), - ItemKind::Trait(is_auto, safety, gen, bounds, items), - (*is_auto, *safety, gen, bounds, items); + ItemKind::Trait(is_auto, safety, generics, bounds, items), + (*is_auto, *safety, generics, bounds, items); expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>), - ItemKind::TraitAlias(gen, bounds), (gen, bounds); + ItemKind::TraitAlias(generics, bounds), (generics, bounds); expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp; } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0acc119115a7..e0aad2991632 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -35,7 +35,6 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::FieldIdx; use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; @@ -85,7 +84,6 @@ pub fn provide(providers: &mut Providers) { coroutine_kind, coroutine_for_closure, is_type_alias_impl_trait, - find_field, ..*providers }; } @@ -914,23 +912,6 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } -fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { - let adt = tcx.adt_def(def_id); - if adt.is_enum() { - return None; - } - - adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { - if field.is_unnamed() { - let field_ty = tcx.type_of(field.did).instantiate_identity(); - let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); - tcx.find_field((adt_def.did(), ident)).map(|_| idx) - } else { - (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) - } - }) -} - #[derive(Clone, Copy)] struct NestedSpan { span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f057dbc013fc..035a3429ed76 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -59,6 +59,8 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use smallvec::SmallVec; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_expr_has_type_or_error( &self, @@ -2318,6 +2320,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { display } + /// Find the position of a field named `ident` in `base_def`, accounting for unnammed fields. + /// Return whether such a field has been found. The path to it is stored in `nested_fields`. + /// `ident` must have been adjusted beforehand. + fn find_adt_field( + &self, + base_def: ty::AdtDef<'tcx>, + ident: Ident, + nested_fields: &mut SmallVec<[(FieldIdx, &'tcx ty::FieldDef); 1]>, + ) -> bool { + // No way to find a field in an enum. + if base_def.is_enum() { + return false; + } + + for (field_idx, field) in base_def.non_enum_variant().fields.iter_enumerated() { + if field.is_unnamed() { + // We have an unnamed field, recurse into the nested ADT to find `ident`. + // If we find it there, return immediately, and `nested_fields` will contain the + // correct path. + nested_fields.push((field_idx, field)); + + let field_ty = self.tcx.type_of(field.did).instantiate_identity(); + let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + if self.find_adt_field(adt_def, ident, &mut *nested_fields) { + return true; + } + + nested_fields.pop(); + } else if field.ident(self.tcx).normalize_to_macros_2_0() == ident { + // We found the field we wanted. + nested_fields.push((field_idx, field)); + return true; + } + } + + false + } + // Check field access expressions fn check_field( &self, @@ -2339,44 +2379,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); - let mut adt_def = *base_def; - let mut last_ty = None; - let mut nested_fields = Vec::new(); - let mut index = None; // we don't care to report errors for a struct if the struct itself is tainted - if let Err(guar) = adt_def.non_enum_variant().has_errors() { + if let Err(guar) = base_def.non_enum_variant().has_errors() { return Ty::new_error(self.tcx(), guar); } - while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) { - let &mut first_idx = index.get_or_insert(idx); - let field = &adt_def.non_enum_variant().fields[idx]; - let field_ty = self.field_ty(expr.span, field, args); - if let Some(ty) = last_ty { - nested_fields.push((ty, idx)); - } - if field.ident(self.tcx).normalize_to_macros_2_0() == ident { - // Save the index of all fields regardless of their visibility in case - // of error recovery. - self.write_field_index(expr.hir_id, first_idx, nested_fields); - let adjustments = self.adjust_steps(&autoderef); - if field.vis.is_accessible_from(def_scope, self.tcx) { - self.apply_adjustments(base, adjustments); - self.register_predicates(autoderef.into_obligations()); - self.tcx.check_stability( - field.did, - Some(expr.hir_id), - expr.span, - None, - ); - return field_ty; - } - private_candidate = Some((adjustments, base_def.did())); - break; + let mut field_path = SmallVec::new(); + if self.find_adt_field(*base_def, ident, &mut field_path) { + let (first_idx, _) = field_path[0]; + let (_, last_field) = field_path.last().unwrap(); + + // Save the index of all fields regardless of their visibility in case + // of error recovery. + let nested_fields = field_path[..] + .array_windows() + .map(|[(_, outer), (inner_idx, _)]| { + let outer_ty = self.field_ty(expr.span, outer, args); + (outer_ty, *inner_idx) + }) + .collect(); + self.write_field_index(expr.hir_id, first_idx, nested_fields); + + let adjustments = self.adjust_steps(&autoderef); + if last_field.vis.is_accessible_from(def_scope, self.tcx) { + self.apply_adjustments(base, adjustments); + self.register_predicates(autoderef.into_obligations()); + + self.tcx.check_stability( + last_field.did, + Some(expr.hir_id), + expr.span, + None, + ); + return self.field_ty(expr.span, last_field, args); } - last_ty = Some(field_ty); - adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + + // The field is not accessible, fall through to error reporting. + private_candidate = Some((adjustments, base_def.did())); } } ty::Tuple(tys) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ab0f356ce91f..9fbb01216bbb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -948,6 +948,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, ); + self.suggest_deref_unwrap_or( + &mut err, + error_span, + 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, @@ -2554,7 +2565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|node| node.generics()) .into_iter() .flat_map(|generics| generics.params) - .find(|gen| &gen.def_id.to_def_id() == res_def_id) + .find(|param| ¶m.def_id.to_def_id() == res_def_id) } else { None } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5f897c74482d..b3b4c5a56fbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -466,21 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { borrow_removal_span, }); return true; - } else if let Some((deref_ty, _)) = - self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1) - && self.can_eq(self.param_env, deref_ty, peeled) - && error_tys_equate_as_ref - { - let sugg = prefix_wrap(".as_deref()"); - err.subdiagnostic(errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }); - return true; - } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() + } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind() + && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. @@ -496,12 +483,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); return true; + } else { + if !error_tys_equate_as_ref { + return false; + } + let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors(); + if let Some((deref_ty, _)) = steps.nth(1) + && self.can_eq(self.param_env, deref_ty, peeled) + { + let sugg = prefix_wrap(".as_deref()"); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + for (deref_ty, n_step) in steps { + if self.can_eq(self.param_env, deref_ty, peeled) { + let explicit_deref = "*".repeat(n_step); + let sugg = prefix_wrap(&format!(".map(|v| &{explicit_deref}v)")); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); + return true; + } + } } } false } + /// If `ty` is `Option`, returns `T, T, None`. + /// If `ty` is `Result`, returns `T, T, Some(E, E)`. + /// Otherwise, returns `None`. fn deconstruct_option_or_result( &self, found_ty: Ty<'tcx>, @@ -1407,6 +1429,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } + // Suggest to change `Option<&Vec>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`. + #[instrument(level = "trace", skip(self, err, provided_expr))] + pub(crate) fn suggest_deref_unwrap_or( + &self, + err: &mut Diag<'_>, + error_span: Span, + callee_ty: Option>, + call_ident: Option, + expected_ty: Ty<'tcx>, + provided_ty: Ty<'tcx>, + provided_expr: &Expr<'tcx>, + is_method: bool, + ) { + if !is_method { + return; + } + let Some(callee_ty) = callee_ty else { + return; + }; + let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else { + return; + }; + let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + "Option" + } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) { + "Result" + } else { + return; + }; + + let Some(call_ident) = call_ident else { + return; + }; + if call_ident.name != sym::unwrap_or { + return; + } + + let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else { + return; + }; + + // NOTE: Can we reuse `suggest_deref_or_ref`? + + // Create an dummy type `&[_]` so that both &[] and `&Vec` can coerce to it. + let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind() + && let ty::Infer(_) = elem_ty.kind() + && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0) + { + let slice = Ty::new_slice(self.tcx, *elem_ty); + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice) + } else { + provided_ty + }; + + if !self.can_coerce(expected_ty, dummy_ty) { + return; + } + let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); + err.multipart_suggestion_verbose( + msg, + vec![ + (call_ident.span, "map_or".to_owned()), + (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()), + ], + Applicability::MachineApplicable, + ); + } + /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a87ee7b45548..bdbdcee6446d 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index fbe8d31370cc..7a5e71599203 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -221,6 +221,10 @@ infer_opaque_hidden_type = infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... + +infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it +infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` + infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a801001eaf98..ce1b0f86d034 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1581,3 +1581,32 @@ pub enum ObligationCauseFailureCode { subdiags: Vec, }, } + +#[derive(Subdiagnostic)] +pub enum AddPreciseCapturing { + #[suggestion( + infer_precise_capturing_new, + style = "verbose", + code = " + use<{concatenated_bounds}>", + applicability = "machine-applicable" + )] + New { + #[primary_span] + span: Span, + new_lifetime: Symbol, + concatenated_bounds: String, + }, + #[suggestion( + infer_precise_capturing_existing, + style = "verbose", + code = "{pre}{new_lifetime}{post}", + applicability = "machine-applicable" + )] + Existing { + #[primary_span] + span: Span, + new_lifetime: Symbol, + pre: &'static str, + post: &'static str, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs index 5a465f46e47d..191cb23184da 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/region.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs @@ -1,5 +1,6 @@ use std::iter; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495, }; @@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::symbol::kw; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol}; use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; @@ -1201,17 +1202,21 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( "", ); if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) { - let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); - nice_region_error::suggest_new_region_bound( - tcx, - &mut err, - fn_returns, - hidden_region.to_string(), - None, - format!("captures `{hidden_region}`"), - None, - Some(reg_info.def_id), - ) + if infcx.tcx.features().precise_capturing { + suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); + } else { + let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); + nice_region_error::suggest_new_region_bound( + tcx, + &mut err, + fn_returns, + hidden_region.to_string(), + None, + format!("captures `{hidden_region}`"), + None, + Some(reg_info.def_id), + ) + } } } ty::RePlaceholder(_) => { @@ -1257,3 +1262,95 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( err } + +fn suggest_precise_capturing<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_def_id: LocalDefId, + captured_lifetime: ty::Region<'tcx>, + diag: &mut Diag<'_>, +) { + let hir::OpaqueTy { bounds, .. } = + tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + + let new_lifetime = Symbol::intern(&captured_lifetime.to_string()); + + if let Some((args, span)) = bounds.iter().find_map(|bound| match bound { + hir::GenericBound::Use(args, span) => Some((args, span)), + _ => None, + }) { + let last_lifetime_span = args.iter().rev().find_map(|arg| match arg { + hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span), + _ => None, + }); + + let first_param_span = args.iter().find_map(|arg| match arg { + hir::PreciseCapturingArg::Param(p) => Some(p.ident.span), + _ => None, + }); + + let (span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span { + (last_lifetime_span.shrink_to_hi(), ", ", "") + } else if let Some(first_param_span) = first_param_span { + (first_param_span.shrink_to_lo(), "", ", ") + } else { + // If we have no args, then have `use<>` and need to fall back to using + // span math. This sucks, but should be reliable due to the construction + // of the `use<>` span. + (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "") + }; + + diag.subdiagnostic(errors::AddPreciseCapturing::Existing { span, new_lifetime, pre, post }); + } else { + let mut captured_lifetimes = FxIndexSet::default(); + let mut captured_non_lifetimes = FxIndexSet::default(); + + let variances = tcx.variances_of(opaque_def_id); + let mut generics = tcx.generics_of(opaque_def_id); + loop { + for param in &generics.own_params { + if variances[param.index as usize] == ty::Bivariant { + continue; + } + + match param.kind { + ty::GenericParamDefKind::Lifetime => { + captured_lifetimes.insert(param.name); + } + ty::GenericParamDefKind::Type { synthetic: true, .. } => { + // FIXME: We can't provide a good suggestion for + // `use<...>` if we have an APIT. Bail for now. + return; + } + ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Const { .. } => { + captured_non_lifetimes.insert(param.name); + } + } + } + + if let Some(parent) = generics.parent { + generics = tcx.generics_of(parent); + } else { + break; + } + } + + if !captured_lifetimes.insert(new_lifetime) { + // Uh, strange. This lifetime appears to already be captured... + return; + } + + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::>() + .join(", "); + + diag.subdiagnostic(errors::AddPreciseCapturing::New { + span: tcx.def_span(opaque_def_id).shrink_to_hi(), + new_lifetime, + concatenated_bounds, + }); + } +} diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index e2ba75dfd190..7d7a6a08bee4 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -691,6 +691,7 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dir, String::from("abc")); + untracked!(dump_mir_exclude_alloc_bytes, true); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into()))); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 4f2d59b4c663..de04d882f516 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -52,10 +52,6 @@ lint_builtin_allow_internal_unsafe = lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition .suggestion = try naming the parameter or explicitly ignoring it -lint_builtin_asm_labels = avoid using named labels in inline assembly - .help = only local labels of the form `:` should be used in inline asm - .note = see the asm section of Rust By Example for more information - lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration @@ -163,6 +159,8 @@ lint_builtin_unreachable_pub = unreachable `pub` {$what} lint_builtin_unsafe_block = usage of an `unsafe` block +lint_builtin_unsafe_extern_block = usage of an `unsafe extern` block + lint_builtin_unsafe_impl = implementation of an `unsafe` trait lint_builtin_unsafe_trait = declaration of an `unsafe` trait @@ -403,6 +401,19 @@ lint_incomplete_include = lint_inner_macro_attribute_unstable = inner macro attributes are unstable +lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly + .label = use a different label that doesn't start with `0` or `1` + .note = an LLVM bug makes these labels ambiguous with a binary literal number + .note = see for more information + +lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly + .help = only local labels of the form `:` should be used in inline asm + .note1 = format arguments may expand to a non-numeric value + .note2 = see the asm section of Rust By Example for more information +lint_invalid_asm_label_named = avoid using named labels in inline assembly + .help = only local labels of the form `:` should be used in inline asm + .note = see the asm section of Rust By Example for more information +lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro lint_invalid_crate_type_value = invalid `crate_type` value .suggestion = did you mean diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 79c8046f9b74..485c214ac9de 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -30,13 +30,13 @@ use crate::{ BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, - BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric, - BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, - BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion, - BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, + BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, + BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, - BuiltinWhileTrue, SuggestChangingAssocTypes, + BuiltinWhileTrue, InvalidAsmLabel, SuggestChangingAssocTypes, }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; @@ -45,7 +45,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; -use rustc_errors::{Applicability, LintDiagnostic, MultiSpan}; +use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -69,7 +69,6 @@ use rustc_target::abi::Abi; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; -use tracing::debug; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -326,6 +325,12 @@ impl EarlyLintPass for UnsafeCode { self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm); } + ast::ItemKind::ForeignMod(ForeignMod { safety, .. }) => { + if let Safety::Unsafe(_) = safety { + self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeExternBlock); + } + } + _ => {} } } @@ -2728,10 +2733,52 @@ declare_lint! { "named labels in inline assembly", } -declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]); +declare_lint! { + /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary + /// digits in the inline `asm!` macro. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![feature(asm_experimental_arch)] + /// use std::arch::asm; + /// + /// fn main() { + /// unsafe { + /// asm!("0: jmp 0b"); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary + /// literal instead of a reference to the previous local label `0`. Note that even though the + /// bug is marked as fixed, it only fixes a specific usage of intel syntax within standalone + /// files, not inline assembly. To work around this bug, don't use labels that could be + /// confused with a binary literal. + /// + /// See the explanation in [Rust By Example] for more details. + /// + /// [LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 + /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels + pub BINARY_ASM_LABELS, + Deny, + "labels in inline assembly containing only 0 or 1 digits", +} -impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { - #[allow(rustc::diagnostic_outside_of_impl)] +declare_lint_pass!(AsmLabels => [NAMED_ASM_LABELS, BINARY_ASM_LABELS]); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum AsmLabelKind { + Named, + FormatArg, + Binary, +} + +impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }), @@ -2759,7 +2806,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { None }; - let mut found_labels = Vec::new(); + // diagnostics are emitted per-template, so this is created here as opposed to the outer loop + let mut spans = Vec::new(); // A semicolon might not actually be specified as a separator for all targets, but // it seems like LLVM accepts it always. @@ -2782,16 +2830,21 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { // Whether a { bracket has been seen and its } hasn't been found yet. let mut in_bracket = false; + let mut label_kind = AsmLabelKind::Named; - // A label starts with an ASCII alphabetic character or . or _ // A label can also start with a format arg, if it's not a raw asm block. if !raw && start == '{' { in_bracket = true; + label_kind = AsmLabelKind::FormatArg; + } else if matches!(start, '0' | '1') { + // Binary labels have only the characters `0` or `1`. + label_kind = AsmLabelKind::Binary; } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) { + // Named labels start with ASCII letters, `.` or `_`. + // anything else is not a label break 'label_loop; } - // Labels continue with ASCII alphanumeric characters, _, or $ for c in chars { // Inside a template format arg, any character is permitted for the // puproses of label detection because we assume that it can be @@ -2812,8 +2865,18 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } else if !raw && c == '{' { // Start of a format arg. in_bracket = true; + label_kind = AsmLabelKind::FormatArg; } else { - if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) { + let can_continue = match label_kind { + // Format arg labels are considered to be named labels for the purposes + // of continuing outside of their {} pair. + AsmLabelKind::Named | AsmLabelKind::FormatArg => { + c.is_ascii_alphanumeric() || matches!(c, '_' | '$') + } + AsmLabelKind::Binary => matches!(c, '0' | '1'), + }; + + if !can_continue { // The potential label had an invalid character inside it, it // cannot be a label. break 'label_loop; @@ -2821,25 +2884,41 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } } - // If all characters passed the label checks, this is likely a label. - found_labels.push(possible_label); + // If all characters passed the label checks, this is a label. + spans.push((find_label_span(possible_label), label_kind)); start_idx = idx + 1; } } - debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels); - - if found_labels.len() > 0 { - let spans = found_labels - .into_iter() - .filter_map(|label| find_label_span(label)) - .collect::>(); - // If there were labels but we couldn't find a span, combine the warnings and - // use the template span. - let target_spans: MultiSpan = - if spans.len() > 0 { spans.into() } else { (*template_span).into() }; - - cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel); + for (span, label_kind) in spans { + let missing_precise_span = span.is_none(); + let span = span.unwrap_or(*template_span); + match label_kind { + AsmLabelKind::Named => { + cx.emit_span_lint( + NAMED_ASM_LABELS, + span, + InvalidAsmLabel::Named { missing_precise_span }, + ); + } + AsmLabelKind::FormatArg => { + cx.emit_span_lint( + NAMED_ASM_LABELS, + span, + InvalidAsmLabel::FormatArg { missing_precise_span }, + ); + } + AsmLabelKind::Binary => { + // the binary asm issue only occurs when using intel syntax + if !options.contains(InlineAsmOptions::ATT_SYNTAX) { + cx.emit_span_lint( + BINARY_ASM_LABELS, + span, + InvalidAsmLabel::Binary { missing_precise_span, span }, + ) + } + } + }; } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b6927cf60b69..8be8996e4c8f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -225,7 +225,7 @@ late_lint_methods!( NoopMethodCall: NoopMethodCall, EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, InvalidAtomicOrdering: InvalidAtomicOrdering, - NamedAsmLabels: NamedAsmLabels, + AsmLabels: AsmLabels, OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 54c73710eca6..308bb73f4cea 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -81,6 +81,8 @@ pub enum BuiltinUnsafe { AllowInternalUnsafe, #[diag(lint_builtin_unsafe_block)] UnsafeBlock, + #[diag(lint_builtin_unsafe_extern_block)] + UnsafeExternBlock, #[diag(lint_builtin_unsafe_trait)] UnsafeTrait, #[diag(lint_builtin_unsafe_impl)] @@ -2047,10 +2049,32 @@ pub struct UnitBindingsDiag { } #[derive(LintDiagnostic)] -#[diag(lint_builtin_asm_labels)] -#[help] -#[note] -pub struct BuiltinNamedAsmLabel; +pub enum InvalidAsmLabel { + #[diag(lint_invalid_asm_label_named)] + #[help] + #[note] + Named { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + }, + #[diag(lint_invalid_asm_label_format_arg)] + #[help] + #[note(lint_note1)] + #[note(lint_note2)] + FormatArg { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + }, + #[diag(lint_invalid_asm_label_binary)] + #[note] + Binary { + #[note(lint_invalid_asm_label_no_span)] + missing_precise_span: bool, + // hack to get a label on the whole span, must match the emitted span + #[label] + span: Span, + }, +} #[derive(Subdiagnostic)] pub enum UnexpectedCfgCargoHelp { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 5ee73dbfdc65..fdb71ad41a75 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -5,8 +5,7 @@ use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifie use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::kw, Span}; -use rustc_trait_selection::traits; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use crate::{LateContext, LateLintPass, LintContext}; @@ -130,24 +129,26 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { .iter_instantiated_copied(cx.tcx, proj.projection_term.args) { let assoc_pred = assoc_pred.fold_with(proj_replacer); - let Ok(assoc_pred) = traits::fully_normalize( - infcx, - traits::ObligationCause::dummy(), - cx.param_env, - assoc_pred, - ) else { - continue; - }; - // If that predicate doesn't hold modulo regions (but passed during type-check), - // then we must've taken advantage of the hack in `project_and_unify_types` where - // we replace opaques with inference vars. Emit a warning! - if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( + let ocx = ObligationCtxt::new(infcx); + let assoc_pred = + ocx.normalize(&traits::ObligationCause::dummy(), cx.param_env, assoc_pred); + if !ocx.select_all_or_error().is_empty() { + // Can't normalize for some reason...? + continue; + } + + ocx.register_obligation(traits::Obligation::new( cx.tcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred, - )) { + )); + + // If that predicate doesn't hold modulo regions (but passed during type-check), + // then we must've taken advantage of the hack in `project_and_unify_types` where + // we replace opaques with inference vars. Emit a warning! + if !ocx.select_all_or_error().is_empty() { // If it's a trait bound and an opaque that doesn't satisfy it, // then we can emit a suggestion to add the bound. let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 3aa852c83045..4c1f78e6bee3 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -197,9 +197,8 @@ fn main() { cfg.define("LLVM_RUSTLLVM", None); } - if tracked_env_var_os("LLVM_NDEBUG").is_some() { + if tracked_env_var_os("LLVM_ASSERTIONS").is_none() { cfg.define("NDEBUG", None); - cfg.debug(false); } rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b6790b7df500..14757b27a375 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1137,20 +1137,15 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, Builder->getOrCreateArray(ArrayRef(DataValue, Count)).get()); } -extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( +extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { - auto Result = Builder->insertDeclare( - unwrap(V), unwrap(VarInfo), - Builder->createExpression( - llvm::ArrayRef(AddrOps, AddrOpsCount)), - DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd)); -#if LLVM_VERSION_GE(19, 0) - return wrap(Result.get()); -#else - return wrap(Result); -#endif + Builder->insertDeclare(unwrap(V), unwrap(VarInfo), + Builder->createExpression( + llvm::ArrayRef(AddrOps, AddrOpsCount)), + DebugLoc(cast(unwrap(DL))), + unwrap(InsertAtEnd)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index a3abbdcf18ca..2743660ab891 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -71,6 +71,8 @@ impl<'a> DiagnosticDerive<'a> { }); // A lifetime of `'a` causes conflicts, but `_sess` is fine. + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let mut imp = structure.gen_impl(quote! { gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self where G: rustc_errors::EmissionGuarantee @@ -148,6 +150,8 @@ impl<'a> LintDiagnosticDerive<'a> { } }); + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let mut imp = structure.gen_impl(quote! { gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self { #[track_caller] diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 46bd80c2df64..f93d89d6c0f0 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -269,6 +269,7 @@ impl DiagnosticDeriveVariantBuilder { let field_binding = &binding_info.binding; let inner_ty = FieldInnerTy::from_type(&field.ty); + let mut seen_label = false; field .attrs @@ -280,6 +281,14 @@ impl DiagnosticDeriveVariantBuilder { } let name = attr.path().segments.last().unwrap().ident.to_string(); + + if name == "primary_span" && seen_label { + span_err(attr.span().unwrap(), format!("`#[primary_span]` must be placed before labels, since it overwrites the span of the diagnostic")).emit(); + } + if name == "label" { + seen_label = true; + } + let needs_clone = name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); let (binding, needs_destructure) = if needs_clone { diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 69014f39925a..7f090f5ebc16 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -86,6 +86,9 @@ impl SubdiagnosticDerive { let diag = &self.diag; let f = &self.f; + + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] let ret = structure.gen_impl(quote! { gen impl rustc_errors::Subdiagnostic for @Self { fn add_to_diag_with<__G, __F>( @@ -100,6 +103,7 @@ impl SubdiagnosticDerive { } } }); + ret } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index beaaadd497d3..2a593340849e 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -220,19 +220,6 @@ pub enum MappingKind { } impl MappingKind { - /// Iterator over all coverage terms in this mapping kind. - pub fn terms(&self) -> impl Iterator { - let zero = || None.into_iter().chain(None); - let one = |a| Some(a).into_iter().chain(None); - let two = |a, b| Some(a).into_iter().chain(Some(b)); - match *self { - Self::Code(term) => one(term), - Self::Branch { true_term, false_term } => two(true_term, false_term), - Self::MCDCBranch { true_term, false_term, .. } => two(true_term, false_term), - Self::MCDCDecision(_) => zero(), - } - } - /// Returns a copy of this mapping kind, in which all coverage terms have /// been replaced with ones returned by the given function. pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 4e95e600b5ab..bdd1eb11a38e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -393,7 +393,6 @@ pub(crate) struct AllocMap<'tcx> { alloc_map: FxHashMap>, /// Used to ensure that statics and functions only get one associated `AllocId`. - /// Should never contain a `GlobalAlloc::Memory`! // // FIXME: Should we just have two separate dedup maps for statics and functions each? dedup: FxHashMap, AllocId>, @@ -433,13 +432,13 @@ impl<'tcx> TyCtxt<'tcx> { } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. - /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we - /// don't want to dedup IDs for "real" memory! + /// Should not be used for mutable memory. fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); - match alloc { - GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} - GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), + if let GlobalAlloc::Memory(mem) = alloc { + if mem.inner().mutability.is_mut() { + bug!("trying to dedup-reserve mutable memory"); + } } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { return alloc_id; @@ -451,6 +450,12 @@ impl<'tcx> TyCtxt<'tcx> { id } + /// Generates an `AllocId` for a memory allocation. If the exact same memory has been + /// allocated before, this will return the same `AllocId`. + pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>) -> AllocId { + self.reserve_and_set_dedup(GlobalAlloc::Memory(mem)) + } + /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 82625ae3d474..223249952dc7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1545,6 +1545,9 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display // We are done. return write!(w, " {{}}"); } + if tcx.sess.opts.unstable_opts.dump_mir_exclude_alloc_bytes { + return write!(w, " {{ .. }}"); + } // Write allocation bytes. writeln!(w, " {{")?; write_allocation_bytes(tcx, alloc, w, " ")?; diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 0d3c419748b7..0031ded24406 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1016,14 +1016,14 @@ macro_rules! extra_body_methods { macro_rules! super_body { ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => { let span = $body.span; - if let Some(gen) = &$($mutability)? $body.coroutine { - if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { + if let Some(coroutine) = &$($mutability)? $body.coroutine { + if let Some(yield_ty) = $(& $mutability)? coroutine.yield_ty { $self.visit_ty( yield_ty, TyContext::YieldTy(SourceInfo::outermost(span)) ); } - if let Some(resume_ty) = $(& $mutability)? gen.resume_ty { + if let Some(resume_ty) = $(& $mutability)? coroutine.resume_ty { $self.visit_ty( resume_ty, TyContext::ResumeTy(SourceInfo::outermost(span)) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 33c27d41d864..817c7157b682 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2280,10 +2280,6 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } - - query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option { - desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) } - } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 7bc4c60f1027..f659bf8125a0 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -8,10 +8,6 @@ use crate::ty::{ self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; -mod cache; - -pub use cache::EvaluationCache; - pub type Goal<'tcx, P> = ir::solve::Goal, P>; pub type QueryInput<'tcx, P> = ir::solve::QueryInput, P>; pub type QueryResult<'tcx> = ir::solve::QueryResult>; diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs deleted file mode 100644 index 72a8d4eb4050..000000000000 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ /dev/null @@ -1,121 +0,0 @@ -use super::{inspect, CanonicalInput, QueryResult}; -use crate::ty::TyCtxt; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lock; -use rustc_query_system::cache::WithDepNode; -use rustc_query_system::dep_graph::DepNodeIndex; -use rustc_session::Limit; -use rustc_type_ir::solve::CacheData; - -/// The trait solver cache used by `-Znext-solver`. -/// -/// FIXME(@lcnr): link to some official documentation of how -/// this works. -#[derive(Default)] -pub struct EvaluationCache<'tcx> { - map: Lock, CacheEntry<'tcx>>>, -} - -impl<'tcx> rustc_type_ir::inherent::EvaluationCache> for &'tcx EvaluationCache<'tcx> { - /// Insert a final result into the global cache. - fn insert( - &self, - tcx: TyCtxt<'tcx>, - key: CanonicalInput<'tcx>, - proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, - additional_depth: usize, - encountered_overflow: bool, - cycle_participants: FxHashSet>, - dep_node: DepNodeIndex, - result: QueryResult<'tcx>, - ) { - let mut map = self.map.borrow_mut(); - let entry = map.entry(key).or_default(); - let data = WithDepNode::new(dep_node, QueryData { result, proof_tree }); - entry.cycle_participants.extend(cycle_participants); - if encountered_overflow { - entry.with_overflow.insert(additional_depth, data); - } else { - entry.success = Some(Success { data, additional_depth }); - } - - if cfg!(debug_assertions) { - drop(map); - let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow }; - let actual = self.get(tcx, key, [], additional_depth); - if !actual.as_ref().is_some_and(|actual| expected == *actual) { - bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}"); - } - } - } - - /// Try to fetch a cached result, checking the recursion limit - /// and handling root goals of coinductive cycles. - /// - /// If this returns `Some` the cache result can be used. - fn get( - &self, - tcx: TyCtxt<'tcx>, - key: CanonicalInput<'tcx>, - stack_entries: impl IntoIterator>, - available_depth: usize, - ) -> Option>> { - let map = self.map.borrow(); - let entry = map.get(&key)?; - - for stack_entry in stack_entries { - if entry.cycle_participants.contains(&stack_entry) { - return None; - } - } - - if let Some(ref success) = entry.success { - if Limit(available_depth).value_within_limit(success.additional_depth) { - let QueryData { result, proof_tree } = success.data.get(tcx); - return Some(CacheData { - result, - proof_tree, - additional_depth: success.additional_depth, - encountered_overflow: false, - }); - } - } - - entry.with_overflow.get(&available_depth).map(|e| { - let QueryData { result, proof_tree } = e.get(tcx); - CacheData { - result, - proof_tree, - additional_depth: available_depth, - encountered_overflow: true, - } - }) - } -} - -struct Success<'tcx> { - data: WithDepNode>, - additional_depth: usize, -} - -#[derive(Clone, Copy)] -pub struct QueryData<'tcx> { - pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, -} - -/// The cache entry for a goal `CanonicalInput`. -/// -/// This contains results whose computation never hit the -/// recursion limit in `success`, and all results which hit -/// the recursion limit in `with_overflow`. -#[derive(Default)] -struct CacheEntry<'tcx> { - success: Option>, - /// We have to be careful when caching roots of cycles. - /// - /// See the doc comment of `StackEntry::cycle_participants` for more - /// details. - cycle_participants: FxHashSet>, - with_overflow: FxHashMap>>, -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aee42bfe3aac..25070e6b042c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -59,6 +59,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -75,7 +76,7 @@ use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::SolverMode; use rustc_type_ir::TyKind::*; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -164,12 +165,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Clause = Clause<'tcx>; type Clauses = ty::Clauses<'tcx>; - type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>; + type Tracked = WithDepNode; + fn mk_tracked( + self, + data: T, + dep_node: DepNodeIndex, + ) -> Self::Tracked { + WithDepNode::new(dep_node, data) + } + fn get_tracked(self, tracked: &Self::Tracked) -> T { + tracked.get(self) + } - fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> { + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R { match mode { - SolverMode::Normal => &self.new_solver_evaluation_cache, - SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache, + SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()), + SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()), } } @@ -1283,8 +1298,8 @@ pub struct GlobalCtxt<'tcx> { pub evaluation_cache: traits::EvaluationCache<'tcx>, /// Caches the results of goal evaluation in the new solver. - pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>, - pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>, + pub new_solver_evaluation_cache: Lock>>, + pub new_solver_coherence_evaluation_cache: Lock>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, @@ -1427,11 +1442,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Allocates a read-only byte or string literal for `mir::interpret`. - pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { + /// Returns the same `AllocId` if called again with the same bytes. + pub fn allocate_bytes_dedup(self, bytes: &[u8]) -> interpret::AllocId { // Create an allocation that just contains these bytes. let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes); let alloc = self.mk_const_alloc(alloc); - self.reserve_and_set_memory_alloc(alloc) + self.reserve_and_set_memory_dedup(alloc) } /// Returns a range of the start/end indices specified with the diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index c50a98e88fd6..6e64e9bc4f87 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -541,7 +541,9 @@ impl<'tcx> Instance<'tcx> { // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - if !tcx.type_length_limit().value_within_limit(type_length(args)) { + if tcx.sess.opts.unstable_opts.enforce_type_length_limit + && !tcx.type_length_limit().value_within_limit(type_length(args)) + { return Ok(None); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index eb25aecd9cef..22a6786665ca 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1212,7 +1212,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | RiscvInterruptM | RiscvInterruptS | CCmseNonSecureCall - | Wasm | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3b69058d3cb4..be62a3d37365 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -140,7 +140,7 @@ fn lit_to_mir_constant<'tcx>( ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes(data); + let id = tcx.allocate_bytes_dedup(data); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs new file mode 100644 index 000000000000..2f540478674d --- /dev/null +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -0,0 +1,254 @@ +use rustc_middle::mir::*; +use rustc_middle::thir::{self, *}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; + +use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::matches::{FlatPat, MatchPair, TestCase}; +use crate::build::Builder; + +impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Builds and returns [`MatchPair`] trees, one for each pattern in + /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or + /// [`PatKind::Leaf`]. + /// + /// Used internally by [`MatchPair::new`]. + fn field_match_pairs<'pat>( + &mut self, + place: PlaceBuilder<'tcx>, + subpatterns: &'pat [FieldPat<'tcx>], + ) -> Vec> { + subpatterns + .iter() + .map(|fieldpat| { + let place = + place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); + MatchPair::new(place, &fieldpat.pattern, self) + }) + .collect() + } + + /// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an + /// array pattern or slice pattern, and adds those trees to `match_pairs`. + /// + /// Used internally by [`MatchPair::new`]. + fn prefix_slice_suffix<'pat>( + &mut self, + match_pairs: &mut Vec>, + place: &PlaceBuilder<'tcx>, + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], + ) { + let tcx = self.tcx; + let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { + match place_resolved.ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; + + match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + let elem = + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + MatchPair::new(place.clone_project(elem), subpattern, self) + })); + + if let Some(subslice_pat) = opt_slice { + let suffix_len = suffix.len() as u64; + let subslice = place.clone_project(PlaceElem::Subslice { + from: prefix.len() as u64, + to: if exact_size { min_length - suffix_len } else { suffix_len }, + from_end: !exact_size, + }); + match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); + } + + match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { + let end_offset = (idx + 1) as u64; + let elem = ProjectionElem::ConstantIndex { + offset: if exact_size { min_length - end_offset } else { end_offset }, + min_length, + from_end: !exact_size, + }; + let place = place.clone_project(elem); + MatchPair::new(place, subpattern, self) + })); + } +} + +impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { + /// Recursively builds a `MatchPair` tree for the given pattern and its + /// subpatterns. + pub(in crate::build) fn new( + mut place_builder: PlaceBuilder<'tcx>, + pattern: &'pat Pat<'tcx>, + cx: &mut Builder<'_, 'tcx>, + ) -> MatchPair<'pat, 'tcx> { + // Force the place type to the pattern's type. + // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? + if let Some(resolved) = place_builder.resolve_upvar(cx) { + place_builder = resolved; + } + + // Only add the OpaqueCast projection if the given place is an opaque type and the + // expected type from the pattern is not. + let may_need_cast = match place_builder.base() { + PlaceBase::Local(local) => { + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; + ty != pattern.ty && ty.has_opaque_types() + } + _ => true, + }; + if may_need_cast { + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); + } + + let place = place_builder.try_to_place(cx); + let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; + let mut subpairs = Vec::new(); + let test_case = match pattern.kind { + PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + + PatKind::Or { ref pats } => TestCase::Or { + pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), + }, + + PatKind::Range(ref range) => { + if range.is_full_range(cx.tcx) == Some(true) { + default_irrefutable() + } else { + TestCase::Range(range) + } + } + + PatKind::Constant { value } => TestCase::Constant { value }, + + PatKind::AscribeUserType { + ascription: thir::Ascription { ref annotation, variance }, + ref subpattern, + .. + } => { + // Apply the type ascription to the value at `match_pair.place` + let ascription = place.map(|source| super::Ascription { + annotation: annotation.clone(), + source, + variance, + }); + + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Binding { mode, var, ref subpattern, .. } => { + let binding = place.map(|source| super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + + if let Some(subpattern) = subpattern.as_ref() { + // this is the `x @ P` case; have to keep matching against `P` now + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + } + TestCase::Irrefutable { ascription: None, binding } + } + + PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + let ascription = place.map(|source| { + let span = pattern.span; + let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + cx.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), + ty: cx.infcx.next_ty_var(span), + }, + ) + .args; + let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + super::Ascription { annotation, source, variance: ty::Contravariant } + }); + + subpairs.push(MatchPair::new(place_builder, pattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Array { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + default_irrefutable() + } + PatKind::Slice { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + + if prefix.is_empty() && slice.is_some() && suffix.is_empty() { + default_irrefutable() + } else { + TestCase::Slice { + len: prefix.len() + suffix.len(), + variable_length: slice.is_some(), + } + } + } + + PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { + let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` + subpairs = cx.field_match_pairs(downcast_place, subpatterns); + + let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { + i == variant_index || { + (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && !v + .inhabited_predicate(cx.tcx, adt_def) + .instantiate(cx.tcx, args) + .apply_ignore_module(cx.tcx, cx.param_env) + } + }) && (adt_def.did().is_local() + || !adt_def.is_variant_list_non_exhaustive()); + if irrefutable { + default_irrefutable() + } else { + TestCase::Variant { adt_def, variant_index } + } + } + + PatKind::Leaf { ref subpatterns } => { + subpairs = cx.field_match_pairs(place_builder, subpatterns); + default_irrefutable() + } + + PatKind::Deref { ref subpattern } => { + subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); + default_irrefutable() + } + + PatKind::DerefPattern { ref subpattern, mutability } => { + // Create a new temporary for each deref pattern. + // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? + let temp = cx.temp( + Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), + pattern.span, + ); + subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); + TestCase::Deref { temp, mutability } + } + + PatKind::Never => TestCase::Never, + }; + + MatchPair { place, test_case, subpairs, pattern } + } +} diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5695c881ecc2..98de4df3ce39 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -24,6 +24,7 @@ use tracing::{debug, instrument}; use util::visit_bindings; // helper functions, broken out by category: +mod match_pair; mod simplify; mod test; mod util; @@ -1119,6 +1120,11 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { } } + /// Returns whether the first match pair of this candidate is an or-pattern. + fn starts_with_or_pattern(&self) -> bool { + matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..]) + } + /// Visit the leaf candidates (those with no subcandidates) contained in /// this candidate. fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) { @@ -1190,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> { } } +/// Node in a tree of "match pairs", where each pair consists of a place to be +/// tested, and a test to perform on that place. +/// +/// Each node also has a list of subpairs (possibly empty) that must also match, +/// and a reference to the THIR pattern it represents. #[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { /// This place... - // This can be `None` if it referred to a non-captured place in a closure. - // Invariant: place.is_none() => test_case is Irrefutable - // In other words this must be `Some(_)` after simplification. + /// + /// --- + /// This can be `None` if it referred to a non-captured place in a closure. + /// + /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. + /// Therefore this must be `Some(_)` after simplification. place: Option>, /// ... must pass this test... - // Invariant: after creation and simplification in `Candidate::new()`, this must not be - // `Irrefutable`. + /// + /// --- + /// Invariant: after creation and simplification in [`FlatPat::new`], + /// this must not be [`TestCase::Irrefutable`]. test_case: TestCase<'pat, 'tcx>, /// ... and these subpairs must match. @@ -1308,11 +1324,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], refutable: bool, ) -> BasicBlock { + // This will generate code to test scrutinee_place and branch to the appropriate arm block. // See the doc comment on `match_candidates` for why we have an otherwise block. - let otherwise_block = self.cfg.start_new_block(); - - // This will generate code to test scrutinee_place and branch to the appropriate arm block - self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); + let otherwise_block = + self.match_candidates(match_start_span, scrutinee_span, block, candidates); // Link each leaf candidate to the `false_edge_start_block` of the next one. let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; @@ -1363,27 +1378,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block } - /// The main match algorithm. It begins with a set of candidates - /// `candidates` and has the job of generating code to determine - /// which of these candidates, if any, is the correct one. The + /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of + /// generating code that branches to an appropriate block if the scrutinee matches one of these + /// candidates. The /// candidates are sorted such that the first item in the list /// has the highest priority. When a candidate is found to match /// the value, we will set and generate a branch to the appropriate /// pre-binding block. /// - /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`. + /// If none of the candidates apply, we continue to the returned `otherwise_block`. /// /// It might be surprising that the input can be non-exhaustive. - /// Indeed, initially, it is not, because all matches are + /// Indeed, for matches, initially, it is not, because all matches are /// exhaustive in Rust. But during processing we sometimes divide /// up the list of candidates and recurse with a non-exhaustive /// list. This is how our lowering approach (called "backtracking /// automaton" in the literature) works. /// See [`Builder::test_candidates`] for more details. /// - /// If `fake_borrows` is `Some`, then places which need fake borrows - /// will be added to it. - /// /// For an example of how we use `otherwise_block`, consider: /// ``` /// # fn foo((x, y): (bool, bool)) -> u32 { @@ -1408,7 +1420,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// } /// if y { /// if x { - /// // This is actually unreachable because the `(true, true)` case was handled above. + /// // This is actually unreachable because the `(true, true)` case was handled above, + /// // but we don't know that from within the lowering algorithm. /// // continue /// } else { /// return 3 @@ -1425,161 +1438,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`]. /// /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller - /// code size at the expense of non-optimal code paths. + /// code size so we accept non-optimal code paths. #[instrument(skip(self), level = "debug")] - fn match_candidates<'pat>( + fn match_candidates( &mut self, span: Span, scrutinee_span: Span, start_block: BasicBlock, - otherwise_block: BasicBlock, - candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) { - // We process or-patterns here. If any candidate starts with an or-pattern, we have to - // expand the or-pattern before we can proceed further. - // - // We can't expand them freely however. The rule is: if the candidate has an or-pattern as - // its only remaining match pair, we can expand it freely. If it has other match pairs, we - // can expand it but we can't process more candidates after it. - // - // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following, - // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2` - // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same - // set of candidates, when we reach the block that tests `false` we don't know whether we - // came from `1` or `2`, hence we can't know where to branch on failure. - // ```ignore(illustrative) - // match (1, true) { - // (1 | 2, false) => {}, - // (2, _) => {}, - // _ => {} - // } - // ``` - // - // We therefore split the `candidates` slice in two, expand or-patterns in the first half, - // and process both halves separately. - let mut expand_until = 0; - for (i, candidate) in candidates.iter().enumerate() { - if matches!( - &*candidate.match_pairs, - [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] - ) { - expand_until = i + 1; - if candidate.match_pairs.len() > 1 { - break; - } - } - if expand_until != 0 { - expand_until = i + 1; - } - } - let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); - + candidates: &mut [&mut Candidate<'_, 'tcx>], + ) -> BasicBlock { ensure_sufficient_stack(|| { - if candidates_to_expand.is_empty() { - // No candidates start with an or-pattern, we can continue. - self.match_expanded_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - remaining_candidates, - ); - } else { - // Expand one level of or-patterns for each candidate in `candidates_to_expand`. - let mut expanded_candidates = Vec::new(); - for candidate in candidates_to_expand.iter_mut() { - if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = - &*candidate.match_pairs - { - let or_match_pair = candidate.match_pairs.remove(0); - // Expand the or-pattern into subcandidates. - self.create_or_subcandidates(candidate, or_match_pair); - // Collect the newly created subcandidates. - for subcandidate in candidate.subcandidates.iter_mut() { - expanded_candidates.push(subcandidate); - } - } else { - expanded_candidates.push(candidate); - } - } - - // Process the expanded candidates. - let remainder_start = self.cfg.start_new_block(); - // There might be new or-patterns obtained from expanding the old ones, so we call - // `match_candidates` again. - self.match_candidates( - span, - scrutinee_span, - start_block, - remainder_start, - expanded_candidates.as_mut_slice(), - ); - - // Simplify subcandidates and process any leftover match pairs. - for candidate in candidates_to_expand { - if !candidate.subcandidates.is_empty() { - self.finalize_or_candidate(span, scrutinee_span, candidate); - } - } - - // Process the remaining candidates. - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); - } - }); + self.match_candidates_inner(span, scrutinee_span, start_block, candidates) + }) } - /// Construct the decision tree for `candidates`. Caller must ensure that no candidate in - /// `candidates` starts with an or-pattern. - fn match_expanded_candidates( + /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates` + /// instead to reserve sufficient stack space. + fn match_candidates_inner( &mut self, span: Span, scrutinee_span: Span, mut start_block: BasicBlock, - otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], - ) { + ) -> BasicBlock { if let [first, ..] = candidates { if first.false_edge_start_block.is_none() { first.false_edge_start_block = Some(start_block); } } - match candidates { + // Process a prefix of the candidates. + let rest = match candidates { [] => { - // If there are no candidates that still need testing, we're done. Since all matches are - // exhaustive, execution should never reach this point. - let source_info = self.source_info(span); - self.cfg.goto(start_block, source_info, otherwise_block); + // If there are no candidates that still need testing, we're done. + return start_block; } [first, remaining @ ..] if first.match_pairs.is_empty() => { // The first candidate has satisfied all its match pairs; we link it up and continue // with the remaining candidates. - start_block = self.select_matched_candidate(first, start_block); - self.match_expanded_candidates( - span, - scrutinee_span, - start_block, - otherwise_block, - remaining, - ) + let remainder_start = self.select_matched_candidate(first, start_block); + remainder_start.and(remaining) + } + candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => { + // If any candidate starts with an or-pattern, we have to expand the or-pattern before we + // can proceed further. + self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates) } candidates => { // The first candidate has some unsatisfied match pairs; we proceed to do more tests. - self.test_candidates( - span, - scrutinee_span, - candidates, - start_block, - otherwise_block, - ); + self.test_candidates(span, scrutinee_span, candidates, start_block) } - } + }; + + // Process any candidates that remain. + let remaining_candidates = unpack!(start_block = rest); + self.match_candidates(span, scrutinee_span, start_block, remaining_candidates) } /// Link up matched candidates. @@ -1624,6 +1537,102 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block } + /// Takes a list of candidates such that some of the candidates' first match pairs are + /// or-patterns. This expands as many or-patterns as possible and processes the resulting + /// candidates. Returns the unprocessed candidates if any. + fn expand_and_match_or_candidates<'pat, 'b, 'c>( + &mut self, + span: Span, + scrutinee_span: Span, + start_block: BasicBlock, + candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], + ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { + // We can't expand or-patterns freely. The rule is: if the candidate has an + // or-pattern as its only remaining match pair, we can expand it freely. If it has + // other match pairs, we can expand it but we can't process more candidates after + // it. + // + // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the + // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it + // so the `1` and `2` cases branch to a same block (which then tests `false`). If we + // took `(2, _)` in the same set of candidates, when we reach the block that tests + // `false` we don't know whether we came from `1` or `2`, hence we can't know where + // to branch on failure. + // + // ```ignore(illustrative) + // match (1, true) { + // (1 | 2, false) => {}, + // (2, _) => {}, + // _ => {} + // } + // ``` + // + // We therefore split the `candidates` slice in two, expand or-patterns in the first half, + // and process the rest separately. + let mut expand_until = 0; + for (i, candidate) in candidates.iter().enumerate() { + expand_until = i + 1; + if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() { + // The candidate has an or-pattern as well as more match pairs: we must + // split the candidates list here. + break; + } + } + let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); + + // Expand one level of or-patterns for each candidate in `candidates_to_expand`. + let mut expanded_candidates = Vec::new(); + for candidate in candidates_to_expand.iter_mut() { + if candidate.starts_with_or_pattern() { + let or_match_pair = candidate.match_pairs.remove(0); + // Expand the or-pattern into subcandidates. + self.create_or_subcandidates(candidate, or_match_pair); + // Collect the newly created subcandidates. + for subcandidate in candidate.subcandidates.iter_mut() { + expanded_candidates.push(subcandidate); + } + } else { + expanded_candidates.push(candidate); + } + } + + // Process the expanded candidates. + let remainder_start = self.match_candidates( + span, + scrutinee_span, + start_block, + expanded_candidates.as_mut_slice(), + ); + + // Simplify subcandidates and process any leftover match pairs. + for candidate in candidates_to_expand { + if !candidate.subcandidates.is_empty() { + self.finalize_or_candidate(span, scrutinee_span, candidate); + } + } + + remainder_start.and(remaining_candidates) + } + + /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new + /// subcandidate. Any candidate that has been expanded that way should be passed to + /// `finalize_or_candidate` after its subcandidates have been processed. + fn create_or_subcandidates<'pat>( + &mut self, + candidate: &mut Candidate<'pat, 'tcx>, + match_pair: MatchPair<'pat, 'tcx>, + ) { + let TestCase::Or { pats } = match_pair.test_case else { bug!() }; + debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); + candidate.or_span = Some(match_pair.pattern.span); + candidate.subcandidates = pats + .into_vec() + .into_iter() + .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) + .collect(); + candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; + } + /// Simplify subcandidates and process any leftover match pairs. The candidate should have been /// expanded with `create_or_subcandidates`. /// @@ -1690,6 +1699,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.merge_trivial_subcandidates(candidate); if !candidate.match_pairs.is_empty() { + let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span); + let source_info = self.source_info(or_span); // If more match pairs remain, test them after each subcandidate. // We could add them to the or-candidates before the call to `test_or_pattern` but this // would make it impossible to detect simplifiable or-patterns. That would guarantee @@ -1703,6 +1714,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(leaf_candidate.match_pairs.is_empty()); leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); let or_start = leaf_candidate.pre_binding_block.unwrap(); + let otherwise = + self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]); // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q, // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching // directly to `last_otherwise`. If there is a guard, @@ -1713,36 +1726,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { last_otherwise.unwrap() }; - self.match_candidates( - span, - scrutinee_span, - or_start, - or_otherwise, - &mut [leaf_candidate], - ); + self.cfg.goto(otherwise, source_info, or_otherwise); }); } } - /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new - /// subcandidate. Any candidate that has been expanded that way should be passed to - /// `finalize_or_candidate` after its subcandidates have been processed. - fn create_or_subcandidates<'pat>( - &mut self, - candidate: &mut Candidate<'pat, 'tcx>, - match_pair: MatchPair<'pat, 'tcx>, - ) { - let TestCase::Or { pats } = match_pair.test_case else { bug!() }; - debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); - candidate.or_span = Some(match_pair.pattern.span); - candidate.subcandidates = pats - .into_vec() - .into_iter() - .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) - .collect(); - candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; - } - /// Try to merge all of the subcandidates of the given candidate into one. This avoids /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been /// expanded with `create_or_subcandidates`. @@ -1992,14 +1980,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// } /// # } /// ``` + /// + /// We return the unprocessed candidates. fn test_candidates<'pat, 'b, 'c>( &mut self, span: Span, scrutinee_span: Span, candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], start_block: BasicBlock, - otherwise_block: BasicBlock, - ) { + ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { // Extract the match-pair from the highest priority candidate and build a test from it. let (match_place, test) = self.pick_test(candidates); @@ -2010,33 +1999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The block that we should branch to if none of the // `target_candidates` match. - let remainder_start = if !remaining_candidates.is_empty() { - let remainder_start = self.cfg.start_new_block(); - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); - remainder_start - } else { - otherwise_block - }; + let remainder_start = self.cfg.start_new_block(); // For each outcome of test, process the candidates that still apply. let target_blocks: FxIndexMap<_, _> = target_candidates .into_iter() .map(|(branch, mut candidates)| { - let candidate_start = self.cfg.start_new_block(); - self.match_candidates( - span, - scrutinee_span, - candidate_start, - remainder_start, - &mut *candidates, - ); - (branch, candidate_start) + let branch_start = self.cfg.start_new_block(); + let branch_otherwise = + self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates); + let source_info = self.source_info(span); + self.cfg.goto(branch_otherwise, source_info, remainder_start); + (branch, branch_start) }) .collect(); @@ -2050,6 +2024,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &test, target_blocks, ); + + remainder_start.and(remaining_candidates) } } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 3bec154e1df5..e67fc843285e 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,78 +1,15 @@ use std::marker::PhantomData; -use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::expr::as_place::PlaceBase; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; impl<'a, 'tcx> Builder<'a, 'tcx> { - pub(crate) fn field_match_pairs<'pat>( - &mut self, - place: PlaceBuilder<'tcx>, - subpatterns: &'pat [FieldPat<'tcx>], - ) -> Vec> { - subpatterns - .iter() - .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPair::new(place, &fieldpat.pattern, self) - }) - .collect() - } - - pub(crate) fn prefix_slice_suffix<'pat>( - &mut self, - match_pairs: &mut Vec>, - place: &PlaceBuilder<'tcx>, - prefix: &'pat [Box>], - opt_slice: &'pat Option>>, - suffix: &'pat [Box>], - ) { - let tcx = self.tcx; - let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { - match place_resolved.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; - - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPair::new(place.clone_project(elem), subpattern, self) - })); - - if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u64; - let subslice = place.clone_project(PlaceElem::Subslice { - from: prefix.len() as u64, - to: if exact_size { min_length - suffix_len } else { suffix_len }, - from_end: !exact_size, - }); - match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); - } - - match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u64; - let elem = ProjectionElem::ConstantIndex { - offset: if exact_size { min_length - end_offset } else { end_offset }, - min_length, - from_end: !exact_size, - }; - let place = place.clone_project(elem); - MatchPair::new(place, subpattern, self) - })); - } - /// Creates a false edge to `imaginary_target` and a real edge to /// real_target. If `imaginary_target` is none, or is the same as the real /// target, a Goto is generated instead to simplify the generated MIR. @@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - /// Recursively builds a `MatchPair` tree for the given pattern and its - /// subpatterns. - pub(in crate::build) fn new( - mut place_builder: PlaceBuilder<'tcx>, - pattern: &'pat Pat<'tcx>, - cx: &mut Builder<'_, 'tcx>, - ) -> MatchPair<'pat, 'tcx> { - // Force the place type to the pattern's type. - // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - if let Some(resolved) = place_builder.resolve_upvar(cx) { - place_builder = resolved; - } - - // Only add the OpaqueCast projection if the given place is an opaque type and the - // expected type from the pattern is not. - let may_need_cast = match place_builder.base() { - PlaceBase::Local(local) => { - let ty = - Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; - ty != pattern.ty && ty.has_opaque_types() - } - _ => true, - }; - if may_need_cast { - place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); - } - - let place = place_builder.try_to_place(cx); - let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; - let mut subpairs = Vec::new(); - let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => default_irrefutable(), - - PatKind::Or { ref pats } => TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }, - - PatKind::Range(ref range) => { - if range.is_full_range(cx.tcx) == Some(true) { - default_irrefutable() - } else { - TestCase::Range(range) - } - } - - PatKind::Constant { value } => TestCase::Constant { value }, - - PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - // Apply the type ascription to the value at `match_pair.place` - let ascription = place.map(|source| super::Ascription { - annotation: annotation.clone(), - source, - variance, - }); - - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Binding { mode, var, ref subpattern, .. } => { - let binding = place.map(|source| super::Binding { - span: pattern.span, - source, - var_id: var, - binding_mode: mode, - }); - - if let Some(subpattern) = subpattern.as_ref() { - // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - } - TestCase::Irrefutable { ascription: None, binding } - } - - PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { - // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.map(|source| { - let span = pattern.span; - let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - cx.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx.infcx.next_ty_var(span), - }, - ) - .args; - let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), - ty::UserArgs { args, user_self_ty: None }, - )); - let annotation = ty::CanonicalUserTypeAnnotation { - inferred_ty: pattern.ty, - span, - user_ty: Box::new(user_ty), - }; - super::Ascription { annotation, source, variance: ty::Contravariant } - }); - - subpairs.push(MatchPair::new(place_builder, pattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - default_irrefutable() - } - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - - if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - default_irrefutable() - } else { - TestCase::Slice { - len: prefix.len() + suffix.len(), - variable_length: slice.is_some(), - } - } - } - - PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { - let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - subpairs = cx.field_match_pairs(downcast_place, subpatterns); - - let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { - i == variant_index || { - (cx.tcx.features().exhaustive_patterns - || cx.tcx.features().min_exhaustive_patterns) - && !v - .inhabited_predicate(cx.tcx, adt_def) - .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.param_env) - } - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - default_irrefutable() - } else { - TestCase::Variant { adt_def, variant_index } - } - } - - PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place_builder, subpatterns); - default_irrefutable() - } - - PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); - default_irrefutable() - } - - PatKind::DerefPattern { ref subpattern, mutability } => { - // Create a new temporary for each deref pattern. - // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? - let temp = cx.temp( - Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), - pattern.span, - ); - subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); - TestCase::Deref { temp, mutability } - } - - PatKind::Never => TestCase::Never, - }; - - MatchPair { place, test_case, subpairs, pattern } - } -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 09cdb055a3e8..6eaed0f77533 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -402,7 +402,7 @@ where /// building up a `GenKillSet` and then throwing it away. pub trait GenKill { /// Inserts `elem` into the state vector. - fn gen(&mut self, elem: T); + fn gen_(&mut self, elem: T); /// Removes `elem` from the state vector. fn kill(&mut self, elem: T); @@ -410,7 +410,7 @@ pub trait GenKill { /// Calls `gen` for each element in `elems`. fn gen_all(&mut self, elems: impl IntoIterator) { for elem in elems { - self.gen(elem); + self.gen_(elem); } } @@ -424,12 +424,12 @@ pub trait GenKill { /// Stores a transfer function for a gen/kill problem. /// -/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be -/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for +/// Calling `gen_`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be +/// applied multiple times efficiently. When there are multiple calls to `gen_` and/or `kill` for /// the same element, the most recent one takes precedence. #[derive(Clone)] pub struct GenKillSet { - gen: HybridBitSet, + gen_: HybridBitSet, kill: HybridBitSet, } @@ -437,31 +437,31 @@ impl GenKillSet { /// Creates a new transfer function that will leave the dataflow state unchanged. pub fn identity(universe: usize) -> Self { GenKillSet { - gen: HybridBitSet::new_empty(universe), + gen_: HybridBitSet::new_empty(universe), kill: HybridBitSet::new_empty(universe), } } pub fn apply(&self, state: &mut impl BitSetExt) { - state.union(&self.gen); + state.union(&self.gen_); state.subtract(&self.kill); } } impl GenKill for GenKillSet { - fn gen(&mut self, elem: T) { - self.gen.insert(elem); + fn gen_(&mut self, elem: T) { + self.gen_.insert(elem); self.kill.remove(elem); } fn kill(&mut self, elem: T) { self.kill.insert(elem); - self.gen.remove(elem); + self.gen_.remove(elem); } } impl GenKill for BitSet { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.insert(elem); } @@ -471,7 +471,7 @@ impl GenKill for BitSet { } impl GenKill for ChunkedBitSet { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.insert(elem); } @@ -481,11 +481,11 @@ impl GenKill for ChunkedBitSet { } impl> GenKill for MaybeReachable { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { match self { // If the state is not reachable, adding an element does nothing. MaybeReachable::Unreachable => {} - MaybeReachable::Reachable(set) => set.gen(elem), + MaybeReachable::Reachable(set) => set.gen_(elem), } } @@ -499,7 +499,7 @@ impl> GenKill for MaybeReachable { } impl GenKill for lattice::Dual> { - fn gen(&mut self, elem: T) { + fn gen_(&mut self, elem: T) { self.0.insert(elem); } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 574da949b0ed..885fdd0d58be 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -97,7 +97,7 @@ where Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => { if !borrowed_place.is_indirect() { - self.trans.gen(borrowed_place.local); + self.trans.gen_(borrowed_place.local); } } @@ -131,7 +131,7 @@ where // // [#61069]: https://github.com/rust-lang/rust/pull/61069 if !dropped_place.is_indirect() { - self.trans.gen(dropped_place.local); + self.trans.gen_(dropped_place.local); } } @@ -159,8 +159,8 @@ pub fn borrowed_locals(body: &Body<'_>) -> BitSet { impl GenKill for Borrowed { #[inline] - fn gen(&mut self, elem: Local) { - self.0.gen(elem) + fn gen_(&mut self, elem: Local) { + self.0.gen_(elem) } #[inline] fn kill(&mut self, _: Local) { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index ffcf630b653c..a9bceeccdce2 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -283,7 +283,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { ) { match state { DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), + DropFlagState::Present => trans.gen_(path), } } } @@ -295,7 +295,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, '_, 'tcx> { state: DropFlagState, ) { match state { - DropFlagState::Absent => trans.gen(path), + DropFlagState::Absent => trans.gen_(path), DropFlagState::Present => trans.kill(path), } } @@ -309,7 +309,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { ) { match state { DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), + DropFlagState::Present => trans.gen_(path), } } } @@ -331,7 +331,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len())); drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - state.gen(path); + state.gen_(path); }); } } @@ -362,7 +362,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) { on_all_children_bits(self.move_data(), mpi, |child| { - trans.gen(child); + trans.gen_(child); }) } } @@ -400,7 +400,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.gen(mpi); + trans.gen_(mpi); }, ); }); @@ -572,7 +572,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { self.move_data(), enum_place, variant, - |mpi| trans.gen(mpi), + |mpi| trans.gen_(mpi), ); }); } @@ -643,7 +643,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.gen(mpi); + trans.gen_(mpi); }, ); }); @@ -738,7 +738,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { let call_loc = self.body.terminator_loc(block); for init_index in &init_loc_map[call_loc] { - trans.gen(*init_index); + trans.gen_(*init_index); } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 334fa9976f03..48bdb1316012 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -116,7 +116,7 @@ where self.0.kill(place.local); } } - Some(DefUse::Use) => self.0.gen(place.local), + Some(DefUse::Use) => self.0.gen_(place.local), None => {} } @@ -154,7 +154,7 @@ impl DefUse { fn apply(trans: &mut impl GenKill, place: Place<'_>, context: PlaceContext) { match DefUse::for_place(place, context) { Some(DefUse::Def) => trans.kill(place.local), - Some(DefUse::Use) => trans.gen(place.local), + Some(DefUse::Use) => trans.gen_(place.local), None => {} } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index f850a7102773..682cec12f1fb 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -54,7 +54,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { _: Location, ) { match stmt.kind { - StatementKind::StorageLive(l) => trans.gen(l), + StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageDead(l) => trans.kill(l), _ => (), } @@ -127,7 +127,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { ) { match stmt.kind { StatementKind::StorageLive(l) => trans.kill(l), - StatementKind::StorageDead(l) => trans.gen(l), + StatementKind::StorageDead(l) => trans.gen_(l), _ => (), } } @@ -208,7 +208,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { StatementKind::Assign(box (place, _)) | StatementKind::SetDiscriminant { box place, .. } | StatementKind::Deinit(box place) => { - trans.gen(place.local); + trans.gen_(place.local); } // Nothing to do for these. Match exhaustively so this fails to compile when new @@ -250,7 +250,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { match &terminator.kind { TerminatorKind::Call { destination, .. } => { - trans.gen(destination.local); + trans.gen_(destination.local); } // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for @@ -265,7 +265,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { InlineAsmOperand::Out { place, .. } | InlineAsmOperand::InOut { out_place: place, .. } => { if let Some(place) = place { - trans.gen(place.local); + trans.gen_(place.local); } } InlineAsmOperand::In { .. } @@ -341,7 +341,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { - return_places.for_each(|place| trans.gen(place.local)); + return_places.for_each(|place| trans.gen_(place.local)); } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 1582c2e8a906..c9f5d38fe2c1 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -32,15 +32,16 @@ //! Because of that, we can assume that the only way to change the value behind a tracked place is //! by direct assignment. -use std::collections::VecDeque; use std::fmt::{Debug, Formatter}; use std::ops::Range; -use rustc_data_structures::fx::{FxHashMap, StdEntry}; +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::bug; +use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -58,7 +59,7 @@ pub trait ValueAnalysis<'tcx> { const NAME: &'static str; - fn map(&self) -> ⤅ + fn map(&self) -> &Map<'tcx>; fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State) { self.super_statement(statement, state) @@ -523,12 +524,12 @@ impl State { } /// Assign `value` to all places that are contained in `place` or may alias one. - pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { + pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) { self.flood_with_tail_elem(place, None, map, value) } /// Assign `TOP` to all places that are contained in `place` or may alias one. - pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) + pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map<'_>) where V: HasTop, { @@ -536,12 +537,12 @@ impl State { } /// Assign `value` to the discriminant of `place` and all places that may alias it. - fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { + fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) { self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value) } /// Assign `TOP` to the discriminant of `place` and all places that may alias it. - pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) + pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map<'_>) where V: HasTop, { @@ -559,7 +560,7 @@ impl State { &mut self, place: PlaceRef<'_>, tail_elem: Option, - map: &Map, + map: &Map<'_>, value: V, ) { let State::Reachable(values) = self else { return }; @@ -570,7 +571,7 @@ impl State { /// This does nothing if the place is not tracked. /// /// The target place must have been flooded before calling this method. - fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace, map: &Map) { + fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace, map: &Map<'_>) { match result { ValueOrPlace::Value(value) => self.insert_value_idx(target, value, map), ValueOrPlace::Place(source) => self.insert_place_idx(target, source, map), @@ -581,7 +582,7 @@ impl State { /// This does nothing if the place is not tracked. /// /// The target place must have been flooded before calling this method. - pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { + pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map<'_>) { let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { values.insert(value_index, value) @@ -595,7 +596,7 @@ impl State { /// places that are non-overlapping or identical. /// /// The target place must have been flooded before calling this method. - pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) { + pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) { let State::Reachable(values) = self else { return }; // If both places are tracked, we copy the value to the target. @@ -616,7 +617,7 @@ impl State { } /// Helper method to interpret `target = result`. - pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map) + pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map<'_>) where V: HasTop, { @@ -627,7 +628,7 @@ impl State { } /// Helper method for assignments to a discriminant. - pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map) + pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace, map: &Map<'_>) where V: HasTop, { @@ -638,25 +639,25 @@ impl State { } /// Retrieve the value stored for a place, or `None` if it is not tracked. - pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find(place)?; self.try_get_idx(place, map) } /// Retrieve the discriminant stored for a place, or `None` if it is not tracked. - pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find_discr(place)?; self.try_get_idx(place, map) } /// Retrieve the slice length stored for a place, or `None` if it is not tracked. - pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map) -> Option { + pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option { let place = map.find_len(place)?; self.try_get_idx(place, map) } /// Retrieve the value stored for a place index, or `None` if it is not tracked. - pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { + pub fn try_get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> Option { match self { State::Reachable(values) => { map.places[place].value_index.map(|v| values.get(v).clone()) @@ -668,7 +669,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ if the place is tracked and the state is unreachable. - pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -682,7 +683,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -696,7 +697,7 @@ impl State { /// Retrieve the value stored for a place, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V + pub fn get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -710,7 +711,7 @@ impl State { /// Retrieve the value stored for a place index, or ⊤ if it is not tracked. /// /// This method returns ⊥ the current state is unreachable. - pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V + pub fn get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> V where V: HasBottom + HasTop, { @@ -746,25 +747,25 @@ impl JoinSemiLattice for State { /// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children. /// - To directly get the child for a specific projection, there is a `projections` map. #[derive(Debug)] -pub struct Map { +pub struct Map<'tcx> { locals: IndexVec>, projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>, - places: IndexVec, + places: IndexVec>, value_count: usize, // The Range corresponds to a slice into `inner_values_buffer`. inner_values: IndexVec>, inner_values_buffer: Vec, } -impl Map { +impl<'tcx> Map<'tcx> { /// Returns a map that only tracks places whose type has scalar layout. /// /// This is currently the only way to create a [`Map`]. The way in which the tracked places are /// chosen is an implementation detail and may not be relied upon (other than that their type /// are scalars). - pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { + pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { let mut map = Self { - locals: IndexVec::new(), + locals: IndexVec::from_elem(None, &body.local_decls), projections: FxHashMap::default(), places: IndexVec::new(), value_count: 0, @@ -778,18 +779,15 @@ impl Map { } /// Register all non-excluded places that have scalar layout. - fn register<'tcx>( + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn register( &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, exclude: BitSet, value_limit: Option, ) { - let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len())); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - // Start by constructing the places for each bare local. - self.locals = IndexVec::from_elem(None, &body.local_decls); for (local, decl) in body.local_decls.iter_enumerated() { if exclude.contains(local) { continue; @@ -797,16 +795,60 @@ impl Map { // Create a place for the local. debug_assert!(self.locals[local].is_none()); - let place = self.places.push(PlaceInfo::new(None)); + let place = self.places.push(PlaceInfo::new(decl.ty, None)); self.locals[local] = Some(place); - - // And push the eventual children places to the worklist. - self.register_children(tcx, param_env, place, decl.ty, &mut worklist); } - // `place.elem1.elem2` with type `ty`. - // `elem1` is either `Some(Variant(i))` or `None`. - while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() { + // Collect syntactic places and assignments between them. + let mut collector = + PlaceCollector { tcx, body, map: self, assignments: Default::default() }; + collector.visit_body(body); + let PlaceCollector { mut assignments, .. } = collector; + + // Just collecting syntactic places is not enough. We may need to propagate this pattern: + // _1 = (const 5u32, const 13i64); + // _2 = _1; + // _3 = (_2.0 as u32); + // + // `_1.0` does not appear, but we still need to track it. This is achieved by propagating + // projections from assignments. We recorded an assignment between `_2` and `_1`, so we + // want `_1` and `_2` to have the same sub-places. + // + // This is what this fixpoint loop does. While we are still creating places, run through + // all the assignments, and register places for children. + let mut num_places = 0; + while num_places < self.places.len() { + num_places = self.places.len(); + + for assign in 0.. { + let Some(&(lhs, rhs)) = assignments.get_index(assign) else { break }; + + // Mirror children from `lhs` in `rhs`. + let mut child = self.places[lhs].first_child; + while let Some(lhs_child) = child { + let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[lhs_child]; + let rhs_child = + self.register_place(ty, rhs, proj_elem.expect("child is not a projection")); + assignments.insert((lhs_child, rhs_child)); + child = next_sibling; + } + + // Conversely, mirror children from `rhs` in `lhs`. + let mut child = self.places[rhs].first_child; + while let Some(rhs_child) = child { + let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[rhs_child]; + let lhs_child = + self.register_place(ty, lhs, proj_elem.expect("child is not a projection")); + assignments.insert((lhs_child, rhs_child)); + child = next_sibling; + } + } + } + drop(assignments); + + // Create values for places whose type have scalar layout. + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + for place_info in self.places.iter_mut() { // The user requires a bound on the number of created values. if let Some(value_limit) = value_limit && self.value_count >= value_limit @@ -814,19 +856,18 @@ impl Map { break; } - // Create a place for this projection. - for elem in [elem1, Some(elem2)].into_iter().flatten() { - place = *self.projections.entry((place, elem)).or_insert_with(|| { - // Prepend new child to the linked list. - let next = self.places.push(PlaceInfo::new(Some(elem))); - self.places[next].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(next); - next - }); + if let Ok(ty) = tcx.try_normalize_erasing_regions(param_env, place_info.ty) { + place_info.ty = ty; } - // And push the eventual children places to the worklist. - self.register_children(tcx, param_env, place, ty, &mut worklist); + // Allocate a value slot if it doesn't have one, and the user requested one. + assert!(place_info.value_index.is_none()); + if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty)) + && layout.abi.is_scalar() + { + place_info.value_index = Some(self.value_count.into()); + self.value_count += 1; + } } // Pre-compute the tree of ValueIndex nested in each PlaceIndex. @@ -852,68 +893,14 @@ impl Map { self.projections.retain(|_, child| !self.inner_values[*child].is_empty()); } - /// Potentially register the (local, projection) place and its fields, recursively. - /// - /// Invariant: The projection must only contain trackable elements. - fn register_children<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - place: PlaceIndex, - ty: Ty<'tcx>, - worklist: &mut VecDeque<(PlaceIndex, Option, TrackElem, Ty<'tcx>)>, - ) { - // Allocate a value slot if it doesn't have one, and the user requested one. - assert!(self.places[place].value_index.is_none()); - if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.abi.is_scalar()) { - self.places[place].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - // For enums, directly create the `Discriminant`, as that's their main use. - if ty.is_enum() { - // Prepend new child to the linked list. - let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); - self.places[discr].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(discr); - let old = self.projections.insert((place, TrackElem::Discriminant), discr); - assert!(old.is_none()); - - // Allocate a value slot since it doesn't have one. - assert!(self.places[discr].value_index.is_none()); - self.places[discr].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind() - && let ty::Slice(..) = ref_ty.kind() - // The user may have written a predicate like `[T]: Sized` in their where clauses, - // which makes slices scalars. - && self.places[place].value_index.is_none() - { - // Prepend new child to the linked list. - let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen))); - self.places[len].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(len); - - let old = self.projections.insert((place, TrackElem::DerefLen), len); - assert!(old.is_none()); - - // Allocate a value slot since it doesn't have one. - assert!(self.places[len].value_index.is_none()); - self.places[len].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - - // Recurse with all fields of this place. - iter_fields(ty, tcx, param_env, |variant, field, ty| { - worklist.push_back(( - place, - variant.map(TrackElem::Variant), - TrackElem::Field(field), - ty, - )) - }); + #[tracing::instrument(level = "trace", skip(self), ret)] + fn register_place(&mut self, ty: Ty<'tcx>, base: PlaceIndex, elem: TrackElem) -> PlaceIndex { + *self.projections.entry((base, elem)).or_insert_with(|| { + let next = self.places.push(PlaceInfo::new(ty, Some(elem))); + self.places[next].next_sibling = self.places[base].first_child; + self.places[base].first_child = Some(next); + next + }) } /// Precompute the list of values inside `root` and store it inside @@ -934,7 +921,108 @@ impl Map { let end = self.inner_values_buffer.len(); self.inner_values[root] = start..end; } +} +struct PlaceCollector<'a, 'b, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'b Body<'tcx>, + map: &'a mut Map<'tcx>, + assignments: FxIndexSet<(PlaceIndex, PlaceIndex)>, +} + +impl<'tcx> PlaceCollector<'_, '_, 'tcx> { + #[tracing::instrument(level = "trace", skip(self))] + fn register_place(&mut self, place: Place<'tcx>) -> Option { + // Create a place for this projection. + let mut place_index = self.map.locals[place.local]?; + let mut ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); + tracing::trace!(?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(self.tcx); + self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); + } + + for proj in place.projection { + let track_elem = proj.try_into().ok()?; + ty = ty.projection_ty(self.tcx, proj); + place_index = self.map.register_place(ty.ty, place_index, track_elem); + tracing::trace!(?proj, ?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(self.tcx); + self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); + } + } + + Some(place_index) + } +} + +impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> { + #[tracing::instrument(level = "trace", skip(self))] + fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) { + if !ctxt.is_use() { + return; + } + + self.register_place(*place); + } + + fn visit_assign(&mut self, lhs: &Place<'tcx>, rhs: &Rvalue<'tcx>, location: Location) { + self.super_assign(lhs, rhs, location); + + match rhs { + Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) | Rvalue::CopyForDeref(rhs) => { + let Some(lhs) = self.register_place(*lhs) else { return }; + let Some(rhs) = self.register_place(*rhs) else { return }; + self.assignments.insert((lhs, rhs)); + } + Rvalue::Aggregate(kind, fields) => { + let Some(mut lhs) = self.register_place(*lhs) else { return }; + match **kind { + // Do not propagate unions. + AggregateKind::Adt(_, _, _, _, Some(_)) => return, + AggregateKind::Adt(_, variant, _, _, None) => { + let ty = self.map.places[lhs].ty; + if ty.is_enum() { + lhs = self.map.register_place(ty, lhs, TrackElem::Variant(variant)); + } + } + AggregateKind::RawPtr(..) + | AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(..) + | AggregateKind::Coroutine(..) + | AggregateKind::CoroutineClosure(..) => {} + } + for (index, field) in fields.iter_enumerated() { + if let Some(rhs) = field.place() + && let Some(rhs) = self.register_place(rhs) + { + let lhs = self.map.register_place( + self.map.places[rhs].ty, + lhs, + TrackElem::Field(index), + ); + self.assignments.insert((lhs, rhs)); + } + } + } + _ => {} + } + } +} + +impl<'tcx> Map<'tcx> { /// Applies a single projection element, yielding the corresponding child. pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option { self.projections.get(&(place, elem)).copied() @@ -974,7 +1062,10 @@ impl Map { } /// Iterate over all direct children. - fn children(&self, parent: PlaceIndex) -> impl Iterator + '_ { + fn children( + &self, + parent: PlaceIndex, + ) -> impl Iterator + Captures<'_> + Captures<'tcx> { Children::new(self, parent) } @@ -1081,7 +1172,10 @@ impl Map { /// Together, `first_child` and `next_sibling` form an intrusive linked list, which is used to /// model a tree structure (a replacement for a member like `children: Vec`). #[derive(Debug)] -struct PlaceInfo { +struct PlaceInfo<'tcx> { + /// Type of the referenced place. + ty: Ty<'tcx>, + /// We store a [`ValueIndex`] if and only if the placed is tracked by the analysis. value_index: Option, @@ -1095,24 +1189,24 @@ struct PlaceInfo { next_sibling: Option, } -impl PlaceInfo { - fn new(proj_elem: Option) -> Self { - Self { next_sibling: None, first_child: None, proj_elem, value_index: None } +impl<'tcx> PlaceInfo<'tcx> { + fn new(ty: Ty<'tcx>, proj_elem: Option) -> Self { + Self { ty, next_sibling: None, first_child: None, proj_elem, value_index: None } } } -struct Children<'a> { - map: &'a Map, +struct Children<'a, 'tcx> { + map: &'a Map<'tcx>, next: Option, } -impl<'a> Children<'a> { - fn new(map: &'a Map, parent: PlaceIndex) -> Self { +impl<'a, 'tcx> Children<'a, 'tcx> { + fn new(map: &'a Map<'tcx>, parent: PlaceIndex) -> Self { Self { map, next: map.places[parent].first_child } } } -impl<'a> Iterator for Children<'a> { +impl Iterator for Children<'_, '_> { type Item = PlaceIndex; fn next(&mut self) -> Option { @@ -1261,7 +1355,7 @@ fn debug_with_context_rec( place_str: &str, new: &StateData, old: Option<&StateData>, - map: &Map, + map: &Map<'_>, f: &mut Formatter<'_>, ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { @@ -1305,7 +1399,7 @@ fn debug_with_context_rec( fn debug_with_context( new: &StateData, old: Option<&StateData>, - map: &Map, + map: &Map<'_>, f: &mut Formatter<'_>, ) -> std::fmt::Result { for (local, place) in map.locals.iter_enumerated() { diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 25297245172a..2ac08ea85d25 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -56,6 +56,10 @@ pub(super) struct MCDCDecision { #[derive(Default)] pub(super) struct ExtractedMappings { + /// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't + /// need access to the whole graph when allocating per-BCB data. This is + /// only public so that other code can still use exhaustive destructuring. + pub(super) num_bcbs: usize, pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, pub(super) mcdc_bitmap_bytes: u32, @@ -106,6 +110,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ); ExtractedMappings { + num_bcbs: basic_coverage_blocks.num_nodes(), code_mappings, branch_pairs, mcdc_bitmap_bytes, @@ -115,12 +120,10 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( } impl ExtractedMappings { - pub(super) fn all_bcbs_with_counter_mappings( - &self, - basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set - ) -> BitSet { + pub(super) fn all_bcbs_with_counter_mappings(&self) -> BitSet { // Fully destructure self to make sure we don't miss any fields that have mappings. let Self { + num_bcbs, code_mappings, branch_pairs, mcdc_bitmap_bytes: _, @@ -129,7 +132,7 @@ impl ExtractedMappings { } = self; // Identify which BCBs have one or more mappings. - let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut bcbs_with_counter_mappings = BitSet::new_empty(*num_bcbs); let mut insert = |bcb| { bcbs_with_counter_mappings.insert(bcb); }; @@ -156,6 +159,15 @@ impl ExtractedMappings { bcbs_with_counter_mappings } + + /// Returns the set of BCBs that have one or more `Code` mappings. + pub(super) fn bcbs_with_ordinary_code_mappings(&self) -> BitSet { + let mut bcbs = BitSet::new_empty(self.num_bcbs); + for &CodeMapping { span: _, bcb } in &self.code_mappings { + bcbs.insert(bcb); + } + bcbs + } } fn resolve_block_markers( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 2efca40d1804..3772a8f51181 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -25,7 +25,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; use crate::MirPass; @@ -88,8 +88,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. - let bcbs_with_counter_mappings = - extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks); + let bcbs_with_counter_mappings = extracted_mappings.all_bcbs_with_counter_mappings(); if bcbs_with_counter_mappings.is_empty() { // No relevant spans were found in MIR, so skip instrumenting this function. return; @@ -109,7 +108,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_coverage_statements( mir_body, &basic_coverage_blocks, - bcb_has_counter_mappings, + &extracted_mappings, &coverage_counters, ); @@ -163,6 +162,7 @@ fn create_mappings<'tcx>( // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { + num_bcbs: _, code_mappings, branch_pairs, mcdc_bitmap_bytes: _, @@ -219,7 +219,7 @@ fn create_mappings<'tcx>( fn inject_coverage_statements<'tcx>( mir_body: &mut mir::Body<'tcx>, basic_coverage_blocks: &CoverageGraph, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + extracted_mappings: &ExtractedMappings, coverage_counters: &CoverageCounters, ) { // Inject counter-increment statements into MIR. @@ -252,11 +252,16 @@ fn inject_coverage_statements<'tcx>( // can check whether the injected statement survived MIR optimization. // (BCB edges can't have spans, so we only need to process BCB nodes here.) // + // We only do this for ordinary `Code` mappings, because branch and MC/DC + // mappings might have expressions that don't correspond to any single + // point in the control-flow graph. + // // See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals // with "expressions seen" and "zero terms". + let eligible_bcbs = extracted_mappings.bcbs_with_ordinary_code_mappings(); for (bcb, expression_id) in coverage_counters .bcb_nodes_with_coverage_expressions() - .filter(|&(bcb, _)| bcb_has_coverage_spans(bcb)) + .filter(|&(bcb, _)| eligible_bcbs.contains(bcb)) { inject_statement( mir_body, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8b965f4d18e4..8303ef039d18 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -66,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { } struct ConstAnalysis<'a, 'tcx> { - map: Map, + map: Map<'tcx>, tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, @@ -78,7 +78,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { const NAME: &'static str = "ConstAnalysis"; - fn map(&self) -> &Map { + fn map(&self) -> &Map<'tcx> { &self.map } @@ -330,7 +330,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); Self { map, @@ -560,12 +560,13 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { Self { patch: Patch::new(tcx), local_decls } } + #[instrument(level = "trace", skip(self, ecx, map), ret)] fn try_make_constant( &self, ecx: &mut InterpCx<'tcx, DummyMachine>, place: Place<'tcx>, state: &State>, - map: &Map, + map: &Map<'tcx>, ) -> Option> { let ty = place.ty(self.local_decls, self.patch.tcx).ty; let layout = ecx.layout_of(ty).ok()?; @@ -598,10 +599,11 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { } } +#[instrument(level = "trace", skip(map), ret)] fn propagatable_scalar( place: PlaceIndex, state: &State>, - map: &Map, + map: &Map<'_>, ) -> Option { if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_scalar_int().is_ok() @@ -613,14 +615,14 @@ fn propagatable_scalar( } } -#[instrument(level = "trace", skip(ecx, state, map))] +#[instrument(level = "trace", skip(ecx, state, map), ret)] fn try_write_constant<'tcx>( ecx: &mut InterpCx<'tcx, DummyMachine>, dest: &PlaceTy<'tcx>, place: PlaceIndex, ty: Ty<'tcx>, state: &State>, - map: &Map, + map: &Map<'tcx>, ) -> InterpResult<'tcx> { let layout = ecx.layout_of(ty)?; @@ -719,6 +721,7 @@ impl<'mir, 'tcx> { type FlowState = State>; + #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, @@ -740,6 +743,7 @@ impl<'mir, 'tcx> } } + #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper>>, @@ -834,7 +838,7 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> { state: &'a State>, visitor: &'a mut Collector<'tcx, 'locals>, ecx: &'map mut InterpCx<'tcx, DummyMachine>, - map: &'map Map, + map: &'map Map<'tcx>, } impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 97ec0cb39ded..2100f4b4a1af 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -123,7 +123,7 @@ struct TOFinder<'tcx, 'a> { param_env: ty::ParamEnv<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, - map: &'a Map, + map: &'a Map<'tcx>, loop_headers: &'a BitSet, /// We use an arena to avoid cloning the slices when cloning `state`. arena: &'a DroplessArena, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c90f8e761633..c23bc8f09ad1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -16,9 +16,9 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, - GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, - QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, + CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause, + NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode, + FIXPOINT_STEP_LIMIT, }; pub(super) mod canonical; @@ -72,7 +72,7 @@ where /// new placeholders to the caller. pub(super) max_input_universe: ty::UniverseIndex, - pub(super) search_graph: &'a mut SearchGraph, + pub(super) search_graph: &'a mut SearchGraph, nested_goals: NestedGoals, @@ -200,7 +200,7 @@ where generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode()); + let mut search_graph = SearchGraph::new(delegate.solver_mode()); let mut ecx = EvalCtxt { delegate, @@ -241,7 +241,7 @@ where /// and registering opaques from the canonicalized input. fn enter_canonical( cx: I, - search_graph: &'a mut search_graph::SearchGraph, + search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, canonical_goal_evaluation: &mut ProofTreeBuilder, f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, @@ -296,7 +296,7 @@ where #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( cx: I, - search_graph: &'a mut search_graph::SearchGraph, + search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, goal_evaluation: &mut ProofTreeBuilder, ) -> QueryResult { diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index b50676e8d532..3e266ddac71f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; use std::mem; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, search_graph, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; @@ -38,7 +38,7 @@ use crate::solve::{ /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder::Interner> +pub(crate) struct ProofTreeBuilder::Interner> where D: SolverDelegate, I: Interner, @@ -321,23 +321,6 @@ impl, I: Interner> ProofTreeBuilder { }) } - pub fn finalize_canonical_goal_evaluation( - &mut self, - cx: I, - ) -> Option { - self.as_mut().map(|this| match this { - DebugSolver::CanonicalGoalEvaluation(evaluation) => { - let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); - let final_revision = - cx.intern_canonical_goal_evaluation_step(final_revision.finalize()); - let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; - assert_eq!(evaluation.kind.replace(kind), None); - final_revision - } - _ => unreachable!(), - }) - } - pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { @@ -571,3 +554,51 @@ impl, I: Interner> ProofTreeBuilder { } } } + +impl search_graph::ProofTreeBuilder for ProofTreeBuilder +where + D: SolverDelegate, + I: Interner, +{ + fn try_apply_proof_tree( + &mut self, + proof_tree: Option, + ) -> bool { + if !self.is_noop() { + if let Some(final_revision) = proof_tree { + let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; + self.canonical_goal_evaluation_kind(kind); + true + } else { + false + } + } else { + true + } + } + + fn on_provisional_cache_hit(&mut self) { + self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::ProvisionalCacheHit); + } + + fn on_cycle_in_stack(&mut self) { + self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::CycleInStack); + } + + fn finalize_canonical_goal_evaluation( + &mut self, + tcx: I, + ) -> Option { + self.as_mut().map(|this| match this { + DebugSolver::CanonicalGoalEvaluation(evaluation) => { + let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); + let final_revision = + tcx.intern_canonical_goal_evaluation_step(final_revision.finalize()); + let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; + assert_eq!(evaluation.kind.replace(kind), None); + final_revision + } + _ => unreachable!(), + }) + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 69d52dcad7a5..fe053a506e71 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,599 +1,90 @@ -use std::mem; +use std::marker::PhantomData; -use rustc_index::{Idx, IndexVec}; -use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::inherent::*; +use rustc_type_ir::search_graph::{self, CycleKind, UsageKind}; +use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; use rustc_type_ir::Interner; -use tracing::debug; +use super::inspect::{self, ProofTreeBuilder}; +use super::FIXPOINT_STEP_LIMIT; use crate::delegate::SolverDelegate; -use crate::solve::inspect::{self, ProofTreeBuilder}; -use crate::solve::{ - CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, -}; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SolverLimit(usize); - -rustc_index::newtype_index! { - #[orderable] - #[gate_rustc_only] - pub struct StackDepth {} +/// This type is never constructed. We only use it to implement `search_graph::Delegate` +/// for all types which impl `SolverDelegate` and doing it directly fails in coherence. +pub(super) struct SearchGraphDelegate { + _marker: PhantomData, } +pub(super) type SearchGraph = search_graph::SearchGraph>; +impl search_graph::Delegate for SearchGraphDelegate +where + D: SolverDelegate, + I: Interner, +{ + type Cx = D::Interner; -bitflags::bitflags! { - /// Whether and how this goal has been used as the root of a - /// cycle. We track the kind of cycle as we're otherwise forced - /// to always rerun at least once. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - struct HasBeenUsed: u8 { - const INDUCTIVE_CYCLE = 1 << 0; - const COINDUCTIVE_CYCLE = 1 << 1; - } -} + const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT; -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] -struct StackEntry { - input: CanonicalInput, + type ProofTreeBuilder = ProofTreeBuilder; - available_depth: SolverLimit, - - /// The maximum depth reached by this stack entry, only up-to date - /// for the top of the stack and lazily updated for the rest. - reached_depth: StackDepth, - - /// Whether this entry is a non-root cycle participant. - /// - /// We must not move the result of non-root cycle participants to the - /// global cache. We store the highest stack depth of a head of a cycle - /// this goal is involved in. This necessary to soundly cache its - /// provisional result. - non_root_cycle_participant: Option, - - encountered_overflow: bool, - - has_been_used: HasBeenUsed, - - /// We put only the root goal of a coinductive cycle into the global cache. - /// - /// If we were to use that result when later trying to prove another cycle - /// participant, we can end up with unstable query results. - /// - /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for - /// an example of where this is needed. - /// - /// There can be multiple roots on the same stack, so we need to track - /// cycle participants per root: - /// ```plain - /// A :- B - /// B :- A, C - /// C :- D - /// D :- C - /// ``` - nested_goals: HashSet>, - /// Starts out as `None` and gets set when rerunning this - /// goal in case we encounter a cycle. - provisional_result: Option>, -} - -/// The provisional result for a goal which is not on the stack. -#[derive(Debug)] -struct DetachedEntry { - /// The head of the smallest non-trivial cycle involving this entry. - /// - /// Given the following rules, when proving `A` the head for - /// the provisional entry of `C` would be `B`. - /// ```plain - /// A :- B - /// B :- C - /// C :- A + B + C - /// ``` - head: StackDepth, - result: QueryResult, -} - -/// Stores the stack depth of a currently evaluated goal *and* already -/// computed results for goals which depend on other goals still on the stack. -/// -/// The provisional result may depend on whether the stack above it is inductive -/// or coinductive. Because of this, we store separate provisional results for -/// each case. If an provisional entry is not applicable, it may be the case -/// that we already have provisional result while computing a goal. In this case -/// we prefer the provisional result to potentially avoid fixpoint iterations. -/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example. -/// -/// The provisional cache can theoretically result in changes to the observable behavior, -/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs. -#[derive(derivative::Derivative)] -#[derivative(Default(bound = ""))] -struct ProvisionalCacheEntry { - stack_depth: Option, - with_inductive_stack: Option>, - with_coinductive_stack: Option>, -} - -impl ProvisionalCacheEntry { - fn is_empty(&self) -> bool { - self.stack_depth.is_none() - && self.with_inductive_stack.is_none() - && self.with_coinductive_stack.is_none() - } -} - -pub(super) struct SearchGraph { - mode: SolverMode, - /// The stack of goals currently being computed. - /// - /// An element is *deeper* in the stack if its index is *lower*. - stack: IndexVec>, - provisional_cache: HashMap, ProvisionalCacheEntry>, -} - -impl SearchGraph { - pub(super) fn new(mode: SolverMode) -> SearchGraph { - Self { mode, stack: Default::default(), provisional_cache: Default::default() } + fn recursion_limit(cx: I) -> usize { + cx.recursion_limit() } - pub(super) fn solver_mode(&self) -> SolverMode { - self.mode - } - - fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { - if let Some(parent) = self.stack.raw.last_mut() { - parent.reached_depth = parent.reached_depth.max(reached_depth); - parent.encountered_overflow |= encountered_overflow; + fn initial_provisional_result( + cx: I, + kind: CycleKind, + input: CanonicalInput, + ) -> QueryResult { + match kind { + CycleKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), + CycleKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)), } } - pub(super) fn is_empty(&self) -> bool { - self.stack.is_empty() - } - - /// Returns the remaining depth allowed for nested goals. - /// - /// This is generally simply one less than the current depth. - /// However, if we encountered overflow, we significantly reduce - /// the remaining depth of all nested goals to prevent hangs - /// in case there is exponential blowup. - fn allowed_depth_for_nested( + fn reached_fixpoint( cx: I, - stack: &IndexVec>, - ) -> Option { - if let Some(last) = stack.raw.last() { - if last.available_depth.0 == 0 { - return None; - } - - Some(if last.encountered_overflow { - SolverLimit(last.available_depth.0 / 4) - } else { - SolverLimit(last.available_depth.0 - 1) - }) - } else { - Some(SolverLimit(cx.recursion_limit())) - } - } - - fn stack_coinductive_from( - cx: I, - stack: &IndexVec>, - head: StackDepth, + kind: UsageKind, + input: CanonicalInput, + provisional_result: Option>, + result: QueryResult, ) -> bool { - stack.raw[head.index()..] - .iter() - .all(|entry| entry.input.value.goal.predicate.is_coinductive(cx)) - } - - // When encountering a solver cycle, the result of the current goal - // depends on goals lower on the stack. - // - // We have to therefore be careful when caching goals. Only the final result - // of the cycle root, i.e. the lowest goal on the stack involved in this cycle, - // is moved to the global cache while all others are stored in a provisional cache. - // - // We update both the head of this cycle to rerun its evaluation until - // we reach a fixpoint and all other cycle participants to make sure that - // their result does not get moved to the global cache. - fn tag_cycle_participants( - stack: &mut IndexVec>, - usage_kind: HasBeenUsed, - head: StackDepth, - ) { - stack[head].has_been_used |= usage_kind; - debug_assert!(!stack[head].has_been_used.is_empty()); - - // The current root of these cycles. Note that this may not be the final - // root in case a later goal depends on a goal higher up the stack. - let mut current_root = head; - while let Some(parent) = stack[current_root].non_root_cycle_participant { - current_root = parent; - debug_assert!(!stack[current_root].has_been_used.is_empty()); - } - - let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1); - let current_cycle_root = &mut stack[current_root.as_usize()]; - for entry in cycle_participants { - entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); - current_cycle_root.nested_goals.insert(entry.input); - current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); - } - } - - fn clear_dependent_provisional_results( - provisional_cache: &mut HashMap, ProvisionalCacheEntry>, - head: StackDepth, - ) { - #[allow(rustc::potential_query_instability)] - provisional_cache.retain(|_, entry| { - if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) { - entry.with_coinductive_stack.take(); - } - if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) { - entry.with_inductive_stack.take(); - } - !entry.is_empty() - }); - } - - /// The trait solver behavior is different for coherence - /// so we use a separate cache. Alternatively we could use - /// a single cache and share it between coherence and ordinary - /// trait solving. - pub(super) fn global_cache(&self, cx: I) -> I::EvaluationCache { - cx.evaluation_cache(self.mode) - } - - /// Probably the most involved method of the whole solver. - /// - /// Given some goal which is proven via the `prove_goal` closure, this - /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal>( - &mut self, - cx: I, - input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, - ) -> QueryResult { - self.check_invariants(); - // Check for overflow. - let Some(available_depth) = Self::allowed_depth_for_nested(cx, &self.stack) else { - if let Some(last) = self.stack.raw.last_mut() { - last.encountered_overflow = true; - } - - inspect - .canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); - return Self::response_no_constraints(cx, input, Certainty::overflow(true)); - }; - - if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) { - debug!("global cache hit"); - return result; - } - - // Check whether the goal is in the provisional cache. - // The provisional result may rely on the path to its cycle roots, - // so we have to check the path of the current goal matches that of - // the cache entry. - let cache_entry = self.provisional_cache.entry(input).or_default(); - if let Some(entry) = cache_entry - .with_coinductive_stack - .as_ref() - .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head)) - .or_else(|| { - cache_entry - .with_inductive_stack - .as_ref() - .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head)) - }) - { - debug!("provisional cache hit"); - // We have a nested goal which is already in the provisional cache, use - // its result. We do not provide any usage kind as that should have been - // already set correctly while computing the cache entry. - inspect.canonical_goal_evaluation_kind( - inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit, - ); - Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head); - return entry.result; - } else if let Some(stack_depth) = cache_entry.stack_depth { - debug!("encountered cycle with depth {stack_depth:?}"); - // We have a nested goal which directly relies on a goal deeper in the stack. - // - // We start by tagging all cycle participants, as that's necessary for caching. - // - // Finally we can return either the provisional response or the initial response - // in case we're in the first fixpoint iteration for this goal. - inspect.canonical_goal_evaluation_kind( - inspect::WipCanonicalGoalEvaluationKind::CycleInStack, - ); - let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth); - let usage_kind = if is_coinductive_cycle { - HasBeenUsed::COINDUCTIVE_CYCLE - } else { - HasBeenUsed::INDUCTIVE_CYCLE - }; - Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth); - - // Return the provisional result or, if we're in the first iteration, - // start with no constraints. - return if let Some(result) = self.stack[stack_depth].provisional_result { - result - } else if is_coinductive_cycle { - Self::response_no_constraints(cx, input, Certainty::Yes) - } else { - Self::response_no_constraints(cx, input, Certainty::overflow(false)) - }; - } else { - // No entry, we push this goal on the stack and try to prove it. - let depth = self.stack.next_index(); - let entry = StackEntry { - input, - available_depth, - reached_depth: depth, - non_root_cycle_participant: None, - encountered_overflow: false, - has_been_used: HasBeenUsed::empty(), - nested_goals: Default::default(), - provisional_result: None, - }; - assert_eq!(self.stack.push(entry), depth); - cache_entry.stack_depth = Some(depth); - } - - // This is for global caching, so we properly track query dependencies. - // Everything that affects the `result` should be performed within this - // `with_anon_task` closure. If computing this goal depends on something - // not tracked by the cache key and from outside of this anon task, it - // must not be added to the global cache. Notably, this is the case for - // trait solver cycles participants. - let ((final_entry, result), dep_node) = cx.with_cached_task(|| { - for _ in 0..FIXPOINT_STEP_LIMIT { - match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) { - StepResult::Done(final_entry, result) => return (final_entry, result), - StepResult::HasChanged => debug!("fixpoint changed provisional results"), - } - } - - debug!("canonical cycle overflow"); - let current_entry = self.stack.pop().unwrap(); - debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(cx, input, Certainty::overflow(false)); - (current_entry, result) - }); - - let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); - - self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); - - // We're now done with this goal. In case this goal is involved in a larger cycle - // do not remove it from the provisional cache and update its provisional result. - // We only add the root of cycles to the global cache. - if let Some(head) = final_entry.non_root_cycle_participant { - let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head); - - let entry = self.provisional_cache.get_mut(&input).unwrap(); - entry.stack_depth = None; - if coinductive_stack { - entry.with_coinductive_stack = Some(DetachedEntry { head, result }); - } else { - entry.with_inductive_stack = Some(DetachedEntry { head, result }); - } - } else { - self.provisional_cache.remove(&input); - let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len(); - // When encountering a cycle, both inductive and coinductive, we only - // move the root into the global cache. We also store all other cycle - // participants involved. - // - // We must not use the global cache entry of a root goal if a cycle - // participant is on the stack. This is necessary to prevent unstable - // results. See the comment of `StackEntry::nested_goals` for - // more details. - self.global_cache(cx).insert( - cx, - input, - proof_tree, - reached_depth, - final_entry.encountered_overflow, - final_entry.nested_goals, - dep_node, - result, - ) - } - - self.check_invariants(); - - result - } - - /// Try to fetch a previously computed result from the global cache, - /// making sure to only do so if it would match the result of reevaluating - /// this goal. - fn lookup_global_cache>( - &mut self, - cx: I, - input: CanonicalInput, - available_depth: SolverLimit, - inspect: &mut ProofTreeBuilder, - ) -> Option> { - let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self - .global_cache(cx) - // FIXME: Awkward `Limit -> usize -> Limit`. - .get(cx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; - - // If we're building a proof tree and the current cache entry does not - // contain a proof tree, we do not use the entry but instead recompute - // the goal. We simply overwrite the existing entry once we're done, - // caching the proof tree. - if !inspect.is_noop() { - if let Some(final_revision) = proof_tree { - let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { final_revision }; - inspect.canonical_goal_evaluation_kind(kind); - } else { - return None; - } - } - - // Adjust the parent goal as if we actually computed this goal. - let reached_depth = self.stack.next_index().plus(additional_depth); - self.update_parent_goal(reached_depth, encountered_overflow); - - Some(result) - } -} - -enum StepResult { - Done(StackEntry, QueryResult), - HasChanged, -} - -impl SearchGraph { - /// When we encounter a coinductive cycle, we have to fetch the - /// result of that cycle while we are still computing it. Because - /// of this we continuously recompute the cycle until the result - /// of the previous iteration is equal to the final result, at which - /// point we are done. - fn fixpoint_step_in_task( - &mut self, - cx: I, - input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - prove_goal: &mut F, - ) -> StepResult - where - D: SolverDelegate, - F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, - { - let result = prove_goal(self, inspect); - let stack_entry = self.stack.pop().unwrap(); - debug_assert_eq!(stack_entry.input, input); - - // If the current goal is not the root of a cycle, we are done. - if stack_entry.has_been_used.is_empty() { - return StepResult::Done(stack_entry, result); - } - - // If it is a cycle head, we have to keep trying to prove it until - // we reach a fixpoint. We need to do so for all cycle heads, - // not only for the root. - // - // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs - // for an example. - - // Start by clearing all provisional cache entries which depend on this - // the current goal. - Self::clear_dependent_provisional_results( - &mut self.provisional_cache, - self.stack.next_index(), - ); - - // Check whether we reached a fixpoint, either because the final result - // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the - // final result is equal to the initial response for that case. - let reached_fixpoint = if let Some(r) = stack_entry.provisional_result { + if let Some(r) = provisional_result { r == result - } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE { - Self::response_no_constraints(cx, input, Certainty::Yes) == result - } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE { - Self::response_no_constraints(cx, input, Certainty::overflow(false)) == result } else { - false - }; - - // If we did not reach a fixpoint, update the provisional result and reevaluate. - if reached_fixpoint { - StepResult::Done(stack_entry, result) - } else { - let depth = self.stack.push(StackEntry { - has_been_used: HasBeenUsed::empty(), - provisional_result: Some(result), - ..stack_entry - }); - debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth)); - StepResult::HasChanged + match kind { + UsageKind::Single(CycleKind::Coinductive) => { + response_no_constraints(cx, input, Certainty::Yes) == result + } + UsageKind::Single(CycleKind::Inductive) => { + response_no_constraints(cx, input, Certainty::overflow(false)) == result + } + UsageKind::Mixed => false, + } } } - fn response_no_constraints( + fn on_stack_overflow( cx: I, - goal: CanonicalInput, - certainty: Certainty, + inspect: &mut ProofTreeBuilder, + input: CanonicalInput, ) -> QueryResult { - Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) + inspect.canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); + response_no_constraints(cx, input, Certainty::overflow(true)) } - #[allow(rustc::potential_query_instability)] - fn check_invariants(&self) { - if !cfg!(debug_assertions) { - return; - } + fn on_fixpoint_overflow(cx: I, input: CanonicalInput) -> QueryResult { + response_no_constraints(cx, input, Certainty::overflow(false)) + } - let SearchGraph { mode: _, stack, provisional_cache } = self; - if stack.is_empty() { - assert!(provisional_cache.is_empty()); - } - - for (depth, entry) in stack.iter_enumerated() { - let StackEntry { - input, - available_depth: _, - reached_depth: _, - non_root_cycle_participant, - encountered_overflow: _, - has_been_used, - ref nested_goals, - provisional_result, - } = *entry; - let cache_entry = provisional_cache.get(&entry.input).unwrap(); - assert_eq!(cache_entry.stack_depth, Some(depth)); - if let Some(head) = non_root_cycle_participant { - assert!(head < depth); - assert!(nested_goals.is_empty()); - assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); - - let mut current_root = head; - while let Some(parent) = stack[current_root].non_root_cycle_participant { - current_root = parent; - } - assert!(stack[current_root].nested_goals.contains(&input)); - } - - if !nested_goals.is_empty() { - assert!(provisional_result.is_some() || !has_been_used.is_empty()); - for entry in stack.iter().take(depth.as_usize()) { - assert_eq!(nested_goals.get(&entry.input), None); - } - } - } - - for (&input, entry) in &self.provisional_cache { - let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } = - entry; - assert!( - stack_depth.is_some() - || with_coinductive_stack.is_some() - || with_inductive_stack.is_some() - ); - - if let &Some(stack_depth) = stack_depth { - assert_eq!(stack[stack_depth].input, input); - } - - let check_detached = |detached_entry: &DetachedEntry| { - let DetachedEntry { head, result: _ } = *detached_entry; - assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); - }; - - if let Some(with_coinductive_stack) = with_coinductive_stack { - check_detached(with_coinductive_stack); - } - - if let Some(with_inductive_stack) = with_inductive_stack { - check_detached(with_inductive_stack); - } - } + fn step_is_coinductive(cx: I, input: CanonicalInput) -> bool { + input.value.goal.predicate.is_coinductive(cx) } } + +fn response_no_constraints( + cx: I, + goal: CanonicalInput, + certainty: Certainty, +) -> QueryResult { + Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) +} diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 02c3c87313bc..c2201b1c41ec 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -1,7 +1,7 @@ parse_add_paren = try adding parentheses parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation - .suggestion = add parentheses to clarify the precedence +parse_ambiguous_range_pattern_suggestion = add parentheses to clarify the precedence parse_array_brackets_instead_of_braces = this is a block expression, not an array .suggestion = to make an array, use square brackets instead of curly braces @@ -323,10 +323,10 @@ parse_incorrect_semicolon = .suggestion = remove this semicolon .help = {$name} declarations are not followed by a semicolon -parse_incorrect_use_of_await = - incorrect use of `await` +parse_incorrect_use_of_await = incorrect use of `await` .parentheses_suggestion = `await` is not a method call, remove the parentheses - .postfix_suggestion = `await` is a postfix operation + +parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: @@ -644,7 +644,7 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported - .suggestion = remove the parentheses +parse_parenthesized_lifetime_suggestion = remove the parentheses parse_path_single_colon = path separator must be a double colon .suggestion = use a double colon instead diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3ae9b6dad998..092a2a10ab7b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -18,10 +18,10 @@ use crate::parser::{ForbiddenLetReason, TokenDescription}; #[derive(Diagnostic)] #[diag(parse_maybe_report_ambiguous_plus)] pub(crate) struct AmbiguousPlus { - pub sum_ty: String, #[primary_span] - #[suggestion(code = "({sum_ty})")] pub span: Span, + #[subdiagnostic] + pub suggestion: AddParen, } #[derive(Diagnostic)] @@ -34,17 +34,20 @@ pub(crate) struct BadTypePlus { pub sub: BadTypePlusSub, } +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")] +pub(crate) struct AddParen { + #[suggestion_part(code = "(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum BadTypePlusSub { - #[suggestion( - parse_add_paren, - code = "{sum_with_parens}", - applicability = "machine-applicable" - )] AddParen { - sum_with_parens: String, - #[primary_span] - span: Span, + #[subdiagnostic] + suggestion: AddParen, }, #[label(parse_forgot_paren)] ForgotParen { @@ -80,7 +83,7 @@ pub(crate) struct WrapType { #[diag(parse_incorrect_semicolon)] pub(crate) struct IncorrectSemicolon<'a> { #[primary_span] - #[suggestion(style = "short", code = "", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] pub span: Span, #[help] pub show_help: bool, @@ -91,19 +94,35 @@ pub(crate) struct IncorrectSemicolon<'a> { #[diag(parse_incorrect_use_of_await)] pub(crate) struct IncorrectUseOfAwait { #[primary_span] - #[suggestion(parse_parentheses_suggestion, code = "", applicability = "machine-applicable")] + #[suggestion( + parse_parentheses_suggestion, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_incorrect_use_of_await_postfix_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct AwaitSuggestion { + #[suggestion_part(code = "")] + pub removal: Span, + #[suggestion_part(code = ".await{question_mark}")] + pub dot_await: Span, + pub question_mark: &'static str, +} + #[derive(Diagnostic)] #[diag(parse_incorrect_use_of_await)] pub(crate) struct IncorrectAwait { #[primary_span] pub span: Span, - #[suggestion(parse_postfix_suggestion, code = "{expr}.await{question_mark}")] - pub sugg_span: (Span, Applicability), - pub expr: String, - pub question_mark: &'static str, + #[subdiagnostic] + pub suggestion: AwaitSuggestion, } #[derive(Diagnostic)] @@ -111,7 +130,7 @@ pub(crate) struct IncorrectAwait { pub(crate) struct InInTypo { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")] pub sugg_span: Span, } @@ -126,17 +145,33 @@ pub(crate) struct InvalidVariableDeclaration { #[derive(Subdiagnostic)] pub(crate) enum InvalidVariableDeclarationSub { - #[suggestion(parse_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")] + #[suggestion( + parse_switch_mut_let_order, + style = "verbose", + applicability = "maybe-incorrect", + code = "let mut" + )] SwitchMutLetOrder(#[primary_span] Span), #[suggestion( parse_missing_let_before_mut, applicability = "machine-applicable", + style = "verbose", code = "let mut" )] MissingLet(#[primary_span] Span), - #[suggestion(parse_use_let_not_auto, applicability = "machine-applicable", code = "let")] + #[suggestion( + parse_use_let_not_auto, + style = "verbose", + applicability = "machine-applicable", + code = "let" + )] UseLetNotAuto(#[primary_span] Span), - #[suggestion(parse_use_let_not_var, applicability = "machine-applicable", code = "let")] + #[suggestion( + parse_use_let_not_var, + style = "verbose", + applicability = "machine-applicable", + code = "let" + )] UseLetNotVar(#[primary_span] Span), } @@ -144,7 +179,7 @@ pub(crate) enum InvalidVariableDeclarationSub { #[diag(parse_switch_ref_box_order)] pub(crate) struct SwitchRefBoxOrder { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "box ref")] + #[suggestion(applicability = "machine-applicable", style = "verbose", code = "box ref")] pub span: Span, } @@ -162,7 +197,7 @@ pub(crate) struct InvalidComparisonOperator { pub(crate) enum InvalidComparisonOperatorSub { #[suggestion( parse_use_instead, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "{correct}" )] @@ -191,14 +226,14 @@ pub(crate) struct InvalidLogicalOperator { pub(crate) enum InvalidLogicalOperatorSub { #[suggestion( parse_use_amp_amp_for_conjunction, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "&&" )] Conjunction(#[primary_span] Span), #[suggestion( parse_use_pipe_pipe_for_disjunction, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "||" )] @@ -209,7 +244,7 @@ pub(crate) enum InvalidLogicalOperatorSub { #[diag(parse_tilde_is_not_unary_operator)] pub(crate) struct TildeAsUnaryOperator( #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = "!")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "!")] pub Span, ); @@ -227,7 +262,7 @@ pub(crate) struct NotAsNegationOperator { pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_default, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -235,7 +270,7 @@ pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_bitwise, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -243,7 +278,7 @@ pub enum NotAsNegationOperatorSub { #[suggestion( parse_unexpected_token_after_not_logical, - style = "short", + style = "verbose", applicability = "machine-applicable", code = "!" )] @@ -254,9 +289,9 @@ pub enum NotAsNegationOperatorSub { #[diag(parse_malformed_loop_label)] pub(crate) struct MalformedLoopLabel { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "{correct_label}")] pub span: Span, - pub correct_label: Ident, + #[suggestion(applicability = "machine-applicable", code = "'", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -264,7 +299,7 @@ pub(crate) struct MalformedLoopLabel { pub(crate) struct LifetimeInBorrowExpression { #[primary_span] pub span: Span, - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] #[label] pub lifetime_span: Span, } @@ -306,7 +341,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { pub span: Span, #[label] pub label: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = ": ")] pub label_end: Span, } @@ -315,7 +350,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { #[note] pub(crate) struct DoCatchSyntaxRemoved { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "try")] + #[suggestion(applicability = "machine-applicable", code = "try", style = "verbose")] pub span: Span, } @@ -323,9 +358,9 @@ pub(crate) struct DoCatchSyntaxRemoved { #[diag(parse_float_literal_requires_integer_part)] pub(crate) struct FloatLiteralRequiresIntegerPart { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "{correct}")] pub span: Span, - pub correct: String, + #[suggestion(applicability = "machine-applicable", code = "0", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -394,7 +429,12 @@ pub struct TernaryOperator { } #[derive(Subdiagnostic)] -#[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")] +#[suggestion( + parse_extra_if_in_let_else, + applicability = "maybe-incorrect", + code = "", + style = "verbose" +)] pub(crate) struct IfExpressionLetSomeSub { #[primary_span] pub if_span: Span, @@ -463,7 +503,7 @@ pub(crate) struct ExpectedElseBlock { pub first_tok: String, #[label] pub else_span: Span, - #[suggestion(applicability = "maybe-incorrect", code = "if ")] + #[suggestion(applicability = "maybe-incorrect", code = "if ", style = "verbose")] pub condition_start: Span, } @@ -491,7 +531,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { pub ctx_span: Span, pub ctx: String, - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] pub attributes: Span, } @@ -509,12 +549,17 @@ pub(crate) enum MissingInInForLoopSub { // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect #[suggestion( parse_use_in_not_of, - style = "short", + style = "verbose", applicability = "maybe-incorrect", code = "in" )] InNotOf(#[primary_span] Span), - #[suggestion(parse_add_in, style = "short", applicability = "maybe-incorrect", code = " in ")] + #[suggestion( + parse_add_in, + style = "verbose", + applicability = "maybe-incorrect", + code = " in " + )] AddIn(#[primary_span] Span), } @@ -545,7 +590,7 @@ pub(crate) struct LoopElseNotSupported { #[diag(parse_missing_comma_after_match_arm)] pub(crate) struct MissingCommaAfterMatchArm { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = ",")] + #[suggestion(applicability = "machine-applicable", code = ",", style = "verbose")] pub span: Span, } @@ -563,7 +608,7 @@ pub(crate) struct CatchAfterTry { pub(crate) struct CommaAfterBaseStruct { #[primary_span] pub span: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = "")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")] pub comma: Span, } @@ -572,7 +617,7 @@ pub(crate) struct CommaAfterBaseStruct { pub(crate) struct EqFieldInit { #[primary_span] pub span: Span, - #[suggestion(applicability = "machine-applicable", code = ":")] + #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] pub eq: Span, } @@ -580,8 +625,18 @@ pub(crate) struct EqFieldInit { #[diag(parse_dotdotdot)] pub(crate) struct DotDotDot { #[primary_span] - #[suggestion(parse_suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] - #[suggestion(parse_suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] + #[suggestion( + parse_suggest_exclusive_range, + applicability = "maybe-incorrect", + code = "..", + style = "verbose" + )] + #[suggestion( + parse_suggest_inclusive_range, + applicability = "maybe-incorrect", + code = "..=", + style = "verbose" + )] pub span: Span, } @@ -589,7 +644,7 @@ pub(crate) struct DotDotDot { #[diag(parse_left_arrow_operator)] pub(crate) struct LeftArrowOperator { #[primary_span] - #[suggestion(applicability = "maybe-incorrect", code = "< -")] + #[suggestion(applicability = "maybe-incorrect", code = "< -", style = "verbose")] pub span: Span, } @@ -597,7 +652,7 @@ pub(crate) struct LeftArrowOperator { #[diag(parse_remove_let)] pub(crate) struct RemoveLet { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "")] + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] pub span: Span, } @@ -605,8 +660,9 @@ pub(crate) struct RemoveLet { #[diag(parse_use_eq_instead)] pub(crate) struct UseEqInstead { #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = "=")] pub span: Span, + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -780,7 +836,7 @@ pub(crate) struct InclusiveRangeExtraEquals { #[primary_span] #[suggestion( parse_suggestion_remove_eq, - style = "short", + style = "verbose", code = "..=", applicability = "maybe-incorrect" )] @@ -803,13 +859,14 @@ pub(crate) struct InclusiveRangeMatchArrow { #[note] pub(crate) struct InclusiveRangeNoEnd { #[primary_span] + pub span: Span, #[suggestion( parse_suggestion_open_range, - code = "..", + code = "", applicability = "machine-applicable", - style = "short" + style = "verbose" )] - pub span: Span, + pub suggestion: Span, } #[derive(Subdiagnostic)] @@ -824,7 +881,8 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg { #[suggestion( parse_suggestion_use_comma_not_semicolon, code = ",", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] UseComma { #[primary_span] @@ -867,7 +925,7 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[diag(parse_non_string_abi_literal)] pub(crate) struct NonStringAbiLiteral { #[primary_span] - #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")] + #[suggestion(code = "\"C\"", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -890,7 +948,7 @@ pub(crate) struct MismatchedClosingDelimiter { #[help] pub(crate) struct IncorrectVisibilityRestriction { #[primary_span] - #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")] + #[suggestion(code = "in {inner_str}", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub inner_str: String, } @@ -915,7 +973,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr { pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] pub span: Span, - #[suggestion(code = ",", applicability = "machine-applicable")] + #[suggestion(code = ",", applicability = "machine-applicable", style = "verbose")] pub missing_comma: Option, } @@ -923,7 +981,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything { #[diag(parse_const_let_mutually_exclusive)] pub(crate) struct ConstLetMutuallyExclusive { #[primary_span] - #[suggestion(code = "const", applicability = "maybe-incorrect")] + #[suggestion(code = "const", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -951,8 +1009,9 @@ pub(crate) struct InvalidCurlyInLetElse { #[help] pub(crate) struct CompoundAssignmentExpressionInLet { #[primary_span] - #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")] pub span: Span, + #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -996,7 +1055,12 @@ pub(crate) struct SuggEscapeIdentifier { } #[derive(Subdiagnostic)] -#[suggestion(parse_sugg_remove_comma, applicability = "machine-applicable", code = "")] +#[suggestion( + parse_sugg_remove_comma, + applicability = "machine-applicable", + code = "", + style = "verbose" +)] pub(crate) struct SuggRemoveComma { #[primary_span] pub span: Span, @@ -1147,13 +1211,18 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { #[derive(Subdiagnostic)] pub(crate) enum ExpectedSemiSugg { - #[suggestion(parse_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable")] + #[suggestion( + parse_sugg_change_this_to_semi, + code = ";", + applicability = "machine-applicable", + style = "short" + )] ChangeToSemi(#[primary_span] Span), #[suggestion( parse_sugg_add_semi, - style = "short", code = ";", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "short" )] AddSemi(#[primary_span] Span), } @@ -1198,7 +1267,7 @@ pub(crate) struct StructLiteralNeedingParensSugg { #[diag(parse_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub num_extra_brackets: usize, } @@ -1337,7 +1406,7 @@ pub(crate) struct AttributeOnParamType { #[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] - #[suggestion(code = "_", applicability = "machine-applicable")] + #[suggestion(code = "_", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -1421,7 +1490,7 @@ pub(crate) struct AsyncMoveOrderIncorrect { pub(crate) struct DoubleColonInBound { #[primary_span] pub span: Span, - #[suggestion(code = ": ", applicability = "machine-applicable")] + #[suggestion(code = ": ", applicability = "machine-applicable", style = "verbose")] pub between: Span, } @@ -1500,9 +1569,11 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { #[diag(parse_path_single_colon)] pub(crate) struct PathSingleColon { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "::")] pub span: Span, + #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")] + pub suggestion: Span, + #[note(parse_type_ascription_removed)] pub type_ascription: Option<()>, } @@ -1511,7 +1582,7 @@ pub(crate) struct PathSingleColon { #[diag(parse_colon_as_semi)] pub(crate) struct ColonAsSemi { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = ";")] + #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")] pub span: Span, #[note(parse_type_ascription_removed)] @@ -1662,9 +1733,9 @@ pub(crate) enum MissingKeywordForItemDefinition { pub(crate) enum AmbiguousMissingKwForItemSub { #[suggestion( parse_suggestion, - style = "verbose", applicability = "maybe-incorrect", - code = "{snippet}!" + code = "{snippet}!", + style = "verbose" )] SuggestMacro { #[primary_span] @@ -1679,7 +1750,7 @@ pub(crate) enum AmbiguousMissingKwForItemSub { #[diag(parse_missing_fn_params)] pub(crate) struct MissingFnParams { #[primary_span] - #[suggestion(code = "()", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "()", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -1687,9 +1758,19 @@ pub(crate) struct MissingFnParams { #[diag(parse_missing_trait_in_trait_impl)] pub(crate) struct MissingTraitInTraitImpl { #[primary_span] - #[suggestion(parse_suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")] + #[suggestion( + parse_suggestion_add_trait, + code = " Trait ", + applicability = "has-placeholders", + style = "verbose" + )] pub span: Span, - #[suggestion(parse_suggestion_remove_for, code = "", applicability = "maybe-incorrect")] + #[suggestion( + parse_suggestion_remove_for, + code = "", + applicability = "maybe-incorrect", + style = "verbose" + )] pub for_span: Span, } @@ -1697,7 +1778,7 @@ pub(crate) struct MissingTraitInTraitImpl { #[diag(parse_missing_for_in_trait_impl)] pub(crate) struct MissingForInTraitImpl { #[primary_span] - #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = " for ", applicability = "machine-applicable")] pub span: Span, } @@ -1712,7 +1793,7 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { #[diag(parse_extra_impl_keyword_in_trait_impl)] pub(crate) struct ExtraImplKeywordInTraitImpl { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "short")] pub extra_impl_kw: Span, #[note] pub impl_trait_span: Span, @@ -1771,7 +1852,7 @@ pub(crate) struct ExternCrateNameWithDashesSugg { pub(crate) struct ExternItemCannotBeConst { #[primary_span] pub ident_span: Span, - #[suggestion(code = "static ", applicability = "machine-applicable")] + #[suggestion(code = "static ", applicability = "machine-applicable", style = "verbose")] pub const_span: Option, } @@ -1781,7 +1862,7 @@ pub(crate) struct ConstGlobalCannotBeMutable { #[primary_span] #[label] pub ident_span: Span, - #[suggestion(code = "static", applicability = "maybe-incorrect")] + #[suggestion(code = "static", style = "verbose", applicability = "maybe-incorrect")] pub const_span: Span, } @@ -1789,7 +1870,7 @@ pub(crate) struct ConstGlobalCannotBeMutable { #[diag(parse_missing_const_type)] pub(crate) struct MissingConstType { #[primary_span] - #[suggestion(code = "{colon} ", applicability = "has-placeholders")] + #[suggestion(code = "{colon} ", style = "verbose", applicability = "has-placeholders")] pub span: Span, pub kind: &'static str, @@ -1800,7 +1881,7 @@ pub(crate) struct MissingConstType { #[diag(parse_enum_struct_mutually_exclusive)] pub(crate) struct EnumStructMutuallyExclusive { #[primary_span] - #[suggestion(code = "enum", applicability = "machine-applicable")] + #[suggestion(code = "enum", style = "verbose", applicability = "machine-applicable")] pub span: Span, } @@ -2037,7 +2118,12 @@ pub struct UnknownTokenStart { #[derive(Subdiagnostic)] pub enum TokenSubstitution { - #[suggestion(parse_sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_sugg_quotes, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] DirectedQuotes { #[primary_span] span: Span, @@ -2045,7 +2131,12 @@ pub enum TokenSubstitution { ascii_str: &'static str, ascii_name: &'static str, }, - #[suggestion(parse_sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_sugg_other, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] Other { #[primary_span] span: Span, @@ -2081,7 +2172,12 @@ pub enum UnescapeError { EscapeOnlyChar { #[primary_span] span: Span, - #[suggestion(parse_escape, applicability = "machine-applicable", code = "{escaped_sugg}")] + #[suggestion( + parse_escape, + applicability = "machine-applicable", + code = "{escaped_sugg}", + style = "verbose" + )] char_span: Span, escaped_sugg: String, escaped_msg: String, @@ -2090,7 +2186,12 @@ pub enum UnescapeError { #[diag(parse_bare_cr)] BareCr { #[primary_span] - #[suggestion(parse_escape, applicability = "machine-applicable", code = "\\r")] + #[suggestion( + parse_escape, + applicability = "machine-applicable", + code = "\\r", + style = "verbose" + )] span: Span, double_quotes: bool, }, @@ -2207,7 +2308,8 @@ pub enum MoreThanOneCharSugg { #[suggestion( parse_consider_normalized, code = "{normalized}", - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] NormalizedForm { #[primary_span] @@ -2215,13 +2317,23 @@ pub enum MoreThanOneCharSugg { ch: String, normalized: String, }, - #[suggestion(parse_remove_non, code = "{ch}", applicability = "maybe-incorrect")] + #[suggestion( + parse_remove_non, + code = "{ch}", + applicability = "maybe-incorrect", + style = "verbose" + )] RemoveNonPrinting { #[primary_span] span: Span, ch: String, }, - #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")] + #[suggestion( + parse_use_double_quotes, + code = "{sugg}", + applicability = "machine-applicable", + style = "verbose" + )] QuotesFull { #[primary_span] span: Span, @@ -2259,7 +2371,12 @@ pub enum MoreThanOneCharNote { #[derive(Subdiagnostic)] pub enum NoBraceUnicodeSub { - #[suggestion(parse_use_braces, code = "{suggestion}", applicability = "maybe-incorrect")] + #[suggestion( + parse_use_braces, + code = "{suggestion}", + applicability = "maybe-incorrect", + style = "verbose" + )] Suggestion { #[primary_span] span: Span, @@ -2269,27 +2386,32 @@ pub enum NoBraceUnicodeSub { Help, } +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_sugg_wrap_pattern_in_parens, applicability = "machine-applicable")] +pub(crate) struct WrapInParens { + #[suggestion_part(code = "(")] + pub(crate) lo: Span, + #[suggestion_part(code = ")")] + pub(crate) hi: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum TopLevelOrPatternNotAllowedSugg { #[suggestion( parse_sugg_remove_leading_vert_in_pattern, - code = "{pat}", - applicability = "machine-applicable" + code = "", + applicability = "machine-applicable", + style = "verbose" )] RemoveLeadingVert { #[primary_span] span: Span, - pat: String, }, - #[suggestion( - parse_sugg_wrap_pattern_in_parens, - code = "({pat})", - applicability = "machine-applicable" - )] WrapInParens { #[primary_span] span: Span, - pat: String, + #[subdiagnostic] + suggestion: WrapInParens, }, } @@ -2298,7 +2420,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg { #[note(parse_note_pattern_alternatives_use_single_vert)] pub(crate) struct UnexpectedVertVertBeforeFunctionParam { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2306,7 +2428,7 @@ pub(crate) struct UnexpectedVertVertBeforeFunctionParam { #[diag(parse_unexpected_vert_vert_in_pattern)] pub(crate) struct UnexpectedVertVertInPattern { #[primary_span] - #[suggestion(code = "|", applicability = "machine-applicable")] + #[suggestion(code = "|", applicability = "machine-applicable", style = "verbose")] pub span: Span, #[label(parse_label_while_parsing_or_pattern_here)] pub start: Option, @@ -2316,7 +2438,7 @@ pub(crate) struct UnexpectedVertVertInPattern { #[diag(parse_trailing_vert_not_allowed)] pub(crate) struct TrailingVertNotAllowed { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, #[label(parse_label_while_parsing_or_pattern_here)] pub start: Option, @@ -2329,16 +2451,17 @@ pub(crate) struct TrailingVertNotAllowed { #[diag(parse_dotdotdot_rest_pattern)] pub(crate) struct DotDotDotRestPattern { #[primary_span] - #[suggestion(style = "short", code = "..", applicability = "machine-applicable")] #[label] pub span: Span, + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub suggestion: Span, } #[derive(Diagnostic)] #[diag(parse_pattern_on_wrong_side_of_at)] pub(crate) struct PatternOnWrongSideOfAt { #[primary_span] - #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")] + #[suggestion(code = "{whole_pat}", applicability = "machine-applicable", style = "verbose")] pub whole_span: Span, pub whole_pat: String, #[label(parse_label_pattern)] @@ -2359,22 +2482,35 @@ pub(crate) struct ExpectedBindingLeftOfAt { pub rhs: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_ambiguous_range_pattern_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct ParenRangeSuggestion { + #[suggestion_part(code = "(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(parse_ambiguous_range_pattern)] pub(crate) struct AmbiguousRangePattern { #[primary_span] - #[suggestion(code = "({pat})", applicability = "maybe-incorrect")] pub span: Span, - pub pat: String, + #[subdiagnostic] + pub suggestion: ParenRangeSuggestion, } #[derive(Diagnostic)] #[diag(parse_unexpected_lifetime_in_pattern)] pub(crate) struct UnexpectedLifetimeInPattern { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, pub symbol: Symbol, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -2383,7 +2519,7 @@ pub(crate) enum InvalidMutInPattern { #[note(parse_note_mut_pattern_usage)] NestedIdent { #[primary_span] - #[suggestion(code = "{pat}", applicability = "machine-applicable")] + #[suggestion(code = "{pat}", applicability = "machine-applicable", style = "verbose")] span: Span, pat: String, }, @@ -2391,7 +2527,7 @@ pub(crate) enum InvalidMutInPattern { #[note(parse_note_mut_pattern_usage)] NonIdent { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] span: Span, }, } @@ -2400,7 +2536,7 @@ pub(crate) enum InvalidMutInPattern { #[diag(parse_repeated_mut_in_pattern)] pub(crate) struct RepeatedMutInPattern { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2408,7 +2544,7 @@ pub(crate) struct RepeatedMutInPattern { #[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)] pub(crate) struct DotDotDotRangeToPatternNotAllowed { #[primary_span] - #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "..=", applicability = "machine-applicable")] pub span: Span, } @@ -2472,8 +2608,9 @@ pub(crate) struct UnexpectedParenInRangePatSugg { #[diag(parse_return_types_use_thin_arrow)] pub(crate) struct ReturnTypesUseThinArrow { #[primary_span] - #[suggestion(style = "short", code = "->", applicability = "machine-applicable")] pub span: Span, + #[suggestion(style = "verbose", code = " -> ", applicability = "machine-applicable")] + pub suggestion: Span, } #[derive(Diagnostic)] @@ -2488,7 +2625,7 @@ pub(crate) struct NeedPlusAfterTraitObjectLifetime { pub(crate) struct ExpectedMutOrConstInRawPointerType { #[primary_span] pub span: Span, - #[suggestion(code("mut ", "const "), applicability = "has-placeholders")] + #[suggestion(code("mut ", "const "), applicability = "has-placeholders", style = "verbose")] pub after_asterisk: Span, } @@ -2497,7 +2634,7 @@ pub(crate) struct ExpectedMutOrConstInRawPointerType { pub(crate) struct LifetimeAfterMut { #[primary_span] pub span: Span, - #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")] + #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect", style = "verbose")] pub suggest_lifetime: Option, pub snippet: String, } @@ -2506,7 +2643,7 @@ pub(crate) struct LifetimeAfterMut { #[diag(parse_dyn_after_mut)] pub(crate) struct DynAfterMut { #[primary_span] - #[suggestion(code = "&mut dyn", applicability = "machine-applicable")] + #[suggestion(code = "&mut dyn", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2515,7 +2652,7 @@ pub(crate) struct DynAfterMut { pub(crate) struct FnPointerCannotBeConst { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, } @@ -2525,7 +2662,7 @@ pub(crate) struct FnPointerCannotBeConst { pub(crate) struct FnPointerCannotBeAsync { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] #[label] pub qualifier: Span, } @@ -2542,8 +2679,9 @@ pub(crate) struct NestedCVariadicType { #[help] pub(crate) struct InvalidDynKeyword { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub suggestion: Span, } #[derive(Subdiagnostic)] @@ -2584,7 +2722,7 @@ pub struct BoxSyntaxRemoved<'a> { #[diag(parse_bad_return_type_notation_output)] pub(crate) struct BadReturnTypeNotationOutput { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, } @@ -2655,14 +2793,25 @@ pub(crate) struct ModifierLifetime { pub modifier: &'static str, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_parenthesized_lifetime_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct RemoveParens { + #[suggestion_part(code = "")] + pub lo: Span, + #[suggestion_part(code = "")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(parse_parenthesized_lifetime)] pub(crate) struct ParenthesizedLifetime { #[primary_span] pub span: Span, - #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")] - pub sugg: Option, - pub snippet: String, + #[subdiagnostic] + pub sugg: RemoveParens, } #[derive(Diagnostic)] @@ -2677,7 +2826,7 @@ pub(crate) struct UnderscoreLiteralSuffix { pub(crate) struct ExpectedLabelFoundIdent { #[primary_span] pub span: Span, - #[suggestion(code = "'", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "'", applicability = "machine-applicable", style = "verbose")] pub start: Span, } @@ -2696,7 +2845,7 @@ pub(crate) struct InappropriateDefault { #[diag(parse_recover_import_as_use)] pub(crate) struct RecoverImportAsUse { #[primary_span] - #[suggestion(code = "use", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "use", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub token_name: String, } @@ -2706,7 +2855,7 @@ pub(crate) struct RecoverImportAsUse { #[note] pub(crate) struct SingleColonImportPath { #[primary_span] - #[suggestion(code = "::", applicability = "machine-applicable", style = "short")] + #[suggestion(code = "::", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2733,7 +2882,7 @@ pub(crate) struct SingleColonStructType { #[diag(parse_equals_struct_default)] pub(crate) struct EqualsStructDefault { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, } @@ -2750,7 +2899,7 @@ pub(crate) struct MacroRulesMissingBang { #[diag(parse_macro_name_remove_bang)] pub(crate) struct MacroNameRemoveBang { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "short")] pub span: Span, } @@ -2758,7 +2907,7 @@ pub(crate) struct MacroNameRemoveBang { #[diag(parse_macro_rules_visibility)] pub(crate) struct MacroRulesVisibility<'a> { #[primary_span] - #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")] + #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, pub vis: &'a str, } @@ -2768,7 +2917,7 @@ pub(crate) struct MacroRulesVisibility<'a> { #[help] pub(crate) struct MacroInvocationVisibility<'a> { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub vis: &'a str, } @@ -2778,7 +2927,7 @@ pub(crate) struct MacroInvocationVisibility<'a> { pub(crate) struct NestedAdt<'a> { #[primary_span] pub span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub item: Span, pub keyword: &'a str, pub kw_str: Cow<'a, str>, @@ -2818,7 +2967,7 @@ pub(crate) struct BoxNotPat { #[diag(parse_unmatched_angle)] pub(crate) struct UnmatchedAngle { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, pub plural: bool, } @@ -2858,7 +3007,7 @@ pub(crate) struct IncorrectParensTraitBoundsSugg { #[diag(parse_kw_bad_case)] pub(crate) struct KwBadCase<'a> { #[primary_span] - #[suggestion(code = "{kw}", applicability = "machine-applicable")] + #[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")] pub span: Span, pub kw: &'a str, } @@ -2895,7 +3044,7 @@ pub(crate) struct MetaBadDelimSugg { #[note] pub(crate) struct MalformedCfgAttr { #[primary_span] - #[suggestion(code = "{sugg}")] + #[suggestion(style = "verbose", code = "{sugg}")] pub span: Span, pub sugg: &'static str, } @@ -3000,7 +3149,7 @@ pub(crate) struct AsyncImpl { #[help] pub(crate) struct ExprRArrowCall { #[primary_span] - #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = ".")] pub span: Span, } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 5522127be83e..4454747ea021 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -157,14 +157,14 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok } pub fn parse_cfg_attr( - attr: &Attribute, + cfg_attr: &Attribute, psess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ "; - match attr.get_normal_item().args { + match cfg_attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => { @@ -180,7 +180,7 @@ pub fn parse_cfg_attr( } _ => { psess.dcx().emit_err(errors::MalformedCfgAttr { - span: attr.span, + span: cfg_attr.span, sugg: CFG_ATTR_GRAMMAR_HELP, }); } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 38f18022e3c5..1123c31f5513 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -103,11 +103,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) - .chain(iter::repeat_with(|| { - let token = cursor_snapshot.next(); - (FlatToken::Token(token.0), token.1) - })) + let tokens = iter::once(FlatToken::Token(self.start_token.clone())) + .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) .take(self.num_calls as usize); if self.replace_ranges.is_empty() { @@ -156,11 +153,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { (range.start as usize)..(range.end as usize), target .into_iter() - .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) - .chain( - iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - target_len), - ), + .map(|target| FlatToken::AttrsTarget(target)) + .chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)), ); } make_attr_token_stream(tokens.into_iter(), self.break_last_token) @@ -301,21 +295,22 @@ impl<'a> Parser<'a> { let num_calls = end_pos - start_pos; - // If we have no attributes, then we will never need to - // use any replace ranges. - let replace_ranges: Box<[ReplaceRange]> = if ret.attrs().is_empty() && !self.capture_cfg { - Box::new([]) - } else { - // Grab any replace ranges that occur *inside* the current AST node. - // We will perform the actual replacement when we convert the `LazyAttrTokenStream` - // to an `AttrTokenStream`. - self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] - .iter() - .cloned() - .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) - .collect() - }; + // This is hot enough for `deep-vector` that checking the conditions for an empty iterator + // is measurably faster than actually executing the iterator. + let replace_ranges: Box<[ReplaceRange]> = + if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() { + Box::new([]) + } else { + // Grab any replace ranges that occur *inside* the current AST node. + // We will perform the actual replacement when we convert the `LazyAttrTokenStream` + // to an `AttrTokenStream`. + self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] + .iter() + .cloned() + .chain(inner_attr_replace_ranges.iter().cloned()) + .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) + .collect() + }; let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { start_token, @@ -325,12 +320,9 @@ impl<'a> Parser<'a> { replace_ranges, }); - // If we support tokens at all - if let Some(target_tokens) = ret.tokens_mut() { - if target_tokens.is_none() { - // Store our newly captured tokens into the AST node. - *target_tokens = Some(tokens.clone()); - } + // If we support tokens and don't already have them, store the newly captured tokens. + if let Some(target_tokens @ None) = ret.tokens_mut() { + *target_tokens = Some(tokens.clone()); } let final_attrs = ret.attrs(); @@ -352,15 +344,10 @@ impl<'a> Parser<'a> { let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); - } - - // Only clear our `replace_ranges` when we're finished capturing entirely. - if matches!(self.capture_state.capturing, Capturing::No) { + } else if matches!(self.capture_state.capturing, Capturing::No) { + // Only clear the ranges once we've finished capturing entirely. self.capture_state.replace_ranges.clear(); - // We don't clear `inner_attr_ranges`, as doing so repeatedly - // had a measurable performance impact. Most inner attributes that - // we insert will get removed - when we drop the parser, we'll free - // up the memory used by any attributes that we didn't remove from the map. + self.capture_state.inner_attr_ranges.clear(); } Ok(ret) } @@ -370,7 +357,7 @@ impl<'a> Parser<'a> { /// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and /// close delims. fn make_attr_token_stream( - mut iter: impl Iterator, + iter: impl Iterator, break_last_token: bool, ) -> AttrTokenStream { #[derive(Debug)] @@ -379,19 +366,19 @@ fn make_attr_token_stream( open_delim_sp: Option<(Delimiter, Span, Spacing)>, inner: Vec, } - let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; - let mut token_and_spacing = iter.next(); - while let Some((token, spacing)) = token_and_spacing { - match token { - FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { - stack - .push(FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }); + // The stack always has at least one element. Storing it separately makes for shorter code. + let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] }; + let mut stack_rest = vec![]; + for flat_token in iter { + match flat_token { + FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => { + stack_rest.push(mem::replace( + &mut stack_top, + FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, + )); } - FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => { - let frame_data = stack - .pop() - .unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}")); - + FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => { + let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); assert_eq!( open_delim, delim, @@ -401,29 +388,20 @@ fn make_attr_token_stream( let dspacing = DelimSpacing::new(open_spacing, spacing); let stream = AttrTokenStream::new(frame_data.inner); let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); - stack - .last_mut() - .unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}")) - .inner - .push(delimited); + stack_top.inner.push(delimited); + } + FlatToken::Token((token, spacing)) => { + stack_top.inner.push(AttrTokenTree::Token(token, spacing)) + } + FlatToken::AttrsTarget(target) => { + stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) } - FlatToken::Token(token) => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push(AttrTokenTree::Token(token, spacing)), - FlatToken::AttrsTarget(target) => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } - token_and_spacing = iter.next(); } - let mut final_buf = stack.pop().expect("Missing final buf!"); + if break_last_token { - let last_token = final_buf.inner.pop().unwrap(); + let last_token = stack_top.inner.pop().unwrap(); if let AttrTokenTree::Token(last_token, spacing) = last_token { let unglued_first = last_token.kind.break_two_token_op().unwrap().0; @@ -431,14 +409,14 @@ fn make_attr_token_stream( let mut first_span = last_token.span.shrink_to_lo(); first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1)); - final_buf + stack_top .inner .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing)); } else { panic!("Unexpected last token {last_token:?}") } } - AttrTokenStream::new(final_buf.inner) + AttrTokenStream::new(stack_top.inner) } // Some types are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 81d5f0fca0ec..0da7fefe6ed2 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -3,8 +3,8 @@ use super::{ BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType, }; use crate::errors::{ - AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus, - BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, + BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, @@ -566,7 +566,10 @@ impl<'a> Parser<'a> { && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq))) { // Likely typo: `=` → `==` in let expr or enum item - return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); + return Err(self.dcx().create_err(UseEqInstead { + span: self.token.span, + suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)), + })); } if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { @@ -1151,7 +1154,7 @@ impl<'a> Parser<'a> { // Eat from where we started until the end token so that parsing can continue // as if we didn't have those extra angle brackets. self.eat_to_tokens(end); - let span = lo.until(self.token.span); + let span = lo.to(self.prev_token.span); let num_extra_brackets = number_of_gt + number_of_shr * 2; return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets })); @@ -1539,7 +1542,10 @@ impl<'a> Parser<'a> { pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) { if impl_dyn_multi { - self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span }); + self.dcx().emit_err(AmbiguousPlus { + span: ty.span, + suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() }, + }); } } @@ -1604,25 +1610,14 @@ impl<'a> Parser<'a> { } self.bump(); // `+` - let bounds = self.parse_generic_bounds()?; + let _bounds = self.parse_generic_bounds()?; let sum_span = ty.span.to(self.prev_token.span); let sub = match &ty.kind { - TyKind::Ref(lifetime, mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - s.s.word("&"); - s.print_opt_lifetime(lifetime); - s.print_mutability(mut_ty.mutbl, false); - s.popen(); - s.print_type(&mut_ty.ty); - if !bounds.is_empty() { - s.word(" + "); - s.print_type_bounds(&bounds); - } - s.pclose() - }); - - BadTypePlusSub::AddParen { sum_with_parens, span: sum_span } + TyKind::Ref(_lifetime, mut_ty) => { + let lo = mut_ty.ty.span.shrink_to_lo(); + let hi = self.prev_token.span.shrink_to_hi(); + BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } } TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, _ => BadTypePlusSub::ExpectPath { span: sum_span }, @@ -1964,18 +1959,14 @@ impl<'a> Parser<'a> { is_question: bool, ) -> (Span, ErrorGuaranteed) { let span = lo.to(hi); - let applicability = match expr.kind { - ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` - _ => Applicability::MachineApplicable, - }; - let guar = self.dcx().emit_err(IncorrectAwait { span, - sugg_span: (span, applicability), - expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)), - question_mark: if is_question { "?" } else { "" }, + suggestion: AwaitSuggestion { + removal: lo.until(expr.span), + dot_await: expr.span.shrink_to_hi(), + question_mark: if is_question { "?" } else { "" }, + }, }); - (span, guar) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b2df9a14eb01..4bd20be41712 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -714,7 +714,7 @@ impl<'a> Parser<'a> { type_err.cancel(); self.dcx().emit_err(errors::MalformedLoopLabel { span: label.ident.span, - correct_label: label.ident, + suggestion: label.ident.span.shrink_to_lo(), }); return Ok(expr); } @@ -856,7 +856,7 @@ impl<'a> Parser<'a> { let hi = self.interpolated_or_expr_span(&expr); let span = lo.to(hi); if let Some(lt) = lifetime { - self.error_remove_borrow_lifetime(span, lt.ident.span); + self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span)); } Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) } @@ -1653,6 +1653,7 @@ impl<'a> Parser<'a> { let lo = label_.ident.span; let label = Some(label_); let ate_colon = self.eat(&token::Colon); + let tok_sp = self.token.span; let expr = if self.eat_keyword(kw::While) { self.parse_expr_while(label, lo) } else if self.eat_keyword(kw::For) { @@ -1747,7 +1748,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::RequireColonAfterLabeledExpression { span: expr.span, label: lo, - label_end: lo.shrink_to_hi(), + label_end: lo.between(tok_sp), }); } @@ -2106,7 +2107,7 @@ impl<'a> Parser<'a> { self.bump(); self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart { span: token.span, - correct: pprust::token_to_string(token).into_owned(), + suggestion: token.span.shrink_to_lo(), }); } } @@ -2741,7 +2742,7 @@ impl<'a> Parser<'a> { if !attrs.is_empty() && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess) { - let attributes = x0.span.to(xn.span); + let attributes = x0.span.until(branch_span); let last = xn.span; let ctx = if is_ctx_else { "else" } else { "if" }; self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f31e634f55c8..76857cb85042 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -387,8 +387,8 @@ impl<'a> Parser<'a> { let span = if is_pub { self.prev_token.span.to(ident_span) } else { ident_span }; let insert_span = ident_span.shrink_to_lo(); - let ident = if (!is_const - || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis))) + let ident = if self.token.is_ident() + && (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis))) && self.look_ahead(1, |t| { [ token::Lt, @@ -810,7 +810,7 @@ impl<'a> Parser<'a> { self.dcx().struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); if is_let { - err.span_suggestion( + err.span_suggestion_verbose( non_item_span, "consider using `const` instead of `let` for associated const", "const", @@ -2241,9 +2241,13 @@ impl<'a> Parser<'a> { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; + let mut item = item.unwrap().span; + if self.token == token::Comma { + item = item.to(self.token.span); + } self.dcx().emit_err(errors::NestedAdt { span: kw_token.span, - item: item.unwrap().span, + item, kw_str, keyword: keyword.as_str(), }); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 45ca267fe5d1..958458eda9a7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1118,41 +1118,37 @@ impl<'a> Parser<'a> { return looker(&self.token); } - if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last() - && delim != Delimiter::Invisible - { - // We are not in the outermost token stream, and the token stream - // we are in has non-skipped delimiters. Look for skipped - // delimiters in the lookahead range. - let tree_cursor = &self.token_cursor.tree_cursor; - let all_normal = (0..dist).all(|i| { - let token = tree_cursor.look_ahead(i); - !matches!(token, Some(TokenTree::Delimited(.., Delimiter::Invisible, _))) - }); - if all_normal { - // There were no skipped delimiters. Do lookahead by plain indexing. - return match tree_cursor.look_ahead(dist - 1) { - Some(tree) => { - // Indexing stayed within the current token stream. - match tree { - TokenTree::Token(token, _) => looker(token), - TokenTree::Delimited(dspan, _, delim, _) => { - looker(&Token::new(token::OpenDelim(*delim), dspan.open)) - } + // Typically around 98% of the `dist > 0` cases have `dist == 1`, so we + // have a fast special case for that. + if dist == 1 { + // The index is zero because the tree cursor's index always points + // to the next token to be gotten. + match self.token_cursor.tree_cursor.look_ahead(0) { + Some(tree) => { + // Indexing stayed within the current token tree. + return match tree { + TokenTree::Token(token, _) => looker(token), + TokenTree::Delimited(dspan, _, delim, _) => { + looker(&Token::new(token::OpenDelim(*delim), dspan.open)) } + }; + } + None => { + // The tree cursor lookahead went (one) past the end of the + // current token tree. Try to return a close delimiter. + if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last() + && delim != Delimiter::Invisible + { + // We are not in the outermost token stream, so we have + // delimiters. Also, those delimiters are not skipped. + return looker(&Token::new(token::CloseDelim(delim), span.close)); } - None => { - // Indexing went past the end of the current token - // stream. Use the close delimiter, no matter how far - // ahead `dist` went. - looker(&Token::new(token::CloseDelim(delim), span.close)) - } - }; + } } } - // We are in a more complex case. Just clone the token cursor and use - // `next`, skipping delimiters as necessary. Slow but simple. + // Just clone the token cursor and use `next`, skipping delimiters as + // necessary. Slow but simple. let mut cursor = self.token_cursor.clone(); let mut i = 0; let mut token = Token::dummy(); @@ -1541,14 +1537,16 @@ impl<'a> Parser<'a> { // we don't need N spans, but we want at least one, so print all of prev_token dbg_fmt.field("prev_token", &parser.prev_token); - // make it easier to peek farther ahead by taking TokenKinds only until EOF - let tokens = (0..*lookahead) - .map(|i| parser.look_ahead(i, |tok| tok.kind.clone())) - .scan(parser.prev_token == TokenKind::Eof, |eof, tok| { - let current = eof.then_some(tok.clone()); // include a trailing EOF token - *eof |= &tok == &TokenKind::Eof; - current - }); + let mut tokens = vec![]; + for i in 0..*lookahead { + let tok = parser.look_ahead(i, |tok| tok.kind.clone()); + let is_eof = tok == TokenKind::Eof; + tokens.push(tok); + if is_eof { + // Don't look ahead past EOF. + break; + } + } dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish()); dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls); @@ -1607,7 +1605,7 @@ pub(crate) fn make_unclosed_delims_error( enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens - Token(Token), + Token((Token, Spacing)), /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted /// directly into the constructed `AttrTokenStream` as an /// `AttrTokenTree::AttrsTarget`. diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 6f2b71771594..e4e89615d716 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -4,11 +4,11 @@ use crate::errors::{ DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, - PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, - TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, - UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, + SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -24,7 +24,7 @@ use rustc_errors::{Applicability, Diag, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -236,11 +236,15 @@ impl<'a> Parser<'a> { if let PatKind::Or(pats) = &pat.kind { let span = pat.span; - let pat = pprust::pat_to_string(&pat); let sub = if pats.len() == 1 { - Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat }) + Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { + span: span.with_hi(span.lo() + BytePos(1)), + }) } else { - Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) + Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { + span, + suggestion: WrapInParens { lo: span.shrink_to_lo(), hi: span.shrink_to_hi() }, + }) }; let err = self.dcx().create_err(match syntax_loc { @@ -599,7 +603,10 @@ impl<'a> Parser<'a> { self.bump(); // `...` // The user probably mistook `...` for a rest pattern `..`. - self.dcx().emit_err(DotDotDotRestPattern { span: lo }); + self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: lo.with_lo(lo.hi() - BytePos(1)), + }); PatKind::Rest } @@ -664,8 +671,13 @@ impl<'a> Parser<'a> { _ => return, } - self.dcx() - .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) }); + self.dcx().emit_err(AmbiguousRangePattern { + span: pat.span, + suggestion: ParenRangeSuggestion { + lo: pat.span.shrink_to_lo(), + hi: pat.span.shrink_to_hi(), + }, + }); } /// Parse `&pat` / `&mut pat`. @@ -674,8 +686,11 @@ impl<'a> Parser<'a> { if let token::Lifetime(name) = self.token.kind { self.bump(); // `'a` - self.dcx() - .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name }); + self.dcx().emit_err(UnexpectedLifetimeInPattern { + span: self.prev_token.span, + symbol: name, + suggestion: self.prev_token.span.until(self.token.span), + }); } let mutbl = self.parse_mutability(); @@ -913,10 +928,13 @@ impl<'a> Parser<'a> { self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }) } token::Gt if no_space => { - let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); + let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(); self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }) } - _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }), + _ => self.dcx().emit_err(InclusiveRangeNoEnd { + span, + suggestion: span.with_lo(span.hi() - BytePos(1)), + }), } } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 03c647dd5278..b9014dea7266 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -258,6 +258,7 @@ impl<'a> Parser<'a> { self.bump(); // bump past the colon self.dcx().emit_err(PathSingleColon { span: self.prev_token.span, + suggestion: self.prev_token.span.shrink_to_hi(), type_ascription: self .psess .unstable_features @@ -329,6 +330,7 @@ impl<'a> Parser<'a> { err.cancel(); err = self.dcx().create_err(PathSingleColon { span: self.token.span, + suggestion: self.prev_token.span.shrink_to_hi(), type_ascription: self .psess .unstable_features diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index d65f6ff68eee..70d41de00a7b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -430,8 +430,10 @@ impl<'a> Parser<'a> { let eq_consumed = match self.token.kind { token::BinOpEq(..) => { // Recover `let x = 1` as `let x = 1` - self.dcx() - .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span }); + self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet { + span: self.token.span, + suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)), + }); self.bump(); true } @@ -717,7 +719,7 @@ impl<'a> Parser<'a> { e.cancel(); self.dcx().emit_err(MalformedLoopLabel { span: label.ident.span, - correct_label: label.ident, + suggestion: label.ident.span.shrink_to_lo(), }); *expr = labeled_expr; break 'break_recover None; diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 42392ad2163d..cf791d332a2f 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1376,6 +1376,365 @@ fn ttdelim_span() { }); } +#[track_caller] +fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) { + // Do the `assert_eq` outside the closure so that `track_caller` works. + // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure + // doesn't give the line number in the test below if the assertion fails.) + let tok = p.look_ahead(dist, |tok| tok.clone()); + assert_eq!(kind, tok.kind); +} + +#[test] +fn look_ahead() { + create_default_session_globals_then(|| { + let sym_f = Symbol::intern("f"); + let sym_x = Symbol::intern("x"); + #[allow(non_snake_case)] + let sym_S = Symbol::intern("S"); + let raw_no = IdentIsRaw::No; + + let psess = psess(); + let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); + + // Current position is the `fn`. + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); + // Any lookahead past the end of the token stream returns `Eof`. + look(&p, 13, token::Eof); + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); + + // Move forward to the first `x`. + for _ in 0..3 { + p.bump(); + } + look(&p, 0, token::Ident(sym_x, raw_no)); + look(&p, 1, token::Colon); + look(&p, 2, token::Ident(sym::u32, raw_no)); + look(&p, 3, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 4, token::OpenDelim(Delimiter::Brace)); + look(&p, 5, token::Ident(sym_x, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Brace)); + look(&p, 7, token::Ident(kw::Struct, raw_no)); + look(&p, 8, token::Ident(sym_S, raw_no)); + look(&p, 9, token::Semi); + look(&p, 10, token::Eof); + look(&p, 11, token::Eof); + look(&p, 100, token::Eof); + + // Move forward to the `;`. + for _ in 0..9 { + p.bump(); + } + look(&p, 0, token::Semi); + // Any lookahead past the end of the token stream returns `Eof`. + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); + + // Move one past the `;`, i.e. past the end of the token stream. + p.bump(); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); + + // Bumping after Eof is idempotent. + p.bump(); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); + }); +} + +/// There used to be some buggy behaviour when using `look_ahead` not within +/// the outermost token stream, which this test covers. +#[test] +fn look_ahead_non_outermost_stream() { + create_default_session_globals_then(|| { + let sym_f = Symbol::intern("f"); + let sym_x = Symbol::intern("x"); + #[allow(non_snake_case)] + let sym_S = Symbol::intern("S"); + let raw_no = IdentIsRaw::No; + + let psess = psess(); + let mut p = string_to_parser(&psess, "mod m { fn f(x: u32) { x } struct S; }".to_string()); + + // Move forward to the `fn`, which is not within the outermost token + // stream (because it's inside the `mod { ... }`). + for _ in 0..3 { + p.bump(); + } + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); + look(&p, 13, token::CloseDelim(Delimiter::Brace)); + // Any lookahead past the end of the token stream returns `Eof`. + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); + }); +} + +// FIXME(nnethercote) All the output is currently wrong. +#[test] +fn debug_lookahead() { + create_default_session_globals_then(|| { + let psess = psess(); + let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); + + // Current position is the `fn`. + assert_eq!( + &format!("{:#?}", p.debug_lookahead(0)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 1, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(7)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + ], + approx_token_stream_pos: 1, + .. +}" + ); + // There are 13 tokens. We request 15, get 14; the last one is `Eof`. + assert_eq!( + &format!("{:#?}", p.debug_lookahead(15)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + OpenDelim( + Brace, + ), + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + Semi, + Eof, + ], + approx_token_stream_pos: 1, + .. +}" + ); + + // Move forward to the second `x`. + for _ in 0..8 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(1)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"x\", + No, + ), + ], + approx_token_stream_pos: 9, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(4)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + ], + approx_token_stream_pos: 9, + .. +}" + ); + + // Move two past the final token (the `;`). + for _ in 0..6 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(3)), + "Parser { + prev_token: Token { + kind: Eof, + span: Span { + lo: BytePos( + 27, + ), + hi: BytePos( + 28, + ), + ctxt: #0, + }, + }, + tokens: [ + Eof, + ], + approx_token_stream_pos: 15, + .. +}" + ); + }); +} + // This tests that when parsing a string (rather than a file) we don't try // and read in a file for a module declaration and just parse a stub. // See `recurse_into_file_modules` in the parser. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1e5b227aaa9b..94321b1dddd9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -209,6 +209,7 @@ impl<'a> Parser<'a> { recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { + let lo = self.prev_token.span; Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( @@ -224,7 +225,10 @@ impl<'a> Parser<'a> { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); - self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span }); + self.dcx().emit_err(ReturnTypesUseThinArrow { + span: self.prev_token.span, + suggestion: lo.between(self.token.span), + }); let ty = self.parse_ty_common( allow_plus, AllowCVariadic::No, @@ -794,8 +798,11 @@ impl<'a> Parser<'a> { { if self.token.is_keyword(kw::Dyn) { // Account for `&dyn Trait + dyn Other`. - self.dcx().emit_err(InvalidDynKeyword { span: self.token.span }); self.bump(); + self.dcx().emit_err(InvalidDynKeyword { + span: self.prev_token.span, + suggestion: self.prev_token.span.until(self.token.span), + }); } bounds.push(self.parse_generic_bound()?); if allow_plus == AllowPlus::No || !self.eat_plus() { @@ -861,7 +868,7 @@ impl<'a> Parser<'a> { if has_parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P)`? - self.recover_paren_lifetime(lo, lt.ident.span)?; + self.recover_paren_lifetime(lo)?; } Ok(bound) } @@ -909,16 +916,12 @@ impl<'a> Parser<'a> { } /// Recover on `('lifetime)` with `(` already eaten. - fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> { + fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); - let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) { - (Some(span), snippet) - } else { - (None, String::new()) - }; + let sugg = errors::RemoveParens { lo, hi: self.prev_token.span }; - self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet }); + self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg }); Ok(()) } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d7513fbad63c..1d93cbaddd6f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -290,9 +290,6 @@ passes_export_name = passes_extern_main = the `main` function cannot be declared in an `extern` block -passes_feature_only_on_nightly = - `#![feature]` may not be used on the {$release_channel} release channel - passes_feature_previously_declared = feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a026ff3b13b5..58d27d5b4bba 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1492,14 +1492,6 @@ pub struct TraitImplConstStable { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_feature_only_on_nightly, code = E0554)] -pub struct FeatureOnlyOnNightly { - #[primary_span] - pub span: Span, - pub release_channel: &'static str, -} - #[derive(Diagnostic)] #[diag(passes_unknown_feature, code = E0635)] pub struct UnknownFeature { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6bdfaf0c9089..2c34f477de5c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -936,12 +936,6 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let declared_lib_features = &tcx.features().declared_lib_features; let mut remaining_lib_features = FxIndexMap::default(); for (feature, span) in declared_lib_features { - if !tcx.sess.opts.unstable_features.is_nightly_build() { - tcx.dcx().emit_err(errors::FeatureOnlyOnNightly { - span: *span, - release_channel: env!("CFG_RELEASE_CHANNEL"), - }); - } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs index 6e862db0b254..d8a5bdba7b8a 100644 --- a/compiler/rustc_query_system/src/cache.rs +++ b/compiler/rustc_query_system/src/cache.rs @@ -40,7 +40,7 @@ impl Cache { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct WithDepNode { dep_node: DepNodeIndex, cached_value: T, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ffd495aa9857..e3917acce65b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span }) } - ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => { + ResolutionError::AttemptToUseNonConstantValueInConstant { + ident, + suggestion, + current, + type_span, + } => { // let foo =... // ^^^ given this Span // ------- get this Span to have an applicable suggestion @@ -836,13 +841,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let ((with, with_label), without) = match sp { Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => { - let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32))); + let sp = sp + .with_lo(BytePos(sp.lo().0 - (current.len() as u32))) + .until(ident.span); ( (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion { span: sp, - ident, suggestion, current, + type_span, }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})), None, ) @@ -1985,12 +1992,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(candidate) = candidates.get(0) { let path = { // remove the possible common prefix of the path - let start_index = (0..failed_segment_idx) - .find(|&i| path[i].ident != candidate.path.segments[i].ident) + let len = candidate.path.segments.len(); + let start_index = (0..=failed_segment_idx.min(len - 1)) + .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name) .unwrap_or_default(); - let segments = (start_index..=failed_segment_idx) - .map(|s| candidate.path.segments[s].clone()) - .collect(); + let segments = + (start_index..len).map(|s| candidate.path.segments[s].clone()).collect(); Path { segments, span: Span::default(), tokens: None } }; ( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0620f3d709eb..097f4af05c30 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { } #[derive(Subdiagnostic)] -#[suggestion( +#[multipart_suggestion( resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion, - code = "{suggestion} {ident}", - applicability = "maybe-incorrect" + style = "verbose", + applicability = "has-placeholders" )] pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { - #[primary_span] + // #[primary_span] + #[suggestion_part(code = "{suggestion} ")] pub(crate) span: Span, - pub(crate) ident: Ident, pub(crate) suggestion: &'a str, + #[suggestion_part(code = ": /* Type */")] + pub(crate) type_span: Option, pub(crate) current: &'a str, } @@ -1089,8 +1091,8 @@ pub(crate) struct ToolWasAlreadyRegistered { #[derive(Diagnostic)] #[diag(resolve_tool_only_accepts_identifiers)] pub(crate) struct ToolOnlyAcceptsIdentifiers { - #[label] #[primary_span] + #[label] pub(crate) span: Span, pub(crate) tool: Symbol, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7d531385e212..f1934ff184bc 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { let (span, resolution_error) = match item { None if rib_ident.as_str() == "self" => (span, LowercaseSelf), - None => ( - rib_ident.span, - AttemptToUseNonConstantValueInConstant( - original_rib_ident_def, - "const", - "let", - ), - ), + None => { + // If we have a `let name = expr;`, we have the span for + // `name` and use that to see if it is followed by a type + // specifier. If not, then we know we need to suggest + // `const name: Ty = expr;`. This is a heuristic, it will + // break down in the presence of macros. + let sm = self.tcx.sess.source_map(); + let type_span = match sm.span_look_ahead( + original_rib_ident_def.span, + ":", + None, + ) { + None => { + Some(original_rib_ident_def.span.shrink_to_hi()) + } + Some(_) => None, + }; + ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant { + ident: original_rib_ident_def, + suggestion: "const", + current: "let", + type_span, + }, + ) + } Some((ident, kind)) => ( span, - AttemptToUseNonConstantValueInConstant( + AttemptToUseNonConstantValueInConstant { ident, - "let", - kind.as_str(), - ), + suggestion: "let", + current: kind.as_str(), + type_span: None, + }, ), }; self.report_error(span, resolution_error); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7cb5a3fb2fd1..3dcb83d65b02 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -236,11 +236,12 @@ enum ResolutionError<'a> { /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. - AttemptToUseNonConstantValueInConstant( - Ident, - /* suggestion */ &'static str, - /* current */ &'static str, - ), + AttemptToUseNonConstantValueInConstant { + ident: Ident, + suggestion: &'static str, + current: &'static str, + type_span: Option, + }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { shadowing_binding: PatternSource, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 41c99f7edeef..e748d1ff47b6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2620,7 +2620,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // This is the location used by the `rust-src` `rustup` component. let mut candidate = sysroot.join("lib/rustlib/src/rust"); if let Ok(metadata) = candidate.symlink_metadata() { - // Replace the symlink rustbuild creates, with its destination. + // Replace the symlink bootstrap creates, with its destination. // We could try to use `fs::canonicalize` instead, but that might // produce unnecessarily verbose path. if metadata.file_type().is_symlink() { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7421cae65e4f..8fd1876ff1d2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1687,6 +1687,8 @@ options! { (default: no)"), dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED], "the directory the MIR is dumped into (default: `mir_dump`)"), + dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED], + "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"), dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], @@ -1709,6 +1711,8 @@ options! { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), + enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], + "enforce the type length limit when monomorphizing instances in codegen"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), external_clangrt: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 7b5abcf45130..7c3553b60fdd 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -466,7 +466,6 @@ impl RustcInternal for Abi { Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, - Abi::Wasm => rustc_target::spec::abi::Abi::Wasm, Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 9382460d6d40..ef2eb7d52eae 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -909,7 +909,6 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { abi::Abi::AvrInterrupt => Abi::AvrInterrupt, abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, - abi::Abi::Wasm => Abi::Wasm, abi::Abi::System { unwind } => Abi::System { unwind }, abi::Abi::RustIntrinsic => Abi::RustIntrinsic, abi::Abi::RustCall => Abi::RustCall, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index af56f4e51413..2fe7c951793f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2072,9 +2072,11 @@ symbols! { write_str, write_via_move, writeln_macro, + x86_amx_intrinsics, x87_reg, xer, xmm_reg, + xop_target_feature, yeet_desugar_details, yeet_expr, yes, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8058130f4415..9f13c195e4ce 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -1,6 +1,6 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; -use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt}; +use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -854,7 +854,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { return Ok(()); } - match &cx.target_spec().arch[..] { + let spec = cx.target_spec(); + match &spec.arch[..] { "x86" => { let flavor = if let spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } = abi @@ -901,9 +902,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { - if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) - == spec::abi::Abi::PtxKernel - { + if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { nvptx64::compute_abi_info(self) @@ -912,13 +911,14 @@ impl<'a, Ty> FnAbi<'a, Ty> { "hexagon" => hexagon::compute_abi_info(self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), - "wasm32" | "wasm64" => { - if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm { + "wasm32" => { + if spec.os == "unknown" && cx.wasm_c_abi_opt() == WasmCAbi::Legacy { wasm::compute_wasm_abi_info(self) } else { wasm::compute_c_abi_info(cx, self) } } + "wasm64" => wasm::compute_c_abi_info(cx, self), "bpf" => bpf::compute_abi_info(self), arch => { return Err(AdjustForForeignAbiError::Unsupported { diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index bf51bb4bf825..0d61345a70e4 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -48,7 +48,6 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, - Wasm, System { unwind: bool, }, @@ -123,7 +122,6 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" }, - AbiData { abi: Abi::Wasm, name: "wasm" }, AbiData { abi: Abi::System { unwind: false }, name: "system" }, AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, @@ -149,6 +147,9 @@ pub fn lookup(name: &str) -> Result { "riscv-interrupt-u" => AbiUnsupported::Reason { explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314", }, + "wasm" => AbiUnsupported::Reason { + explain: "non-standard wasm ABI is no longer supported", + }, _ => AbiUnsupported::Unrecognized, @@ -241,10 +242,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_c_cmse_nonsecure_call, explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", }), - "wasm" => Err(AbiDisabled::Unstable { - feature: sym::wasm_abi, - explain: "wasm ABI is experimental and subject to change", - }), _ => Err(AbiDisabled::Unrecognized), } } @@ -287,16 +284,15 @@ impl Abi { AvrInterrupt => 23, AvrNonBlockingInterrupt => 24, CCmseNonSecureCall => 25, - Wasm => 26, // Cross-platform ABIs - System { unwind: false } => 27, - System { unwind: true } => 28, - RustIntrinsic => 29, - RustCall => 30, - Unadjusted => 31, - RustCold => 32, - RiscvInterruptM => 33, - RiscvInterruptS => 34, + System { unwind: false } => 26, + System { unwind: true } => 27, + RustIntrinsic => 28, + RustCall => 29, + Unadjusted => 30, + RustCold => 31, + RiscvInterruptM => 32, + RiscvInterruptS => 33, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 81ada30a5943..607eeac7ccdc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2608,22 +2608,8 @@ impl DerefMut for Target { impl Target { /// Given a function ABI, turn it into the correct ABI for this target. - pub fn adjust_abi(&self, cx: &C, abi: Abi, c_variadic: bool) -> Abi - where - C: HasWasmCAbiOpt, - { + pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi { match abi { - Abi::C { .. } => { - if self.arch == "wasm32" - && self.os == "unknown" - && cx.wasm_c_abi_opt() == WasmCAbi::Legacy - { - Abi::Wasm - } else { - abi - } - } - // On Windows, `extern "system"` behaves like msvc's `__stdcall`. // `__stdcall` only applies on x86 and on non-variadic functions: // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 @@ -2676,7 +2662,6 @@ impl Target { Msp430Interrupt => self.arch == "msp430", RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]), AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", - Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]), Thiscall { .. } => self.arch == "x86", // On windows these fall-back to platform native calling convention (C) when the // architecture is not supported. diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 4e2964174f92..f37781c3f638 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 macOS (11.0+, Big Sur+)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 20655689772d..11a39c26e9d2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 iOS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 4c008f7985e6..85c40ec60c41 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: mac_catalyst_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple Catalyst on ARM64".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 4a63abdf5419..703b886cc19e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple iOS Simulator on ARM64".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 3310e6c9e8a4..e97ad11cdf6c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 tvOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index b901c663afae..8bfa9c8e8b7e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 tvOS Simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index a00a97a133f6..6d66299d6d9e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-apple-watchos".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Apple WatchOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index e2f80b7b7a88..9675a950d5d0 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: watchos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Apple WatchOS Simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs index 88115b81fa5b..df389fe34bd6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (big-endian)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs index b89c2841dae7..10a8e3e4df81 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-linux-gnu_ilp32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (big-endian, ILP32 ABI)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs index d9164f8b052e..ba646cd6065f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64_be-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 NetBSD (big-endian)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs index 168f6ad1ac2b..1c2273bb3a1f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 SOLID with TOPPERS/ASP3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs index e9fa482bff10..3f0072c00c14 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs index 7e7e202b1121..1ba4fbb3d256 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Nintendo Switch, Horizon".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index 2cc417ea8309..070460538c7a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index a5e7dda5fb8a..f4e2ee448057 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Windows MSVC".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs index 81c9d5927fa2..b10f1c7592e5 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs index d740f0b7c97a..f84853fbb19c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Fuchsia".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs index a466fa055164..55cb0b8f2ee7 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "aarch64".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs index 6f253c2a2239..7f05358e0161 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "aarch64-unknown-solaris2.11".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 illumos".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs index 0c4bac0e1295..1a45c2c5c05e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (kernel 4.1, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs index e202ce2f57f6..851366b7647b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu_ilp32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux (ILP32 ABI)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs index 4a82423bb636..6b4a422a474a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index 3d357bcf3f23..5924e4f57579 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "aarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs index ac26aa822716..0069d5431f8e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 NetBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index 21706aa0b5d8..169468f2e248 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -32,10 +32,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARM64, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index 4f04a7816ce8..222d5651b521 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -26,10 +26,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARM64, softfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs index 8e448a2fa9a7..0e5a0b9b9a54 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 QNX Neutrino 7.1 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, // from: https://llvm.org/docs/LangRef.html#data-layout diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs index b51cddafb1aa..e16991af4e66 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs index 544709cffe67..e59b38a3e411 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-redox".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 RedoxOS".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs index 285c5e79cf05..5ae2d68332c6 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 TEEOS".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs index de4a56ae03da..429303170b6b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-windows".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64 UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs index 50064e673b3d..df1b75272b1f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs @@ -9,9 +9,9 @@ pub fn target() -> Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs index 026b30e9eb78..41f7532ecdb1 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs @@ -5,9 +5,9 @@ pub fn target() -> Target { llvm_target: "aarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 3ca8c9969c2d..2c76f4736de8 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: watchos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm Apple WatchOS 64-bit with 32-bit pointers".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 90be518638e9..6f28f5d05436 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64e Apple Darwin".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 56470d29eae0..1590ae9679d8 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("ARM64e Apple iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs index aedfb8810246..21cb38868fb9 100644 --- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "arm64ec-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm64EC Windows MSVC".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs index 12c6388a97b6..a22bcef47575 100644 --- a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-linux-androideabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs index 8abf7dd53234..8ff272e786db 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index 922f51fd60d0..e3e2f4cd05c2 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs index 3c01c86c7d54..f958b89358b1 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "arm-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs index 5be5bb03979b..98093fdc0032 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs index f95ec8c78dd8..b56f311793ad 100644 --- a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armeb-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm BE8 the default Arm big-endian architecture since Armv6".into()), + tier: Some(3), + host_tools: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index d5ee10dbfc4c..df32b74f6d9a 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-R, Big Endian".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index 2f86506e2d05..063038c80122 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-R, Big Endian, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs index 42d165a6ca48..f873fb0d3495 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv4T".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs index d12bc241d067..18f327bc87f7 100644 --- a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv4T Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs index 512a175f2c97..1fbe4b89ea17 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv5TE".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs index 6b31d0ee25fa..123686448378 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs index ea14a2ec2521..ccbc1e36ddec 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv5te-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs index e2ab803576a9..d88b88333b56 100644 --- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-uclibcgnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv5TE Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs index 04f351788283..24e9d1e03949 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-freebsd-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs index ca4d42ebbe87..62e328b9cbda 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-netbsdelf-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6 NetBSD w/hard-float".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs index 9a88277b0636..bcdad0a55b31 100644 --- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "armv6k-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs index e798ef473543..8f6a58a1b498 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 0730a423f724..a9b5172385ba 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -14,10 +14,12 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-vita-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)".into(), + ), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index 017b126129c1..3a16bbe95db3 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-freebsd-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A FreeBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs index 2be263d6d9c1..8a4ba271456a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux (kernel 4.15, glibc 2.27)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index 8a80a623b1d2..a217a2daeb39 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs index ad4ebed74e7e..96459a5137fd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs index ba7b62bc5eb4..6c878141fd49 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs index 489aad7845d9..bffc51d9b7bc 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs index fdf46101d257..9dc1221287dd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with uClibc, softfloat".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs index 36bc9548209e..01a1468d3a8c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Linux with uClibc, hardfloat".into()), + tier: Some(3), + host_tools: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index 2dc4d9b835b2..a2391503ff8a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-netbsdelf-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A NetBSD w/hard-float".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs index 89469f01c3a2..7d60ec1b64dd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A for VxWorks".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs index ffdeba50df27..76d4653931b8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm SOLID with TOPPERS/ASP3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index cbcf223daf6d..d2b4d46adac6 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Arm SOLID with TOPPERS/ASP3, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs index 3373e677c4ac..b544c404f3f2 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs @@ -33,10 +33,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-A".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index 12844a8e5824..aebb7e667bcd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -25,10 +25,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv7-A, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 5c675c22ef51..e876c567b09a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7k-apple-watchos".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Apple WatchOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs index d5213234339c..b3246dc79281 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-R".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs index 7c39d2d38de8..9ac500d7ffe7 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-R, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index 4dd475e3a82d..11608794932b 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: ios_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Apple-A6 Apple iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs index 17fdd496302c..ee940c3a76a2 100644 --- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "armv8r-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Armv8-R, hardfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs index 470674372fdd..8cddb6fe005c 100644 --- a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "bpfeb".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("BPF (big endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs index 3e3202df17e0..d070aa0ec44b 100644 --- a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "bpfel".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("BPF (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs index 120c75f528ad..e8a0b465e156 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs @@ -6,7 +6,12 @@ pub fn target() -> Target { Target { //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h llvm_target: "csky-unknown-linux-gnuabiv2".into(), - metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None }, + metadata: crate::spec::TargetMetadata { + description: Some("C-SKY abiv2 Linux (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true) + }, pointer_width: 32, data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: "csky".into(), diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs index 2856e94ea4a9..99330ddc3189 100644 --- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs +++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs @@ -6,7 +6,12 @@ pub fn target() -> Target { Target { //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h llvm_target: "csky-unknown-linux-gnuabiv2".into(), - metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None }, + metadata: crate::spec::TargetMetadata { + description: Some("C-SKY abiv2 Linux, hardfloat (little endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true) + }, pointer_width: 32, data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(), arch: "csky".into(), diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index 003d35ebeb45..bd5397990296 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Hexagon Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: concat!( diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs index 8750e0ee85f1..cefd0bf6d67b 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare Hexagon (v60+, HVX)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: concat!( diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index c03a0974bc1c..b1b2b6cdffa8 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // MACH-O commands, so we do too. llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 iOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 290ed81ad45d..6c80ab6994dd 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "i586-pc-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs index 73949c7bdc4c..de42549b7f8d 100644 --- a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "i586-unknown-netbsdelf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86, resricted to Pentium".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index aea6a1ac4ece..02f6bec4692f 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { // While ld64 doesn't understand i686, LLVM does. llvm_target: macos_llvm_target(Arch::I686).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit macOS (10.12+, Sierra+)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index 585aad10c57c..fc313e575be6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index 66e09416dde9..4b0f4bf3ecd2 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MinGW (Windows 10+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs index 7a2d28aec9c0..5bb082014298 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit x86 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs index 5826906e9d8e..cce21fcacb1c 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit FreeBSD".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs index 5f66911b39a1..84ef00f06c81 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-haiku".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Haiku".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index a67105f24ca2..ad8c0f7f582e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-hurd-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit GNU/Hurd".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs index 1d4916cabfdf..5584435a0ad9 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Linux (kernel 3.2, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs index c3b9b71802b1..d1ab1f73b511 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs @@ -24,10 +24,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs index 87eba1fb856f..255148fca9a3 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-netbsdelf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/i386 with SSE2".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs index 0436f39f5b11..d6df801234c6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs index 8665a7ca61a3..b92fc2e759a3 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs @@ -79,10 +79,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs index 77dcd645728f..851bea80fb83 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs @@ -18,9 +18,9 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs index b38302262670..28bd2aae8e71 100644 --- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs @@ -9,9 +9,9 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index ae1a44e44a85..cd488d0532c2 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -22,10 +22,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit Windows 7 support".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs index e4d0b674cc4c..973c75eeca6e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "i686-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 3e88180012e5..6f0bb449c16c 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index c45bc4383500..19b04607f0e0 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 69533e82c3ce..744ffff721fe 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index bc4c5bcde5ed..a382e7a53fbd 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs index abd07ef9bdc7..7cff0efd112c 100644 --- a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "m68k-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Motorola 680x0 Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index 9df7b2b670f5..c3235bf994fa 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 for OpenWrt Linux musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index e9de4a5c2607..cdf4ffb7f9eb 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips64-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index 48443717b196..463f7dc47f72 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index 515473fbabc5..ad77a02c0630 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mips64el-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index e6b998746e6a..83f5c7ea37d6 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs index 3616ea603044..0bdfd6ee6b09 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs index b47bc0d30058..8e27c9936c56 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs index 117d74f2d25e..852e1d9376d0 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-uclibc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs index fafe14935383..9d3f4d9f7950 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psp".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Sony PlatStation Portable (PSP)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs index 9f37b0edc176..c0b99a68b0d0 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psx".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Sony PlayStation 1 (PSX)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs index e65480e355b7..8fe4548a3ad9 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (little endian) Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs index ed98f53a2b29..43914a233080 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (little endian) Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs index dc6807509cb9..6150654c0817 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-uclibc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("MIPS (LE) Linux with uClibc".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs index 8e5cd30a54f2..03501aa76a83 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS (LE), requires mips32 cpu support".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs index b5948b4d35c4..81aac3ce0b87 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs @@ -8,10 +8,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare MIPS (LE) softfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs index dbb143b73192..2ed520e9f48f 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS Release 6 Big Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs index f5fff6bec1c2..de30c5b35b75 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6el-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MIPS Release 6 Little Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index ed236cca1bb5..4178a991e14f 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MIPS Release 6 Big Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index bbdc5b95ad18..8e50373bd124 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MIPS Release 6 Little Endian".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs index 2b022a4a5584..de476741defd 100644 --- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "msp430-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("16-bit MSP430 microcontrollers".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 16, data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".into(), diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 0b0b31b503b8..15156fbcfc9e 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { data_layout: "e-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(), llvm_target: "nvptx64-nvidia-cuda".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index 481df71c1a65..bda43e7a2b0f 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-ibm-aix".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit AIX (7.2 and newer)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index b1b981823b89..6eb5bba0fcd9 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64 FreeBSD (ELFv1 and ELFv2)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index ac10630d9440..53b84479a491 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 663f06cf0c67..0d0484dd1748 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit PowerPC Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index 5611352c951c..2922c921e17d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/powerpc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 22b45042aa66..dd2ec2742076 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -12,9 +12,9 @@ pub fn target() -> Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 812b5928966f..ea295cf169e0 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64LE FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index e3c4b3b585c2..dc70bd238a74 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PPC64LE Linux (kernel 3.10, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index 497a40ade81e..dbfbd69b95b1 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs index 194bb0566f18..2f7acccfae83 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-freebsd13.0".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs index b88b2fbf8094..2ecafbb08bc3 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs index b09c4cd21e04..04b2309fdc88 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC SPE Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs index 67b19e904891..108e468eb66b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("PowerPC Linux with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs index c592cd3f6fd2..3ee6cd46c853 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD 32-bit powerpc systems".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs index a17f437e0648..f00ee9604137 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs index 91925ce151df..5d107d6e60ec 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs index 7640feb28e3c..aea525a69123 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index 7e607574241a..e425d6a3f3fc 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index a46b1bb6588e..409b6b22f1cf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -6,10 +6,12 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches".into(), + ), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs index 87eebbe87087..631a31edeb5e 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32I ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs index 186f8105df5b..726778aca0d8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs index 962fcd0eb996..5fa3858e8574 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs index 9acf6a3b5a0e..2022873d05cb 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMA ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs index 1e1356910d92..386e3a38f975 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs index 705bc17892aa..7ced37e15357 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMAC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs index 80b6e6077b22..cd50a9e60c32 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Xous (RV32IMAC ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs index 6c660793777d..3661e38e7b1b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs index f4a0cd1c51ef..954660908912 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMAFC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs index cee6fd32dd64..d52dc8f96ca2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V ESP-IDF".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs index 5378c132df10..ff9931978466 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), llvm_target: "riscv32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV32IMC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 27629199ea55..2dfaf8a2033c 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V 64-bit Android".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs index 37c360e6761d..1fd6a4b38dcf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V FreeBSD".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs index a600ee765668..5c3f525966ed 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Fuchsia".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs index 63c06a97223d..f11128cfcb67 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "riscv64".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index 199ffc1c139a..308c995297bb 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 4.20, glibc 2.29)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index f8b5ceee8b4f..3e575fdd528d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V Linux (kernel 4.20, musl 1.2.3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs index 9dbe01f45987..65781f5af5c7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("RISC-V NetBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs index 9f128d07a99f..a75f8969a739 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV64IMAFDC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, llvm_target: "riscv64".into(), pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs index 29919a16078a..5bdbda773b1b 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/riscv64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs index 1ab6aebcea94..ba9a10e66331 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), llvm_target: "riscv64".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare RISC-V (RV64IMAC ISA)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, arch: "riscv64".into(), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index be68c5b1c886..b0dd0eb612e1 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -19,10 +19,10 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("S390x Linux (kernel 3.2, glibc 2.17)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index 619e83ce620b..3976233819ce 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -20,10 +20,10 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("S390x Linux (kernel 3.2, musl 1.2.3)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs index 77c9b4f996aa..eeb7eebfe503 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("SPARC Linux (kernel 4.4, glibc 2.23)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs index 42944367cf66..69bb6e1fb60e 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/sparc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs index f0bf55d33e68..08f6eaf83617 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("OpenBSD/sparc64".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs index 5cee06e4936c..8b7ff5d8011c 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs @@ -5,10 +5,10 @@ pub fn target() -> Target { Target { llvm_target: "sparc-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit SPARC Linux".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs index cfe8f65d7941..c977fe608a78 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs @@ -21,10 +21,10 @@ pub fn target() -> Target { data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), llvm_target: "sparc-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare 32-bit SPARC V7+".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "sparc".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs index a42243f59dc4..1c0adadece0b 100644 --- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "sparcv9-sun-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("SPARC Solaris 11, illumos".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i64:64-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs index 9f222522505a..96dd8588d4f6 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv4t-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb-mode Bare ARMv4T".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs index 67e57c5fc352..d92e68cebaa6 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv5te-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb-mode Bare ARMv5TE".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, arch: "arm".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs index cac415128b68..a0fa58d8175c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv6m-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv6-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs index 13e1e349b040..e36aa5ab395d 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs @@ -15,9 +15,9 @@ pub fn target() -> Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs index e3e2ea635944..2e68dd0ec4e8 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs @@ -5,9 +5,9 @@ pub fn target() -> Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs index ec73cf40a713..bd2df9236f67 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7E-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index bff812a5d5c7..e2499ef54112 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7E-M, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs index 0104cdcc9a24..17e37f800f0b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7m-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv7-M".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs index d50e63b92175..c562f57252e5 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb2-mode ARMv7-A Android with NEON".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs index d630ca214e5d..b5e91d61308b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs @@ -10,10 +10,12 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some( + "Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)".into(), + ), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs index 74d5450c787e..71d5eb43c104 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Thumb2-mode ARMv7-A Linux with NEON, musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs index 2f385208f36a..e18bf113fe7c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.base-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Baseline".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs index 29a0803ba07e..5c2f1e093819 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Mainline".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index 88796e7a756b..799ac45b479c 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -7,10 +7,10 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Bare ARMv8-M Mainline, hardfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index 195ff46cf9d2..46257a272d1e 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -25,10 +25,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-emscripten".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly via Emscripten".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs index 23f4772c39cb..bf92f30e8b37 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs @@ -37,10 +37,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs index 4c2d222b590e..a8e7f22c0689 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs @@ -51,10 +51,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasi".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly with WASI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 38af48ab2665..4e60806f3a73 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -63,9 +63,9 @@ pub fn target() -> Target { llvm_target: "wasm32-wasi".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs index 1259969ac365..63d1f4869be4 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs @@ -62,10 +62,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasip2".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs index 8edde36dac62..bc49a3c9f70d 100644 --- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs @@ -40,10 +40,10 @@ pub fn target() -> Target { Target { llvm_target: "wasm64-unknown-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("WebAssembly".into()), + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 21acd750df2d..94638ae62f83 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit macOS (10.12+, Sierra+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index ec61b7967646..3cabca033609 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: ios_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 iOS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index bd967ee972b3..d3ba17cf0271 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: mac_catalyst_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Apple Catalyst on x86_64".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 55b2e1afcd39..2a3125157dd9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -9,10 +9,10 @@ pub fn target() -> Target { Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit tvOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index a783eff15b26..62e60b5e32d0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -6,10 +6,10 @@ pub fn target() -> Target { Target { llvm_target: watchos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit Apple WatchOS simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs index 012450e307e7..5a72fad82632 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs @@ -75,10 +75,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Fortanix ABI for 64-bit Intel SGX".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs index 92711bbe246b..257093b75545 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs @@ -16,10 +16,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-linux-android".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 Android".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs index c7169c3d62d5..f6d22ff32049 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-unknown".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86 64-bit QNX Neutrino 7.1 RTOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index 4dbe049a4b78..697daf590ad0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Solaris 11, illumos".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs index de0f17246c3d..89a9bb1e1cc5 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs @@ -17,10 +17,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit MinGW (Windows 10+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs index b485970bb416..acf0fd421bac 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 MinGW (Windows 10+), LLVM ABI".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs index 8752ba81066e..883da26d786e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Unikraft with musl 1.2.3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "x86_64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs index aef95e373cbf..171a6f2a51e7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-dragonfly".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit DragonFlyBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs index 15146a5ef729..4692b5a3c74e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-freebsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit FreeBSD".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index 80cdeab0a677..5ebf1804302b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-fuchsia".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit x86 Fuchsia".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs index 9f62eb1fa270..b593b79e7bbd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-haiku".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Haiku".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs index 745a658ed00d..3e81ff9a4ec4 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86_64 Hermit".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, arch: "x86_64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs index c52cdf466abe..d683a4420274 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs @@ -13,10 +13,10 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "x86_64-pc-solaris".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("illumos".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs index 6b170c22c9e1..adf489ad7b1d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-l4re-uclibc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index bd12d4d8af0e..4a92d4ef9d5c 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -28,10 +28,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs index f6e0b051e8f5..3c7db0095a14 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs @@ -15,10 +15,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnux32".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs index 66237f071028..109fc3c0728d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Linux with musl 1.2.3".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs index db8db1d25382..c1d888899fc2 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. llvm_target: "x86_64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("x86_64 OpenHarmony".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs index 38ae3a4fe424..d413caf4aaf7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs @@ -19,10 +19,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-netbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("NetBSD/amd64".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 5846dc16d66b..549706998d46 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -18,9 +18,7 @@ pub fn target() -> Target { relro_level: RelroLevel::Full, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - features: - "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" - .into(), + features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(), supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, disable_redzone: true, panic_strategy: PanicStrategy::Abort, @@ -30,10 +28,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Freestanding/bare-metal x86_64 softfloat".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs index 4d7eba242139..8f1c3ef9bc7b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs @@ -12,10 +12,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-openbsd".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit OpenBSD".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs index 99f5d9dc41d2..ae38f63f034f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-redox".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Redox OS".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index 0c6e4b2b1ff5..6da1fcca58c8 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -32,10 +32,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-windows".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit UEFI".into()), + tier: Some(2), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs index aef6fd1a7814..c71bc9ed9231 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs @@ -17,9 +17,9 @@ pub fn target() -> Target { llvm_target: "x86_64-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs index 963ccdbfcd06..178baeca6857 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { llvm_target: "x86_64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 9b458614f2b8..d44ae9fc4e0a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -10,10 +10,10 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-win7-windows-msvc".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit Windows 7 support".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs index b956d228c17f..7b40f7366d0f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs @@ -13,9 +13,9 @@ pub fn target() -> Target { llvm_target: "x86_64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: None, // ? }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index fe6cbca32c74..72cbc1be9310 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -35,10 +35,10 @@ pub fn target() -> Target { // correctly, we do too. llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("macOS with late-gen Intel (at least Haswell)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 017fd3072fdb..6667efb14e2d 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -192,6 +192,11 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-start ("adx", Stable), ("aes", Stable), + ("amx-bf16", Unstable(sym::x86_amx_intrinsics)), + ("amx-complex", Unstable(sym::x86_amx_intrinsics)), + ("amx-fp16", Unstable(sym::x86_amx_intrinsics)), + ("amx-int8", Unstable(sym::x86_amx_intrinsics)), + ("amx-tile", Unstable(sym::x86_amx_intrinsics)), ("avx", Stable), ("avx2", Stable), ("avx512bf16", Unstable(sym::avx512_target_feature)), @@ -241,6 +246,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("tbm", Unstable(sym::tbm_target_feature)), ("vaes", Unstable(sym::avx512_target_feature)), ("vpclmulqdq", Unstable(sym::avx512_target_feature)), + ("xop", Unstable(sym::xop_target_feature)), ("xsave", Stable), ("xsavec", Stable), ("xsaveopt", Stable), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index f7ec5f1ff325..2e6247b46401 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1776,6 +1776,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true }; + // we filter before checking if `impl_candidates` is empty + // to get the fallback solution if we filtered out any impls + let impl_candidates = impl_candidates + .into_iter() + .cloned() + .filter(|cand| { + !self.tcx.has_attrs_with_path( + cand.impl_def_id, + &[sym::diagnostic, sym::do_not_recommend], + ) + }) + .collect::>(); + let def_id = trait_ref.def_id(); if impl_candidates.is_empty() { if self.tcx.trait_is_auto(def_id) @@ -1788,6 +1801,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut impl_candidates: Vec<_> = self .tcx .all_impls(def_id) + // ignore `do_not_recommend` items + .filter(|def_id| { + !self + .tcx + .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend]) + }) // Ignore automatically derived impls and `!Trait` impls. .filter_map(|def_id| self.tcx.impl_trait_header(def_id)) .filter_map(|header| { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2cf808f962f0..f8843b892db3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(where_pred) = where_pred.as_trait_clause() && let Some(failed_pred) = failed_pred.as_trait_clause() + && where_pred.def_id() == failed_pred.def_id() { self.enter_forall(where_pred, |where_pred| { let failed_pred = self.instantiate_binder_with_fresh_vars( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 703ff2f7f169..d28982ed8492 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -271,13 +271,14 @@ fn do_normalize_predicates<'tcx>( // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. let infcx = tcx.infer_ctxt().ignoring_regions().build(); - let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { - Ok(predicates) => predicates, - Err(errors) => { - let reported = infcx.err_ctxt().report_fulfillment_errors(errors); - return Err(reported); - } - }; + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + let predicates = ocx.normalize(&cause, elaborated_env, predicates); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); + } debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); @@ -465,37 +466,6 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } -/// Normalize a type and process all resulting obligations, returning any errors. -/// -/// FIXME(-Znext-solver): This should be replaced by `At::deeply_normalize` -/// which has the same behavior with the new solver. Because using a separate -/// fulfillment context worsens caching in the old solver, `At::deeply_normalize` -/// is still lazy with the old solver as it otherwise negatively impacts perf. -#[instrument(skip_all)] -pub fn fully_normalize<'tcx, T>( - infcx: &InferCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: T, -) -> Result>> -where - T: TypeFoldable>, -{ - let ocx = ObligationCtxt::new_with_diagnostics(infcx); - debug!(?value); - let normalized_value = ocx.normalize(&cause, param_env, value); - debug!(?normalized_value); - debug!("select_all_or_error start"); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - return Err(errors); - } - debug!("select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(normalized_value); - debug!(?resolved_value); - Ok(resolved_value) -} - /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 3a7481acbafd..01ba8c02ea6e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -42,11 +42,9 @@ impl<'tcx> At<'_, 'tcx> { /// same goals in both a temporary and the shared context which negatively impacts /// performance as these don't share caching. /// - /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize` - /// in the new solver, but because of performance reasons, we currently reuse an - /// existing fulfillment context in the old solver. Once we also eagerly prove goals with - /// the old solver or have removed the old solver, remove `traits::fully_normalize` and - /// rename this function to `At::fully_normalize`. + /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing + /// fulfillment context in the old solver. Once we have removed the old solver, we + /// can remove the `fulfill_cx` parameter on this function. fn deeply_normalize( self, value: T, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 6a904ef487ea..3c33d13567d7 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -18,9 +18,7 @@ use crate::error_reporting::traits::to_pretty_impl_header; use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{ - self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, -}; +use crate::traits::{coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -219,19 +217,17 @@ fn fulfill_implication<'tcx>( param_env, source_trait_ref, target_impl ); - let source_trait_ref = - match traits::fully_normalize(infcx, ObligationCause::dummy(), param_env, source_trait_ref) - { - Ok(source_trait_ref) => source_trait_ref, - Err(_errors) => { - infcx.dcx().span_delayed_bug( - infcx.tcx.def_span(source_impl), - format!("failed to fully normalize {source_trait_ref}"), - ); - source_trait_ref - } - }; + let ocx = ObligationCtxt::new(infcx); + let source_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, source_trait_ref); + if !ocx.select_all_or_error().is_empty() { + infcx.dcx().span_delayed_bug( + infcx.tcx.def_span(source_impl), + format!("failed to fully normalize {source_trait_ref}"), + ); + } + + let source_trait_ref = infcx.resolve_vars_if_possible(source_trait_ref); let source_trait = ImplSubject::Trait(source_trait_ref); let selcx = SelectionContext::new(infcx); @@ -253,9 +249,6 @@ fn fulfill_implication<'tcx>( return Err(()); }; - // Needs to be `in_snapshot` because this function is used to rebase - // generic parameters, which may happen inside of a select within a probe. - let ocx = ObligationCtxt::new(infcx); // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) ocx.register_obligations(obligations.chain(more_obligations)); diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f078cfe1b250..1dced9cf7cd2 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -324,7 +324,7 @@ fn fn_sig_for_fn_abi<'tcx>( #[inline] fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { use rustc_target::spec::abi::Abi::*; - match tcx.sess.target.adjust_abi(&tcx, abi, c_variadic) { + match tcx.sess.target.adjust_abi(abi, c_variadic) { RustIntrinsic | Rust | RustCall => Conv::Rust, // This is intentionally not using `Conv::Cold`, as that has to preserve @@ -352,7 +352,6 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }, RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }, - Wasm => Conv::C, // These API constants ought to be more specific... Cdecl { .. } => Conv::C, @@ -744,6 +743,40 @@ fn fn_abi_adjust_for_abi<'tcx>( return; } + // Avoid returning floats in x87 registers on x86 as loading and storing from x87 + // registers will quiet signalling NaNs. + if cx.tcx.sess.target.arch == "x86" + && arg_idx.is_none() + // Intrinsics themselves are not actual "real" functions, so theres no need to + // change their ABIs. + && abi != SpecAbi::RustIntrinsic + { + match arg.layout.abi { + // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled + // below, by returning arguments up to the size of a pointer (32 bits on x86) + // cast to an appropriately sized integer. + Abi::Scalar(s) if s.primitive() == Float(F32) => { + // Same size as a pointer, return in a register. + arg.cast_to(Reg::i32()); + return; + } + Abi::Scalar(s) if s.primitive() == Float(F64) => { + // Larger than a pointer, return indirectly. + arg.make_indirect(); + return; + } + Abi::ScalarPair(s1, s2) + if matches!(s1.primitive(), Float(F32 | F64)) + || matches!(s2.primitive(), Float(F32 | F64)) => + { + // Larger than a pointer, return indirectly. + arg.make_indirect(); + return; + } + _ => {} + }; + } + match arg.layout.abi { Abi::Aggregate { .. } => {} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index de86a8536f7a..f05d626b4703 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,11 +8,10 @@ use std::hash::Hash; use rustc_ast_ir::Mutability; -use crate::data_structures::HashSet; use crate::elaborate::Elaboratable; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; -use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; +use crate::solve::Reveal; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; @@ -539,33 +538,6 @@ pub trait Features: Copy { fn associated_const_equality(self) -> bool; } -pub trait EvaluationCache { - /// Insert a final result into the global cache. - fn insert( - &self, - tcx: I, - key: CanonicalInput, - proof_tree: Option, - additional_depth: usize, - encountered_overflow: bool, - cycle_participants: HashSet>, - dep_node: I::DepNodeIndex, - result: QueryResult, - ); - - /// Try to fetch a cached result, checking the recursion limit - /// and handling root goals of coinductive cycles. - /// - /// If this returns `Some` the cache result can be used. - fn get( - &self, - tcx: I, - key: CanonicalInput, - stack_entries: impl IntoIterator>, - available_depth: usize, - ) -> Option>; -} - pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { fn is_local(self) -> bool; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index fdd1553d389d..14ebbb12fe2f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -10,8 +10,11 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; +use crate::search_graph; use crate::solve::inspect::CanonicalGoalEvaluationStep; -use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode}; +use crate::solve::{ + CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, +}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty}; @@ -86,6 +89,13 @@ pub trait Interner: ) -> Self::ExternalConstraints; type DepNodeIndex; + type Tracked: Debug; + fn mk_tracked( + self, + data: T, + dep_node: Self::DepNodeIndex, + ) -> Self::Tracked; + fn get_tracked(self, tracked: &Self::Tracked) -> T; fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); // Kinds of tys @@ -125,8 +135,11 @@ pub trait Interner: type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - type EvaluationCache: EvaluationCache; - fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache; + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R; fn expand_abstract_consts>(self, t: T) -> T; @@ -373,3 +386,32 @@ impl CollectAndApply for Result { }) } } + +impl search_graph::Cx for I { + type ProofTree = Option; + type Input = CanonicalInput; + type Result = QueryResult; + + type DepNodeIndex = I::DepNodeIndex; + type Tracked = I::Tracked; + fn mk_tracked( + self, + data: T, + dep_node_index: I::DepNodeIndex, + ) -> I::Tracked { + I::mk_tracked(self, data, dep_node_index) + } + fn get_tracked(self, tracked: &I::Tracked) -> T { + I::get_tracked(self, tracked) + } + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) { + I::with_cached_task(self, task) + } + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut search_graph::GlobalCache) -> R, + ) -> R { + I::with_global_cache(self, mode, f) + } +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index b14a65fc7795..37ee66fa222a 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -30,6 +30,7 @@ pub mod lang_items; pub mod lift; pub mod outlives; pub mod relate; +pub mod search_graph; pub mod solve; // These modules are not `pub` since they are glob-imported. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs new file mode 100644 index 000000000000..5ccda931f9c5 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -0,0 +1,118 @@ +use rustc_index::IndexVec; + +use super::{AvailableDepth, Cx, StackDepth, StackEntry}; +use crate::data_structures::{HashMap, HashSet}; + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] +struct QueryData { + result: X::Result, + proof_tree: X::ProofTree, +} + +struct Success { + data: X::Tracked>, + additional_depth: usize, +} + +/// The cache entry for a given input. +/// +/// This contains results whose computation never hit the +/// recursion limit in `success`, and all results which hit +/// the recursion limit in `with_overflow`. +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +struct CacheEntry { + success: Option>, + /// We have to be careful when caching roots of cycles. + /// + /// See the doc comment of `StackEntry::cycle_participants` for more + /// details. + nested_goals: HashSet, + with_overflow: HashMap>>, +} + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +pub(super) struct CacheData<'a, X: Cx> { + pub(super) result: X::Result, + pub(super) proof_tree: X::ProofTree, + pub(super) additional_depth: usize, + pub(super) encountered_overflow: bool, + // FIXME: This is currently unused, but impacts the design + // by requiring a closure for `Cx::with_global_cache`. + pub(super) nested_goals: &'a HashSet, +} + +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +pub struct GlobalCache { + map: HashMap>, +} + +impl GlobalCache { + /// Insert a final result into the global cache. + pub(super) fn insert( + &mut self, + cx: X, + input: X::Input, + + result: X::Result, + proof_tree: X::ProofTree, + dep_node: X::DepNodeIndex, + + additional_depth: usize, + encountered_overflow: bool, + nested_goals: &HashSet, + ) { + let data = cx.mk_tracked(QueryData { result, proof_tree }, dep_node); + let entry = self.map.entry(input).or_default(); + entry.nested_goals.extend(nested_goals); + if encountered_overflow { + entry.with_overflow.insert(additional_depth, data); + } else { + entry.success = Some(Success { data, additional_depth }); + } + } + + /// Try to fetch a cached result, checking the recursion limit + /// and handling root goals of coinductive cycles. + /// + /// If this returns `Some` the cache result can be used. + pub(super) fn get<'a>( + &'a self, + cx: X, + input: X::Input, + stack: &IndexVec>, + available_depth: AvailableDepth, + ) -> Option> { + let entry = self.map.get(&input)?; + if stack.iter().any(|e| entry.nested_goals.contains(&e.input)) { + return None; + } + + if let Some(ref success) = entry.success { + if available_depth.cache_entry_is_applicable(success.additional_depth) { + let QueryData { result, proof_tree } = cx.get_tracked(&success.data); + return Some(CacheData { + result, + proof_tree, + additional_depth: success.additional_depth, + encountered_overflow: false, + nested_goals: &entry.nested_goals, + }); + } + } + + entry.with_overflow.get(&available_depth.0).map(|e| { + let QueryData { result, proof_tree } = cx.get_tracked(e); + CacheData { + result, + proof_tree, + additional_depth: available_depth.0, + encountered_overflow: true, + nested_goals: &entry.nested_goals, + } + }) + } +} diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs new file mode 100644 index 000000000000..c2204becdfd7 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -0,0 +1,605 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::marker::PhantomData; +use std::mem; + +use rustc_index::{Idx, IndexVec}; +use tracing::debug; + +use crate::data_structures::{HashMap, HashSet}; +use crate::solve::SolverMode; + +mod global_cache; +use global_cache::CacheData; +pub use global_cache::GlobalCache; +mod validate; + +/// The search graph does not simply use `Interner` directly +/// to enable its fuzzing without having to stub the rest of +/// the interner. We don't make this a super trait of `Interner` +/// as users of the shared type library shouldn't have to care +/// about `Input` and `Result` as they are implementation details +/// of the search graph. +pub trait Cx: Copy { + type ProofTree: Debug + Copy; + type Input: Debug + Eq + Hash + Copy; + type Result: Debug + Eq + Hash + Copy; + + type DepNodeIndex; + type Tracked: Debug; + fn mk_tracked( + self, + data: T, + dep_node_index: Self::DepNodeIndex, + ) -> Self::Tracked; + fn get_tracked(self, tracked: &Self::Tracked) -> T; + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); + + fn with_global_cache( + self, + mode: SolverMode, + f: impl FnOnce(&mut GlobalCache) -> R, + ) -> R; +} + +pub trait ProofTreeBuilder { + fn try_apply_proof_tree(&mut self, proof_tree: X::ProofTree) -> bool; + fn on_provisional_cache_hit(&mut self); + fn on_cycle_in_stack(&mut self); + fn finalize_canonical_goal_evaluation(&mut self, cx: X) -> X::ProofTree; +} + +pub trait Delegate { + type Cx: Cx; + const FIXPOINT_STEP_LIMIT: usize; + type ProofTreeBuilder: ProofTreeBuilder; + + fn recursion_limit(cx: Self::Cx) -> usize; + + fn initial_provisional_result( + cx: Self::Cx, + kind: CycleKind, + input: ::Input, + ) -> ::Result; + fn reached_fixpoint( + cx: Self::Cx, + kind: UsageKind, + input: ::Input, + provisional_result: Option<::Result>, + result: ::Result, + ) -> bool; + fn on_stack_overflow( + cx: Self::Cx, + inspect: &mut Self::ProofTreeBuilder, + input: ::Input, + ) -> ::Result; + fn on_fixpoint_overflow( + cx: Self::Cx, + input: ::Input, + ) -> ::Result; + + fn step_is_coinductive(cx: Self::Cx, input: ::Input) -> bool; +} + +/// In the initial iteration of a cycle, we do not yet have a provisional +/// result. In the case we return an initial provisional result depending +/// on the kind of cycle. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CycleKind { + Coinductive, + Inductive, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UsageKind { + Single(CycleKind), + Mixed, +} +impl UsageKind { + fn merge(self, other: Self) -> Self { + match (self, other) { + (UsageKind::Single(lhs), UsageKind::Single(rhs)) => { + if lhs == rhs { + UsageKind::Single(lhs) + } else { + UsageKind::Mixed + } + } + (UsageKind::Mixed, UsageKind::Mixed) + | (UsageKind::Mixed, UsageKind::Single(_)) + | (UsageKind::Single(_), UsageKind::Mixed) => UsageKind::Mixed, + } + } +} + +#[derive(Debug, Clone, Copy)] +struct AvailableDepth(usize); +impl AvailableDepth { + /// Returns the remaining depth allowed for nested goals. + /// + /// This is generally simply one less than the current depth. + /// However, if we encountered overflow, we significantly reduce + /// the remaining depth of all nested goals to prevent hangs + /// in case there is exponential blowup. + fn allowed_depth_for_nested( + cx: D::Cx, + stack: &IndexVec>, + ) -> Option { + if let Some(last) = stack.raw.last() { + if last.available_depth.0 == 0 { + return None; + } + + Some(if last.encountered_overflow { + AvailableDepth(last.available_depth.0 / 2) + } else { + AvailableDepth(last.available_depth.0 - 1) + }) + } else { + Some(AvailableDepth(D::recursion_limit(cx))) + } + } + + /// Whether we're allowed to use a global cache entry which required + /// the given depth. + fn cache_entry_is_applicable(self, additional_depth: usize) -> bool { + self.0 >= additional_depth + } +} + +rustc_index::newtype_index! { + #[orderable] + #[gate_rustc_only] + pub struct StackDepth {} +} + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +struct StackEntry { + input: X::Input, + + available_depth: AvailableDepth, + + /// The maximum depth reached by this stack entry, only up-to date + /// for the top of the stack and lazily updated for the rest. + reached_depth: StackDepth, + + /// Whether this entry is a non-root cycle participant. + /// + /// We must not move the result of non-root cycle participants to the + /// global cache. We store the highest stack depth of a head of a cycle + /// this goal is involved in. This necessary to soundly cache its + /// provisional result. + non_root_cycle_participant: Option, + + encountered_overflow: bool, + + has_been_used: Option, + + /// We put only the root goal of a coinductive cycle into the global cache. + /// + /// If we were to use that result when later trying to prove another cycle + /// participant, we can end up with unstable query results. + /// + /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for + /// an example of where this is needed. + /// + /// There can be multiple roots on the same stack, so we need to track + /// cycle participants per root: + /// ```plain + /// A :- B + /// B :- A, C + /// C :- D + /// D :- C + /// ``` + nested_goals: HashSet, + /// Starts out as `None` and gets set when rerunning this + /// goal in case we encounter a cycle. + provisional_result: Option, +} + +/// The provisional result for a goal which is not on the stack. +#[derive(Debug)] +struct DetachedEntry { + /// The head of the smallest non-trivial cycle involving this entry. + /// + /// Given the following rules, when proving `A` the head for + /// the provisional entry of `C` would be `B`. + /// ```plain + /// A :- B + /// B :- C + /// C :- A + B + C + /// ``` + head: StackDepth, + result: X::Result, +} + +/// Stores the stack depth of a currently evaluated goal *and* already +/// computed results for goals which depend on other goals still on the stack. +/// +/// The provisional result may depend on whether the stack above it is inductive +/// or coinductive. Because of this, we store separate provisional results for +/// each case. If an provisional entry is not applicable, it may be the case +/// that we already have provisional result while computing a goal. In this case +/// we prefer the provisional result to potentially avoid fixpoint iterations. +/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example. +/// +/// The provisional cache can theoretically result in changes to the observable behavior, +/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs. +#[derive(derivative::Derivative)] +#[derivative(Default(bound = ""))] +struct ProvisionalCacheEntry { + stack_depth: Option, + with_inductive_stack: Option>, + with_coinductive_stack: Option>, +} + +impl ProvisionalCacheEntry { + fn is_empty(&self) -> bool { + self.stack_depth.is_none() + && self.with_inductive_stack.is_none() + && self.with_coinductive_stack.is_none() + } +} + +pub struct SearchGraph, X: Cx = ::Cx> { + mode: SolverMode, + /// The stack of goals currently being computed. + /// + /// An element is *deeper* in the stack if its index is *lower*. + stack: IndexVec>, + provisional_cache: HashMap>, + + _marker: PhantomData, +} + +impl, X: Cx> SearchGraph { + pub fn new(mode: SolverMode) -> SearchGraph { + Self { + mode, + stack: Default::default(), + provisional_cache: Default::default(), + _marker: PhantomData, + } + } + + pub fn solver_mode(&self) -> SolverMode { + self.mode + } + + fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { + if let Some(parent) = self.stack.raw.last_mut() { + parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.encountered_overflow |= encountered_overflow; + } + } + + pub fn is_empty(&self) -> bool { + self.stack.is_empty() + } + + fn stack_coinductive_from( + cx: X, + stack: &IndexVec>, + head: StackDepth, + ) -> bool { + stack.raw[head.index()..].iter().all(|entry| D::step_is_coinductive(cx, entry.input)) + } + + // When encountering a solver cycle, the result of the current goal + // depends on goals lower on the stack. + // + // We have to therefore be careful when caching goals. Only the final result + // of the cycle root, i.e. the lowest goal on the stack involved in this cycle, + // is moved to the global cache while all others are stored in a provisional cache. + // + // We update both the head of this cycle to rerun its evaluation until + // we reach a fixpoint and all other cycle participants to make sure that + // their result does not get moved to the global cache. + fn tag_cycle_participants( + stack: &mut IndexVec>, + usage_kind: Option, + head: StackDepth, + ) { + if let Some(usage_kind) = usage_kind { + stack[head].has_been_used = + Some(stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind))); + } + debug_assert!(stack[head].has_been_used.is_some()); + + // The current root of these cycles. Note that this may not be the final + // root in case a later goal depends on a goal higher up the stack. + let mut current_root = head; + while let Some(parent) = stack[current_root].non_root_cycle_participant { + current_root = parent; + debug_assert!(stack[current_root].has_been_used.is_some()); + } + + let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1); + let current_cycle_root = &mut stack[current_root.as_usize()]; + for entry in cycle_participants { + entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); + current_cycle_root.nested_goals.insert(entry.input); + current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); + } + } + + fn clear_dependent_provisional_results( + provisional_cache: &mut HashMap>, + head: StackDepth, + ) { + #[allow(rustc::potential_query_instability)] + provisional_cache.retain(|_, entry| { + if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_coinductive_stack.take(); + } + if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) { + entry.with_inductive_stack.take(); + } + !entry.is_empty() + }); + } + + /// Probably the most involved method of the whole solver. + /// + /// Given some goal which is proven via the `prove_goal` closure, this + /// handles caching, overflow, and coinductive cycles. + pub fn with_new_goal( + &mut self, + cx: X, + input: X::Input, + inspect: &mut D::ProofTreeBuilder, + mut prove_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + ) -> X::Result { + self.check_invariants(); + // Check for overflow. + let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::(cx, &self.stack) + else { + if let Some(last) = self.stack.raw.last_mut() { + last.encountered_overflow = true; + } + + debug!("encountered stack overflow"); + return D::on_stack_overflow(cx, inspect, input); + }; + + if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) { + return result; + } + + // Check whether the goal is in the provisional cache. + // The provisional result may rely on the path to its cycle roots, + // so we have to check the path of the current goal matches that of + // the cache entry. + let cache_entry = self.provisional_cache.entry(input).or_default(); + if let Some(entry) = cache_entry + .with_coinductive_stack + .as_ref() + .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head)) + .or_else(|| { + cache_entry + .with_inductive_stack + .as_ref() + .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head)) + }) + { + debug!("provisional cache hit"); + // We have a nested goal which is already in the provisional cache, use + // its result. We do not provide any usage kind as that should have been + // already set correctly while computing the cache entry. + inspect.on_provisional_cache_hit(); + Self::tag_cycle_participants(&mut self.stack, None, entry.head); + return entry.result; + } else if let Some(stack_depth) = cache_entry.stack_depth { + debug!("encountered cycle with depth {stack_depth:?}"); + // We have a nested goal which directly relies on a goal deeper in the stack. + // + // We start by tagging all cycle participants, as that's necessary for caching. + // + // Finally we can return either the provisional response or the initial response + // in case we're in the first fixpoint iteration for this goal. + inspect.on_cycle_in_stack(); + + let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth); + let cycle_kind = + if is_coinductive_cycle { CycleKind::Coinductive } else { CycleKind::Inductive }; + Self::tag_cycle_participants( + &mut self.stack, + Some(UsageKind::Single(cycle_kind)), + stack_depth, + ); + + // Return the provisional result or, if we're in the first iteration, + // start with no constraints. + return if let Some(result) = self.stack[stack_depth].provisional_result { + result + } else { + D::initial_provisional_result(cx, cycle_kind, input) + }; + } else { + // No entry, we push this goal on the stack and try to prove it. + let depth = self.stack.next_index(); + let entry = StackEntry { + input, + available_depth, + reached_depth: depth, + non_root_cycle_participant: None, + encountered_overflow: false, + has_been_used: None, + nested_goals: Default::default(), + provisional_result: None, + }; + assert_eq!(self.stack.push(entry), depth); + cache_entry.stack_depth = Some(depth); + }; + + // This is for global caching, so we properly track query dependencies. + // Everything that affects the `result` should be performed within this + // `with_anon_task` closure. If computing this goal depends on something + // not tracked by the cache key and from outside of this anon task, it + // must not be added to the global cache. Notably, this is the case for + // trait solver cycles participants. + let ((final_entry, result), dep_node) = cx.with_cached_task(|| { + for _ in 0..D::FIXPOINT_STEP_LIMIT { + match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) { + StepResult::Done(final_entry, result) => return (final_entry, result), + StepResult::HasChanged => debug!("fixpoint changed provisional results"), + } + } + + debug!("canonical cycle overflow"); + let current_entry = self.stack.pop().unwrap(); + debug_assert!(current_entry.has_been_used.is_none()); + let result = D::on_fixpoint_overflow(cx, input); + (current_entry, result) + }); + + let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); + + self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); + + // We're now done with this goal. In case this goal is involved in a larger cycle + // do not remove it from the provisional cache and update its provisional result. + // We only add the root of cycles to the global cache. + if let Some(head) = final_entry.non_root_cycle_participant { + let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head); + + let entry = self.provisional_cache.get_mut(&input).unwrap(); + entry.stack_depth = None; + if coinductive_stack { + entry.with_coinductive_stack = Some(DetachedEntry { head, result }); + } else { + entry.with_inductive_stack = Some(DetachedEntry { head, result }); + } + } else { + // When encountering a cycle, both inductive and coinductive, we only + // move the root into the global cache. We also store all other cycle + // participants involved. + // + // We must not use the global cache entry of a root goal if a cycle + // participant is on the stack. This is necessary to prevent unstable + // results. See the comment of `StackEntry::nested_goals` for + // more details. + self.provisional_cache.remove(&input); + let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); + cx.with_global_cache(self.mode, |cache| { + cache.insert( + cx, + input, + result, + proof_tree, + dep_node, + additional_depth, + final_entry.encountered_overflow, + &final_entry.nested_goals, + ) + }) + } + + self.check_invariants(); + + result + } + + /// Try to fetch a previously computed result from the global cache, + /// making sure to only do so if it would match the result of reevaluating + /// this goal. + fn lookup_global_cache( + &mut self, + cx: X, + input: X::Input, + available_depth: AvailableDepth, + inspect: &mut D::ProofTreeBuilder, + ) -> Option { + cx.with_global_cache(self.mode, |cache| { + let CacheData { + result, + proof_tree, + additional_depth, + encountered_overflow, + nested_goals: _, // FIXME: consider nested goals here. + } = cache.get(cx, input, &self.stack, available_depth)?; + + // If we're building a proof tree and the current cache entry does not + // contain a proof tree, we do not use the entry but instead recompute + // the goal. We simply overwrite the existing entry once we're done, + // caching the proof tree. + if !inspect.try_apply_proof_tree(proof_tree) { + return None; + } + + // Update the reached depth of the current goal to make sure + // its state is the same regardless of whether we've used the + // global cache or not. + let reached_depth = self.stack.next_index().plus(additional_depth); + self.update_parent_goal(reached_depth, encountered_overflow); + + debug!("global cache hit"); + Some(result) + }) + } +} + +enum StepResult { + Done(StackEntry, X::Result), + HasChanged, +} + +impl, X: Cx> SearchGraph { + /// When we encounter a coinductive cycle, we have to fetch the + /// result of that cycle while we are still computing it. Because + /// of this we continuously recompute the cycle until the result + /// of the previous iteration is equal to the final result, at which + /// point we are done. + fn fixpoint_step_in_task( + &mut self, + cx: X, + input: X::Input, + inspect: &mut D::ProofTreeBuilder, + prove_goal: &mut F, + ) -> StepResult + where + F: FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + { + let result = prove_goal(self, inspect); + let stack_entry = self.stack.pop().unwrap(); + debug_assert_eq!(stack_entry.input, input); + + // If the current goal is not the root of a cycle, we are done. + let Some(usage_kind) = stack_entry.has_been_used else { + return StepResult::Done(stack_entry, result); + }; + + // If it is a cycle head, we have to keep trying to prove it until + // we reach a fixpoint. We need to do so for all cycle heads, + // not only for the root. + // + // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs + // for an example. + + // Start by clearing all provisional cache entries which depend on this + // the current goal. + Self::clear_dependent_provisional_results( + &mut self.provisional_cache, + self.stack.next_index(), + ); + + // Check whether we reached a fixpoint, either because the final result + // is equal to the provisional result of the previous iteration, or because + // this was only the root of either coinductive or inductive cycles, and the + // final result is equal to the initial response for that case. + // + // If we did not reach a fixpoint, update the provisional result and reevaluate. + if D::reached_fixpoint(cx, usage_kind, input, stack_entry.provisional_result, result) { + StepResult::Done(stack_entry, result) + } else { + let depth = self.stack.push(StackEntry { + has_been_used: None, + provisional_result: Some(result), + ..stack_entry + }); + debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth)); + StepResult::HasChanged + } + } +} diff --git a/compiler/rustc_type_ir/src/search_graph/validate.rs b/compiler/rustc_type_ir/src/search_graph/validate.rs new file mode 100644 index 000000000000..1ae806834ba7 --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/validate.rs @@ -0,0 +1,75 @@ +use super::*; + +impl, X: Cx> SearchGraph { + #[allow(rustc::potential_query_instability)] + pub(super) fn check_invariants(&self) { + if !cfg!(debug_assertions) { + return; + } + + let SearchGraph { mode: _, stack, provisional_cache, _marker } = self; + if stack.is_empty() { + assert!(provisional_cache.is_empty()); + } + + for (depth, entry) in stack.iter_enumerated() { + let StackEntry { + input, + available_depth: _, + reached_depth: _, + non_root_cycle_participant, + encountered_overflow: _, + has_been_used, + ref nested_goals, + provisional_result, + } = *entry; + let cache_entry = provisional_cache.get(&entry.input).unwrap(); + assert_eq!(cache_entry.stack_depth, Some(depth)); + if let Some(head) = non_root_cycle_participant { + assert!(head < depth); + assert!(nested_goals.is_empty()); + assert_ne!(stack[head].has_been_used, None); + + let mut current_root = head; + while let Some(parent) = stack[current_root].non_root_cycle_participant { + current_root = parent; + } + assert!(stack[current_root].nested_goals.contains(&input)); + } + + if !nested_goals.is_empty() { + assert!(provisional_result.is_some() || has_been_used.is_some()); + for entry in stack.iter().take(depth.as_usize()) { + assert_eq!(nested_goals.get(&entry.input), None); + } + } + } + + for (&input, entry) in &self.provisional_cache { + let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } = + entry; + assert!( + stack_depth.is_some() + || with_coinductive_stack.is_some() + || with_inductive_stack.is_some() + ); + + if let &Some(stack_depth) = stack_depth { + assert_eq!(stack[stack_depth].input, input); + } + + let check_detached = |detached_entry: &DetachedEntry| { + let DetachedEntry { head, result: _ } = *detached_entry; + assert_ne!(stack[head].has_been_used, None); + }; + + if let Some(with_coinductive_stack) = with_coinductive_stack { + check_detached(with_coinductive_stack); + } + + if let Some(with_inductive_stack) = with_inductive_stack { + check_detached(with_inductive_stack); + } + } + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve/mod.rs similarity index 100% rename from compiler/rustc_type_ir/src/solve.rs rename to compiler/rustc_type_ir/src/solve/mod.rs diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 01e4f1d1f33b..9b912d160742 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1045,7 +1045,6 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, - Wasm, System { unwind: bool }, RustIntrinsic, RustCall, diff --git a/config.example.toml b/config.example.toml index 679abcdc7771..a2c2fa1c2bd5 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,6 +1,6 @@ # Sample TOML configuration file for building Rust. # -# To configure rustbuild, run `./configure` or `./x.py setup`. +# To configure bootstrap, run `./configure` or `./x.py setup`. # See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information. # # All options are commented out by default in this file, and they're commented @@ -109,7 +109,7 @@ # increases the size of binaries and consequently the memory required by # each linker process. # If set to 0, linker invocations are treated like any other job and -# controlled by rustbuild's -j parameter. +# controlled by bootstrap's -j parameter. #link-jobs = 0 # Whether to build LLVM as a dynamically linked library (as opposed to statically linked). @@ -371,11 +371,11 @@ # Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time. #local-rebuild = false -# Print out how long each rustbuild step took (mostly intended for CI and +# Print out how long each bootstrap step took (mostly intended for CI and # tracking over time) #print-step-timings = false -# Print out resource usage data for each rustbuild step, as defined by the Unix +# Print out resource usage data for each bootstrap step, as defined by the Unix # struct rusage. (Note that this setting is completely unstable: the data it # captures, what platforms it supports, the format of its associated output, and # this setting's very existence, are all subject to change.) @@ -609,7 +609,7 @@ # Forces frame pointers to be used with `-Cforce-frame-pointers`. # This can be helpful for profiling at a small performance cost. -# frame-pointers = false +#frame-pointers = false # Indicates whether stack protectors should be used # via the unstable option `-Zstack-protector`. diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 65bcb241e4ae..f299aa0124db 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1213,6 +1213,9 @@ impl Box { /// let static_ref: &'static mut usize = Box::leak(x); /// *static_ref += 1; /// assert_eq!(*static_ref, 42); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` /// /// Unsized data: @@ -1222,6 +1225,9 @@ impl Box { /// let static_ref = Box::leak(x); /// static_ref[0] = 4; /// assert_eq!(*static_ref, [4, 2, 3]); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] #[inline] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 3745ecb48c18..9982c8ea6dcb 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -665,16 +665,6 @@ impl Rc { } impl Rc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } /// Constructs a new `Rc` in the provided allocator. /// /// # Examples @@ -1287,6 +1277,8 @@ impl Rc { /// /// let five = Rc::from_raw(ptr); /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count(ptr); /// } /// ``` #[inline] @@ -1331,6 +1323,17 @@ impl Rc { } impl Rc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -1344,6 +1347,8 @@ impl Rc { /// let x = Rc::new("hello".to_owned()); /// let x_ptr = Rc::into_raw(x); /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] @@ -1571,6 +1576,8 @@ impl Rc { /// /// let five = Rc::from_raw_in(ptr, System); /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count_in(ptr, System); /// } /// ``` #[inline] @@ -2994,6 +3001,13 @@ impl Weak { } impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 36078da7c35a..07ffd3e15191 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1984,6 +1984,9 @@ impl String { /// let x = String::from("bucket"); /// let static_ref: &'static mut str = x.leak(); /// assert_eq!(static_ref, "bucket"); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "string_leak", since = "1.72.0")] #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1983ea8281aa..a905a1e6b7e6 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -677,16 +677,6 @@ impl Arc { } impl Arc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } /// Constructs a new `Arc` in the provided allocator. /// /// # Examples @@ -1424,6 +1414,8 @@ impl Arc { /// // the `Arc` between threads. /// let five = Arc::from_raw(ptr); /// assert_eq!(2, Arc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Arc::decrement_strong_count(ptr); /// } /// ``` #[inline] @@ -1470,6 +1462,17 @@ impl Arc { } impl Arc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + /// Consumes the `Arc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Arc` using @@ -1483,6 +1486,8 @@ impl Arc { /// let x = Arc::new("hello".to_owned()); /// let x_ptr = Arc::into_raw(x); /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Arc::from_raw(x_ptr) }); /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] @@ -1765,6 +1770,8 @@ impl Arc { /// // the `Arc` between threads. /// let five = Arc::from_raw_in(ptr, System); /// assert_eq!(2, Arc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Arc::decrement_strong_count_in(ptr, System); /// } /// ``` #[inline] @@ -2715,6 +2722,13 @@ impl Weak { } impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 3bd89eaa6cb5..10f62e4bb62d 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -120,10 +120,15 @@ impl IntoIter { /// This is roughly equivalent to the following, but more efficient /// /// ``` - /// # let mut into_iter = Vec::::with_capacity(10).into_iter(); + /// # let mut vec = Vec::::with_capacity(10); + /// # let ptr = vec.as_mut_ptr(); + /// # let mut into_iter = vec.into_iter(); /// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter()); /// (&mut into_iter).for_each(drop); /// std::mem::forget(into_iter); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Vec::::from_raw_parts(ptr, 0, 10) }); /// ``` /// /// This method is used by in-place iteration, refer to the vec::in_place_collect diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6e9b017ad75c..729d5dd4fe4d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1473,6 +1473,9 @@ impl Vec { /// // 2. `0 <= capacity` always holds whatever `capacity` is. /// unsafe { /// vec.set_len(0); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # vec.set_len(3); /// } /// ``` /// @@ -2391,6 +2394,9 @@ impl Vec { /// let static_ref: &'static mut [usize] = x.leak(); /// static_ref[0] += 1; /// assert_eq!(static_ref, &[2, 2, 3]); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # drop(unsafe { Box::from_raw(static_ref) }); /// ``` #[stable(feature = "vec_leak", since = "1.47.0")] #[inline] diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index bc026d0a4463..ccb1cc4e974d 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -184,6 +184,7 @@ pub trait Borrow { /// an underlying type by providing a mutable reference. See [`Borrow`] /// for more information on borrowing as another type. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "BorrowMut"] pub trait BorrowMut: Borrow { /// Mutably borrows from an owned value. /// diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 7c7130ec075e..21452d40f9de 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -67,7 +67,7 @@ impl T> LazyCell { /// # Examples /// /// ``` - /// #![feature(lazy_cell_consume)] + /// #![feature(lazy_cell_into_inner)] /// /// use std::cell::LazyCell; /// @@ -78,7 +78,7 @@ impl T> LazyCell { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "125623")] + #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub fn into_inner(this: Self) -> Result { match this.state.into_inner() { State::Init(data) => Ok(data), diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 458be49fb152..4186565c131e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -223,7 +223,10 @@ impl char { /// assert_eq!('❤', c); /// ``` #[stable(feature = "assoc_char_funcs", since = "1.52.0")] - #[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")] + #[rustc_const_stable( + feature = "const_char_from_u32_unchecked", + since = "CURRENT_RUSTC_VERSION" + )] #[must_use] #[inline] pub const unsafe fn from_u32_unchecked(i: u32) -> char { diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index f3683fe3f9c8..26b463e25ea6 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -123,7 +123,7 @@ pub const fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]. /// instead. #[stable(feature = "char_from_unchecked", since = "1.5.0")] -#[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")] +#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const unsafe fn from_u32_unchecked(i: u32) -> char { diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d2a408485d16..76752f22ed89 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -263,8 +263,6 @@ impl CStr { /// ``` /// /// ``` - /// #![feature(const_cstr_from_ptr)] - /// /// use std::ffi::{c_char, CStr}; /// /// const HELLO_PTR: *const c_char = { @@ -280,11 +278,11 @@ impl CStr { #[inline] // inline is necessary for codegen to see strlen. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] + #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C // string with a NUL terminator less than `isize::MAX` from `ptr`. - let len = unsafe { const_strlen(ptr) }; + let len = unsafe { strlen(ptr) }; // SAFETY: The caller has provided a valid pointer with length less than // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid @@ -542,7 +540,7 @@ impl CStr { #[must_use] #[doc(alias("len", "strlen"))] #[stable(feature = "cstr_count_bytes", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] + #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const fn count_bytes(&self) -> usize { self.inner.len() - 1 } @@ -742,7 +740,10 @@ impl AsRef for CStr { /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be /// located within `isize::MAX` from `ptr`. #[inline] -const unsafe fn const_strlen(ptr: *const c_char) -> usize { +#[unstable(feature = "cstr_internals", issue = "none")] +#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")] +#[rustc_allow_const_fn_unstable(const_eval_select)] +const unsafe fn strlen(ptr: *const c_char) -> usize { const fn strlen_ct(s: *const c_char) -> usize { let mut len = 0; diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 0168b11c7394..243f938bce2a 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -8,11 +8,15 @@ use crate::num::NonZero; /// Infinite iterators like `repeat()` are often used with adapters like /// [`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. +/// /// 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 /// instead use the [`repeat_with()`] function. /// /// [`repeat_with()`]: crate::iter::repeat_with +/// [`str::repeat()`]: ../../std/primitive.str.html#method.repeat /// /// # Examples /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0f82f01e57a7..49f89e702558 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -119,7 +119,6 @@ #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_cell_into_inner)] -#![feature(const_char_from_u32_unchecked)] #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_bits_conv)] diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index e0c3b9f3b51d..997f088c6d68 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -62,6 +62,9 @@ impl ManuallyDrop { /// x.truncate(5); // You can still safely operate on the value /// assert_eq!(*x, "Hello"); /// // But `Drop` will not be run here + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # let _ = ManuallyDrop::into_inner(x); /// ``` #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] #[stable(feature = "manually_drop", since = "1.20.0")] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 24ebe33bb2c1..dd40f57dc870 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -274,6 +274,8 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let v: MaybeUninit> = MaybeUninit::new(vec![42]); + /// # // Prevent leaks for Miri + /// # unsafe { let _ = MaybeUninit::assume_init(v); } /// ``` /// /// [`assume_init`]: MaybeUninit::assume_init @@ -446,6 +448,9 @@ impl MaybeUninit { /// let mut x = MaybeUninit::::uninit(); /// /// x.write("Hello".to_string()); + /// # // FIXME(https://github.com/rust-lang/miri/issues/3670): + /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak. + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// // This leaks the contained string: /// x.write("hello".to_string()); /// // x is initialized now: @@ -506,6 +511,8 @@ impl MaybeUninit { /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; /// assert_eq!(x_vec.len(), 3); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// ``` /// /// *Incorrect* usage of this method: @@ -545,6 +552,8 @@ impl MaybeUninit { /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; /// x_vec.push(3); /// assert_eq!(x_vec.len(), 4); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x); } /// ``` /// /// *Incorrect* usage of this method: @@ -746,6 +755,8 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); + /// # let mut x_mu = x; + /// # let mut x = &mut x_mu; /// // Initialize `x`: /// x.write(vec![1, 2, 3]); /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to @@ -755,6 +766,8 @@ impl MaybeUninit { /// x.assume_init_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); + /// # // Prevent leaks for Miri + /// # unsafe { MaybeUninit::assume_init_drop(&mut x_mu); } /// ``` /// /// ### *Incorrect* usages of this method: @@ -1088,6 +1101,8 @@ impl MaybeUninit { /// let init = MaybeUninit::clone_from_slice(&mut dst, &src); /// /// assert_eq!(init, src); + /// # // Prevent leaks for Miri + /// # unsafe { std::ptr::drop_in_place(init); } /// ``` /// /// ``` diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 58ed98c888cc..05dc1e97852e 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -12,7 +12,10 @@ #![unstable(feature = "f128", issue = "116909")] use crate::convert::FloatToInt; +#[cfg(not(test))] +use crate::intrinsics; use crate::mem; +use crate::num::FpCategory; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] @@ -167,7 +170,7 @@ impl f128 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS #[unstable(feature = "f128", issue = "116909")] - pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128; + pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128; /// Smallest finite `f128` value. /// @@ -175,7 +178,7 @@ impl f128 { /// /// [`MAX`]: f128::MAX #[unstable(feature = "f128", issue = "116909")] - pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128; + pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128; /// Smallest positive normal `f128` value. /// /// Equal to 2[`MIN_EXP`] − 1. @@ -191,7 +194,7 @@ impl f128 { /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS /// [`MAX_EXP`]: f128::MAX_EXP #[unstable(feature = "f128", issue = "116909")] - pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128; + pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; /// One greater than the minimum possible normal power of 2 exponent. /// @@ -251,6 +254,12 @@ impl f128 { #[cfg(not(bootstrap))] pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + /// Exponent mask + pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000; + + /// Mantissa mask + pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff; + /// Minimum representable positive value (min subnormal) #[cfg(not(bootstrap))] const TINY_BITS: u128 = 0x1; @@ -354,6 +363,119 @@ impl f128 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128 + /// let max = f128::MAX; + /// let lower_than_min = 1.0e-4960_f128; + /// let zero = 0.0_f128; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f128::NAN.is_subnormal()); + /// assert!(!f128::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// # } + /// ``` + /// + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + + /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128 + /// let max = f128::MAX; + /// let lower_than_min = 1.0e-4960_f128; + /// let zero = 0.0_f128; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f128::NAN.is_normal()); + /// assert!(!f128::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// # } + /// ``` + /// + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) + } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// #![feature(f128)] + /// # // FIXME(f16_f128): remove when `eqtf2` is available + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + /// use std::num::FpCategory; + /// + /// let num = 12.4_f128; + /// let inf = f128::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// # } + /// ``` + #[inline] + #[cfg(not(bootstrap))] + #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { + // Other float types cannot use a bitwise classify because they may suffer a variety + // of errors if the backend chooses to cast to different float types (x87). `f128` cannot + // fit into any other float types so this is not a concern, and we rely on bit patterns. + + // SAFETY: POD bitcast, same as in `to_bits`. + let bits = unsafe { mem::transmute::(self) }; + Self::classify_bits(bits) + } + + /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs. + /// FIXME(jubilee): In a just world, this would be the entire impl for classify, + /// plus a transmute. We do not live in a just world, but we can make it more so. + #[inline] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn classify_bits(b: u128) -> FpCategory { + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that @@ -638,12 +760,52 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_bits(self) -> u128 { - // SAFETY: `u128` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(self) } + pub const fn to_bits(self) -> u128 { + // SAFETY: `u128` is a plain old datatype so we can always transmute to it. + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to a floating point mode that alters nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // we reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_f128_to_u128(ct: f128) -> u128 { + // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that + // is not available on all platforms (needs `netf2` and `unordtf2`). So classify + // the bits instead. + + // SAFETY: this is a POD transmutation + let bits = unsafe { mem::transmute::(ct) }; + match f128::classify_bits(bits) { + FpCategory::Nan => { + panic!("const-eval error: cannot use f128::to_bits on a NaN") + } + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f128::to_bits on a subnormal number") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits, + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f128_to_u128(x: f128) -> u128 { + // SAFETY: `u128` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128) } /// Raw transmutation from `u128`. @@ -688,11 +850,52 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_bits(v: u128) -> Self { - // SAFETY: `u128 is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(v) } + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_bits(v: u128) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + // SAFETY: `u128` is a plain old datatype so we can always transmute from it + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to floating point modes that alter nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // This is not a problem usually, but at least one tier2 platform for Rust + // actually exhibits this behavior by default: thumbv7neon + // aka "the Neon FPU in AArch32 state" + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_u128_to_f128(ct: u128) -> f128 { + match f128::classify_bits(ct) { + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f128::from_bits on a subnormal number") + } + FpCategory::Nan => { + panic!("const-eval error: cannot use f128::from_bits on NaN") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => { + // SAFETY: It's not a frumious number + unsafe { mem::transmute::(ct) } + } + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u128_to_f128(x: u128) -> f128 { + // SAFETY: `u128` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128) } /// Return the memory representation of this floating point number as a byte array in @@ -715,8 +918,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_be_bytes(self) -> [u8; 16] { + pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() } @@ -740,8 +944,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_le_bytes(self) -> [u8; 16] { + pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() } @@ -776,8 +981,9 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_ne_bytes(self) -> [u8; 16] { + pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() } @@ -803,7 +1009,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_be_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -829,7 +1036,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_le_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -865,7 +1073,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn from_ne_bytes(bytes: [u8; 16]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e74300d6c2f3..2a8ede938384 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -12,7 +12,10 @@ #![unstable(feature = "f16", issue = "116909")] use crate::convert::FloatToInt; +#[cfg(not(test))] +use crate::intrinsics; use crate::mem; +use crate::num::FpCategory; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] @@ -244,7 +247,13 @@ impl f16 { /// Sign bit #[cfg(not(bootstrap))] - const SIGN_MASK: u16 = 0x8000; + pub(crate) const SIGN_MASK: u16 = 0x8000; + + /// Exponent mask + pub(crate) const EXP_MASK: u16 = 0x7c00; + + /// Mantissa mask + pub(crate) const MAN_MASK: u16 = 0x03ff; /// Minimum representable positive value (min subnormal) #[cfg(not(bootstrap))] @@ -344,6 +353,159 @@ impl f16 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let min = f16::MIN_POSITIVE; // 6.1035e-5 + /// let max = f16::MAX; + /// let lower_than_min = 1.0e-7_f16; + /// let zero = 0.0_f16; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f16::NAN.is_subnormal()); + /// assert!(!f16::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// # } + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + + /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let min = f16::MIN_POSITIVE; // 6.1035e-5 + /// let max = f16::MAX; + /// let lower_than_min = 1.0e-7_f16; + /// let zero = 0.0_f16; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f16::NAN.is_normal()); + /// assert!(!f16::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// # } + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[inline] + #[must_use] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn is_normal(self) -> bool { + matches!(self.classify(), FpCategory::Normal) + } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// use std::num::FpCategory; + /// + /// let num = 12.4_f16; + /// let inf = f16::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// # } + /// ``` + #[inline] + #[cfg(not(bootstrap))] + #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + pub const fn classify(self) -> FpCategory { + // A previous implementation for f32/f64 tried to only use bitmask-based checks, + // using `to_bits` to transmute the float to its bit repr and match on that. + // Unfortunately, floating point numbers can be much worse than that. + // This also needs to not result in recursive evaluations of `to_bits`. + // + + // Platforms without native support generally convert to `f32` to perform operations, + // and most of these platforms correctly round back to `f16` after each operation. + // However, some platforms have bugs where they keep the excess `f32` precision (e.g. + // WASM, see llvm/llvm-project#96437). This implementation makes a best-effort attempt + // to account for that excess precision. + if self.is_infinite() { + // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask. + FpCategory::Infinite + } else if self.is_nan() { + // And it may not be NaN, as it can simply be an "overextended" finite value. + FpCategory::Nan + } else { + // However, std can't simply compare to zero to check for zero, either, + // as correctness requires avoiding equality tests that may be Subnormal == -0.0 + // because it may be wrong under "denormals are zero" and "flush to zero" modes. + // Most of std's targets don't use those, but they are used for thumbv7neon. + // So, this does use bitpattern matching for the rest. + + // SAFETY: f16 to u16 is fine. Usually. + // If classify has gotten this far, the value is definitely in one of these categories. + unsafe { f16::partial_classify(self) } + } + } + + /// This doesn't actually return a right answer for NaN on purpose, + /// seeing as how it cannot correctly discern between a floating point NaN, + /// and some normal floating point numbers truncated from an x87 FPU. + /// + /// # Safety + /// + /// This requires making sure you call this function for values it answers correctly on, + /// otherwise it returns a wrong answer. This is not important for memory safety per se, + /// but getting floats correct is important for not accidentally leaking const eval + /// runtime-deviating logic which may or may not be acceptable. + #[inline] + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const unsafe fn partial_classify(self) -> FpCategory { + // SAFETY: The caller is not asking questions for which this will tell lies. + let b = unsafe { mem::transmute::(self) }; + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + + /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs. + /// FIXME(jubilee): In a just world, this would be the entire impl for classify, + /// plus a transmute. We do not live in a just world, but we can make it more so. + #[inline] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + const fn classify_bits(b: u16) -> FpCategory { + match (b & Self::MAN_MASK, b & Self::EXP_MASK) { + (0, Self::EXP_MASK) => FpCategory::Infinite, + (_, Self::EXP_MASK) => FpCategory::Nan, + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + _ => FpCategory::Normal, + } + } + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that @@ -353,12 +515,15 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0_f16; /// let g = -7.0_f16; /// /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); + /// # } /// ``` #[inline] #[must_use] @@ -376,12 +541,15 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0_f16; /// let g = -7.0_f16; /// /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); + /// # } /// ``` #[inline] #[must_use] @@ -628,12 +796,52 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_bits(self) -> u16 { - // SAFETY: `u16` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(self) } + pub const fn to_bits(self) -> u16 { + // SAFETY: `u16` is a plain old datatype so we can always transmute to it. + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to a floating point mode that alters nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // we reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_f16_to_u16(ct: f16) -> u16 { + // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but we don't yet + // want to rely on that on all platforms because it is nondeterministic (e.g. x86 has + // convention discrepancies calling intrinsics). So just classify the bits instead. + + // SAFETY: this is a POD transmutation + let bits = unsafe { mem::transmute::(ct) }; + match f16::classify_bits(bits) { + FpCategory::Nan => { + panic!("const-eval error: cannot use f16::to_bits on a NaN") + } + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f16::to_bits on a subnormal number") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits, + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f16_to_u16(x: f16) -> u16 { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((self,), ct_f16_to_u16, rt_f16_to_u16) } /// Raw transmutation from `u16`. @@ -677,11 +885,52 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_bits(v: u16) -> Self { - // SAFETY: `u16` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - unsafe { mem::transmute(v) } + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_bits(v: u16) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + // SAFETY: `u16` is a plain old datatype so we can always transmute from it + // ...sorta. + // + // It turns out that at runtime, it is possible for a floating point number + // to be subject to floating point modes that alter nonzero subnormal numbers + // to zero on reads and writes, aka "denormals are zero" and "flush to zero". + // This is not a problem usually, but at least one tier2 platform for Rust + // actually exhibits this behavior by default: thumbv7neon + // aka "the Neon FPU in AArch32 state" + // + // And, of course evaluating to a NaN value is fairly nondeterministic. + // More precisely: when NaN should be returned is knowable, but which NaN? + // So far that's defined by a combination of LLVM and the CPU, not Rust. + // This function, however, allows observing the bitstring of a NaN, + // thus introspection on CTFE. + // + // In order to preserve, at least for the moment, const-to-runtime equivalence, + // reject any of these possible situations from happening. + #[inline] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + const fn ct_u16_to_f16(ct: u16) -> f16 { + match f16::classify_bits(ct) { + FpCategory::Subnormal => { + panic!("const-eval error: cannot use f16::from_bits on a subnormal number") + } + FpCategory::Nan => { + panic!("const-eval error: cannot use f16::from_bits on NaN") + } + FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => { + // SAFETY: It's not a frumious number + unsafe { mem::transmute::(ct) } + } + } + } + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u16_to_f16(x: u16) -> f16 { + // SAFETY: `u16` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } + intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16) } /// Return the memory representation of this floating point number as a byte array in @@ -694,14 +943,18 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_be_bytes(); /// assert_eq!(bytes, [0x4a, 0x40]); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_be_bytes(self) -> [u8; 2] { + pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() } @@ -715,14 +968,18 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_le_bytes(); /// assert_eq!(bytes, [0x40, 0x4a]); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_le_bytes(self) -> [u8; 2] { + pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() } @@ -742,6 +999,8 @@ impl f16 { /// /// ``` /// #![feature(f16)] + /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let bytes = 12.5f16.to_ne_bytes(); /// assert_eq!( @@ -752,11 +1011,13 @@ impl f16 { /// [0x40, 0x4a] /// } /// ); + /// # } /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] #[must_use = "this returns the result of the operation, without modifying the original"] - pub fn to_ne_bytes(self) -> [u8; 2] { + pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() } @@ -778,7 +1039,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_be_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -800,7 +1062,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_le_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -833,7 +1096,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn from_ne_bytes(bytes: [u8; 2]) -> Self { + #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")] + pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 68cf82034334..3e7933e9eec8 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -604,9 +604,9 @@ impl *const T { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -653,14 +653,14 @@ impl *const T { /// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8; /// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8; /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff).wrapping_offset(1); /// assert_eq!(ptr2 as usize, ptr2_other as usize); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// unsafe { - /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️ /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 0dc910db5b9b..904d6c62dcf1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -829,9 +829,9 @@ impl *mut T { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -878,14 +878,14 @@ impl *mut T { /// let ptr1 = Box::into_raw(Box::new(0u8)); /// let ptr2 = Box::into_raw(Box::new(1u8)); /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff).wrapping_offset(1); /// assert_eq!(ptr2 as usize, ptr2_other as usize); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// unsafe { - /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️ /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 75a99e14fdad..796c85d0cacc 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -735,9 +735,9 @@ impl NonNull { /// /// * `self` and `origin` must either /// + /// * point to the same address, or /// * both be *derived from* a pointer to the same [allocated object], and the memory range between - /// the two pointers must be either empty or in bounds of that object. (See below for an example.) - /// * or both be derived from an integer literal/constant, and point to the same address. + /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. @@ -789,14 +789,15 @@ impl NonNull { /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap(); /// let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap(); /// let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize); - /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. - /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff)).unwrap(); + /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1. + /// let diff_plus_1 = diff.wrapping_add(1); + /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff_plus_1)).unwrap(); /// assert_eq!(ptr2.addr(), ptr2_other.addr()); /// // Since ptr2_other and ptr2 are derived from pointers to different objects, /// // computing their offset is undefined behavior, even though - /// // they point to the same address! + /// // they point to addresses that are in-bounds of the same object! /// - /// let zero = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior + /// let one = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior! ⚠️ /// ``` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -1663,6 +1664,8 @@ impl NonNull<[T]> { /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] /// let slice: &mut [MaybeUninit] = unsafe { memory.as_uninit_slice_mut() }; + /// # // Prevent leaks for Miri. + /// # unsafe { Global.deallocate(memory.cast(), Layout::new::<[u8; 32]>()); } /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index ca1920f98120..504676ce187a 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -388,6 +388,9 @@ pub(super) trait SplitIter: DoubleEndedIterator { /// ``` /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split(|num| num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40][..])); +/// assert_eq!(iter.next(), Some(&[20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`split`]: slice::split @@ -541,6 +544,9 @@ impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} /// ``` /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40, 33][..])); +/// assert_eq!(iter.next(), Some(&[20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`split_inclusive`]: slice::split_inclusive @@ -914,7 +920,10 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// /// ``` /// let slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit(|num| *num == 0); +/// let mut iter = slice.rsplit(|num| *num == 0); +/// assert_eq!(iter.next(), Some(&[44, 55][..])); +/// assert_eq!(iter.next(), Some(&[11, 22, 33][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rsplit`]: slice::rsplit @@ -1134,7 +1143,10 @@ impl> Iterator for GenericSplitN { /// /// ``` /// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// let mut iter = slice.splitn(2, |num| *num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[10, 40][..])); +/// assert_eq!(iter.next(), Some(&[20, 60, 50][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`splitn`]: slice::splitn @@ -1175,7 +1187,10 @@ where /// /// ``` /// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// let mut iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// assert_eq!(iter.next(), Some(&[50][..])); +/// assert_eq!(iter.next(), Some(&[10, 40, 30, 20][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rsplitn`]: slice::rsplitn @@ -1300,7 +1315,11 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] } /// /// ``` /// let slice = ['r', 'u', 's', 't']; -/// let iter = slice.windows(2); +/// let mut iter = slice.windows(2); +/// assert_eq!(iter.next(), Some(&['r', 'u'][..])); +/// assert_eq!(iter.next(), Some(&['u', 's'][..])); +/// assert_eq!(iter.next(), Some(&['s', 't'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`windows`]: slice::windows @@ -1448,7 +1467,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.chunks(2); +/// let mut iter = slice.chunks(2); +/// assert_eq!(iter.next(), Some(&['l', 'o'][..])); +/// assert_eq!(iter.next(), Some(&['r', 'e'][..])); +/// assert_eq!(iter.next(), Some(&['m'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`chunks`]: slice::chunks @@ -1819,7 +1842,10 @@ unsafe impl Sync for ChunksMut<'_, T> where T: Sync {} /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.chunks_exact(2); +/// let mut iter = slice.chunks_exact(2); +/// assert_eq!(iter.next(), Some(&['l', 'o'][..])); +/// assert_eq!(iter.next(), Some(&['r', 'e'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`chunks_exact`]: slice::chunks_exact @@ -2163,7 +2189,11 @@ unsafe impl Sync for ChunksExactMut<'_, T> where T: Sync {} /// #![feature(array_windows)] /// /// let slice = [0, 1, 2, 3]; -/// let iter = slice.array_windows::<2>(); +/// let mut iter = slice.array_windows::<2>(); +/// assert_eq!(iter.next(), Some(&[0, 1])); +/// assert_eq!(iter.next(), Some(&[1, 2])); +/// assert_eq!(iter.next(), Some(&[2, 3])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`array_windows`]: slice::array_windows @@ -2285,7 +2315,10 @@ impl ExactSizeIterator for ArrayWindows<'_, T, N> { /// #![feature(array_chunks)] /// /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.array_chunks::<2>(); +/// let mut iter = slice.array_chunks::<2>(); +/// assert_eq!(iter.next(), Some(&['l', 'o'])); +/// assert_eq!(iter.next(), Some(&['r', 'e'])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`array_chunks`]: slice::array_chunks @@ -2526,7 +2559,11 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMu /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.rchunks(2); +/// let mut iter = slice.rchunks(2); +/// assert_eq!(iter.next(), Some(&['e', 'm'][..])); +/// assert_eq!(iter.next(), Some(&['o', 'r'][..])); +/// assert_eq!(iter.next(), Some(&['l'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rchunks`]: slice::rchunks @@ -2892,7 +2929,10 @@ unsafe impl Sync for RChunksMut<'_, T> where T: Sync {} /// /// ``` /// let slice = ['l', 'o', 'r', 'e', 'm']; -/// let iter = slice.rchunks_exact(2); +/// let mut iter = slice.rchunks_exact(2); +/// assert_eq!(iter.next(), Some(&['e', 'm'][..])); +/// assert_eq!(iter.next(), Some(&['o', 'r'][..])); +/// assert_eq!(iter.next(), None); /// ``` /// /// [`rchunks_exact`]: slice::rchunks_exact diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 521c32482044..68508e85f8e1 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3959,17 +3959,8 @@ impl [T] { /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix. /// - /// This is a safe wrapper around [`slice::align_to`], so has the same weak - /// postconditions as that method. You're only assured that - /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`. - /// - /// Notably, all of the following are possible: - /// - `prefix.len() >= LANES`. - /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`. - /// - `suffix.len() >= LANES`. - /// - /// That said, this is a safe method, so if you're only writing safe code, - /// then this can at most cause incorrect logic, not unsoundness. + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. /// /// # Panics /// @@ -4033,17 +4024,8 @@ impl [T] { /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types, /// and a mutable suffix. /// - /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak - /// postconditions as that method. You're only assured that - /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`. - /// - /// Notably, all of the following are possible: - /// - `prefix.len() >= LANES`. - /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`. - /// - `suffix.len() >= LANES`. - /// - /// That said, this is a safe method, so if you're only writing safe code, - /// then this can at most cause incorrect logic, not unsoundness. + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. /// /// This is the mutable version of [`slice::as_simd`]; see that for examples. /// diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 358510b8f77d..b991b1cf22dd 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -87,6 +87,10 @@ std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] std_detect_env_override = ["std_detect/std_detect_env_override"] +# Enable using raw-dylib for Windows imports. +# This will eventually be the default. +windows_raw_dylib = [] + [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing threads = 125 diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index fcd1c307b5af..1f6a3e904795 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1018,7 +1018,7 @@ where K: Borrow, Q: Hash + Eq, { - self.base.get_many_unchecked_mut(ks) + unsafe { self.base.get_many_unchecked_mut(ks) } } /// Returns `true` if the map contains a value for the specified key. diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 2f35e721610e..36add02d68c5 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -366,11 +366,8 @@ impl Error for VarError { #[rustc_deprecated_safe_2024] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { - _set_var(key.as_ref(), value.as_ref()) -} - -unsafe fn _set_var(key: &OsStr, value: &OsStr) { - os_imp::setenv(key, value).unwrap_or_else(|e| { + let (key, value) = (key.as_ref(), value.as_ref()); + unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| { panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") }) } @@ -433,11 +430,8 @@ unsafe fn _set_var(key: &OsStr, value: &OsStr) { #[rustc_deprecated_safe_2024] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { - _remove_var(key.as_ref()) -} - -unsafe fn _remove_var(key: &OsStr) { - os_imp::unsetenv(key) + let key = key.as_ref(); + unsafe { os_imp::unsetenv(key) } .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) } diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index bd7a921c502a..0b3e485b0e73 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -3,6 +3,7 @@ #![cfg(reliable_f128)] use crate::f128::consts; +use crate::num::FpCategory as Fp; use crate::num::*; /// Smallest number @@ -52,9 +53,8 @@ fn test_nan() { assert!(!nan.is_finite()); assert!(nan.is_sign_positive()); assert!(!nan.is_sign_negative()); - // FIXME(f16_f128): classify - // assert!(!nan.is_normal()); - // assert_eq!(Fp::Nan, nan.classify()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); } #[test] @@ -65,9 +65,8 @@ fn test_infinity() { assert!(inf.is_sign_positive()); assert!(!inf.is_sign_negative()); assert!(!inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!inf.is_normal()); - // assert_eq!(Fp::Infinite, inf.classify()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); } #[test] @@ -78,9 +77,8 @@ fn test_neg_infinity() { assert!(!neg_inf.is_sign_positive()); assert!(neg_inf.is_sign_negative()); assert!(!neg_inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_inf.is_normal()); - // assert_eq!(Fp::Infinite, neg_inf.classify()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); } #[test] @@ -92,9 +90,8 @@ fn test_zero() { assert!(zero.is_sign_positive()); assert!(!zero.is_sign_negative()); assert!(!zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!zero.is_normal()); - // assert_eq!(Fp::Zero, zero.classify()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); } #[test] @@ -106,9 +103,8 @@ fn test_neg_zero() { assert!(!neg_zero.is_sign_positive()); assert!(neg_zero.is_sign_negative()); assert!(!neg_zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_zero.is_normal()); - // assert_eq!(Fp::Zero, neg_zero.classify()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); } #[test] @@ -120,9 +116,8 @@ fn test_one() { assert!(one.is_sign_positive()); assert!(!one.is_sign_negative()); assert!(!one.is_nan()); - // FIXME(f16_f128): classify - // assert!(one.is_normal()); - // assert_eq!(Fp::Normal, one.classify()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); } #[test] @@ -164,7 +159,40 @@ fn test_is_finite() { assert!((-109.2f128).is_finite()); } -// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working +#[test] +fn test_is_normal() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f128.is_normal()); + assert!(1e-4931f128.is_normal()); + assert!(!1e-4932f128.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f128.classify(), Fp::Normal); + assert_eq!(1e-4931f128.classify(), Fp::Normal); + assert_eq!(1e-4932f128.classify(), Fp::Subnormal); +} + // FIXME(f16_f128): add missing math functions when available #[test] diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs index bb6a811529e1..26658a0be87b 100644 --- a/library/std/src/f16/tests.rs +++ b/library/std/src/f16/tests.rs @@ -3,6 +3,7 @@ #![cfg(reliable_f16)] use crate::f16::consts; +use crate::num::FpCategory as Fp; use crate::num::*; // We run out of precision pretty quickly with f16 @@ -58,9 +59,8 @@ fn test_nan() { assert!(!nan.is_finite()); assert!(nan.is_sign_positive()); assert!(!nan.is_sign_negative()); - // FIXME(f16_f128): classify - // assert!(!nan.is_normal()); - // assert_eq!(Fp::Nan, nan.classify()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); } #[test] @@ -71,9 +71,8 @@ fn test_infinity() { assert!(inf.is_sign_positive()); assert!(!inf.is_sign_negative()); assert!(!inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!inf.is_normal()); - // assert_eq!(Fp::Infinite, inf.classify()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); } #[test] @@ -84,9 +83,8 @@ fn test_neg_infinity() { assert!(!neg_inf.is_sign_positive()); assert!(neg_inf.is_sign_negative()); assert!(!neg_inf.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_inf.is_normal()); - // assert_eq!(Fp::Infinite, neg_inf.classify()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); } #[test] @@ -98,9 +96,8 @@ fn test_zero() { assert!(zero.is_sign_positive()); assert!(!zero.is_sign_negative()); assert!(!zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!zero.is_normal()); - // assert_eq!(Fp::Zero, zero.classify()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); } #[test] @@ -112,9 +109,8 @@ fn test_neg_zero() { assert!(!neg_zero.is_sign_positive()); assert!(neg_zero.is_sign_negative()); assert!(!neg_zero.is_nan()); - // FIXME(f16_f128): classify - // assert!(!neg_zero.is_normal()); - // assert_eq!(Fp::Zero, neg_zero.classify()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); } #[test] @@ -126,9 +122,8 @@ fn test_one() { assert!(one.is_sign_positive()); assert!(!one.is_sign_negative()); assert!(!one.is_nan()); - // FIXME(f16_f128): classify - // assert!(one.is_normal()); - // assert_eq!(Fp::Normal, one.classify()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); } #[test] @@ -170,7 +165,40 @@ fn test_is_finite() { assert!((-109.2f16).is_finite()); } -// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working +#[test] +fn test_is_normal() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f16.is_normal()); + assert!(1e-4f16.is_normal()); + assert!(!1e-5f16.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f16.classify(), Fp::Normal); + assert_eq!(1e-4f16.classify(), Fp::Normal); + assert_eq!(1e-5f16.classify(), Fp::Subnormal); +} + // FIXME(f16_f128): add missing math functions when available #[test] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index f8c66a3e7175..1ca2b32e241c 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -520,7 +520,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f64 { - crate::sys::log_wrapper(self, |n| unsafe { intrinsics::logf64(n) }) + unsafe { intrinsics::logf64(self) } } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -574,7 +574,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - crate::sys::log_wrapper(self, crate::sys::log2f64) + crate::sys::log2f64(self) } /// Returns the base 10 logarithm of the number. @@ -599,7 +599,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f64 { - crate::sys::log_wrapper(self, |n| unsafe { intrinsics::log10f64(n) }) + unsafe { intrinsics::log10f64(self) } } /// The positive difference of two numbers. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 4a417c84a30a..f9dba08da4c3 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -184,7 +184,7 @@ impl OsString { #[inline] #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self { - OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) } + OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } } } /// Converts to an [`OsStr`] slice. @@ -813,7 +813,7 @@ impl OsStr { #[inline] #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { - Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes)) + Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) }) } #[inline] diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index b75579d6d5e0..5ca631399aa4 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1638,16 +1638,8 @@ fn rename_directory() { #[test] fn test_file_times() { - #[cfg(target_os = "ios")] - use crate::os::ios::fs::FileTimesExt; - #[cfg(target_os = "macos")] - use crate::os::macos::fs::FileTimesExt; - #[cfg(target_os = "tvos")] - use crate::os::tvos::fs::FileTimesExt; - #[cfg(target_os = "visionos")] - use crate::os::visionos::fs::FileTimesExt; - #[cfg(target_os = "watchos")] - use crate::os::watchos::fs::FileTimesExt; + #[cfg(target_vendor = "apple")] + use crate::os::darwin::fs::FileTimesExt; #[cfg(windows)] use crate::os::windows::fs::FileTimesExt; @@ -1693,16 +1685,7 @@ fn test_file_times() { #[test] #[cfg(target_vendor = "apple")] fn test_file_times_pre_epoch_with_nanos() { - #[cfg(target_os = "ios")] - use crate::os::ios::fs::FileTimesExt; - #[cfg(target_os = "macos")] - use crate::os::macos::fs::FileTimesExt; - #[cfg(target_os = "tvos")] - use crate::os::tvos::fs::FileTimesExt; - #[cfg(target_os = "visionos")] - use crate::os::visionos::fs::FileTimesExt; - #[cfg(target_os = "watchos")] - use crate::os::watchos::fs::FileTimesExt; + use crate::os::darwin::fs::FileTimesExt; let tmp = tmpdir(); let file = File::create(tmp.join("foo")).unwrap(); diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 2d13230ffbab..a8680e9b6ead 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -3,7 +3,7 @@ use crate::fmt; use crate::io::{ self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, }; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::ptr; /// Wraps a writer and buffers its output. @@ -164,13 +164,13 @@ impl BufWriter { /// assert_eq!(&buffered_data.unwrap(), b"ata"); /// ``` #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] - pub fn into_parts(mut self) -> (W, Result, WriterPanicked>) { - let buf = mem::take(&mut self.buf); - let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; + pub fn into_parts(self) -> (W, Result, WriterPanicked>) { + let mut this = ManuallyDrop::new(self); + let buf = mem::take(&mut this.buf); + let buf = if !this.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; - // SAFETY: forget(self) prevents double dropping inner - let inner = unsafe { ptr::read(&self.inner) }; - mem::forget(self); + // SAFETY: double-drops are prevented by putting `this` in a ManuallyDrop that is never dropped + let inner = unsafe { ptr::read(&this.inner) }; (inner, buf) } @@ -433,9 +433,11 @@ impl BufWriter { let old_len = self.buf.len(); let buf_len = buf.len(); let src = buf.as_ptr(); - let dst = self.buf.as_mut_ptr().add(old_len); - ptr::copy_nonoverlapping(src, dst, buf_len); - self.buf.set_len(old_len + buf_len); + unsafe { + let dst = self.buf.as_mut_ptr().add(old_len); + ptr::copy_nonoverlapping(src, dst, buf_len); + self.buf.set_len(old_len + buf_len); + } } #[inline] diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index ee0db30e22c2..ab66deaf31d2 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1067,3 +1067,13 @@ fn bufreader_full_initialize() { // But we initialized the whole buffer! assert_eq!(reader.initialized(), reader.capacity()); } + +/// This is a regression test for https://github.com/rust-lang/rust/issues/127584. +#[test] +fn bufwriter_aliasing() { + use crate::io::{BufWriter, Cursor}; + let mut v = vec![0; 1024]; + let c = Cursor::new(&mut v); + let w = BufWriter::new(Box::new(c)); + let _ = w.into_parts(); +} diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index a1a8b2a3505c..2ed64a40495e 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -482,7 +482,7 @@ where A: Allocator, { debug_assert!(vec.capacity() >= pos + buf.len()); - vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()); + unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) }; pos + buf.len() } diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index a5cefe2292be..fbb74967df3f 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -267,11 +267,14 @@ where // Using this rather than unwrap meaningfully improves the code // for callers which only care about one variant (usually // `Custom`) - core::hint::unreachable_unchecked(); + unsafe { core::hint::unreachable_unchecked() }; }); ErrorData::Simple(kind) } - TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()), + TAG_SIMPLE_MESSAGE => { + // SAFETY: per tag + unsafe { ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()) } + } TAG_CUSTOM => { // It would be correct for us to use `ptr::byte_sub` here (see the // comment above the `wrapping_add` call in `new_custom` for why), diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 97b72f9664bb..1345a30361e2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -382,11 +382,11 @@ pub(crate) unsafe fn append_to_string(buf: &mut String, f: F) -> Result) -> Result, { - let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; + let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } }; let ret = f(g.buf); // SAFETY: the caller promises to only append data to `buf` - let appended = g.buf.get_unchecked(g.len..); + let appended = unsafe { g.buf.get_unchecked(g.len..) }; if str::from_utf8(appended).is_err() { ret.and_then(|_| Err(Error::INVALID_UTF8)) } else { @@ -1256,8 +1256,6 @@ impl<'a> IoSliceMut<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSliceMut; /// use std::ops::Deref; /// @@ -1268,7 +1266,7 @@ impl<'a> IoSliceMut<'a> { /// buf.advance(3); /// assert_eq!(buf.deref(), [1; 5].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance(&mut self, n: usize) { self.0.advance(n) @@ -1290,8 +1288,6 @@ impl<'a> IoSliceMut<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSliceMut; /// use std::ops::Deref; /// @@ -1309,7 +1305,7 @@ impl<'a> IoSliceMut<'a> { /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) { // Number of buffers to remove. @@ -1400,8 +1396,6 @@ impl<'a> IoSlice<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSlice; /// use std::ops::Deref; /// @@ -1412,7 +1406,7 @@ impl<'a> IoSlice<'a> { /// buf.advance(3); /// assert_eq!(buf.deref(), [1; 5].as_ref()); /// ``` - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance(&mut self, n: usize) { self.0.advance(n) @@ -1434,8 +1428,6 @@ impl<'a> IoSlice<'a> { /// # Examples /// /// ``` - /// #![feature(io_slice_advance)] - /// /// use std::io::IoSlice; /// use std::ops::Deref; /// @@ -1452,7 +1444,7 @@ impl<'a> IoSlice<'a> { /// IoSlice::advance_slices(&mut bufs, 10); /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - #[unstable(feature = "io_slice_advance", issue = "62726")] + #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) { // Number of buffers to remove. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 66aeb35aceec..d4d68c2068d8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -252,6 +252,7 @@ #![allow(internal_features)] #![deny(rustc::existing_doc_keyword)] #![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] @@ -664,7 +665,7 @@ pub mod alloc; mod panicking; #[path = "../../backtrace/src/lib.rs"] -#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)] +#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)] mod backtrace_rs; // Re-export macros defined in core. diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/darwin/fs.rs similarity index 98% rename from library/std/src/os/macos/fs.rs rename to library/std/src/os/darwin/fs.rs index 573426d1a864..2032cca311a1 100644 --- a/library/std/src/os/macos/fs.rs +++ b/library/std/src/os/darwin/fs.rs @@ -1,4 +1,4 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] +#![allow(dead_code)] use crate::fs::{self, Metadata}; use crate::sealed::Sealed; @@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; #[allow(deprecated)] -use crate::os::macos::raw; +use super::raw; /// OS-specific extensions to [`fs::Metadata`]. /// @@ -70,6 +70,7 @@ pub trait MetadataExt { fn st_gen(&self) -> u32; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_lspare(&self) -> u32; + #[cfg(target_os = "macos")] #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_qspare(&self) -> [u64; 2]; } @@ -143,6 +144,7 @@ impl MetadataExt for Metadata { fn st_lspare(&self) -> u32 { self.as_inner().as_inner().st_lspare as u32 } + #[cfg(target_os = "macos")] fn st_qspare(&self) -> [u64; 2] { let qspare = self.as_inner().as_inner().st_qspare; [qspare[0] as u64, qspare[1] as u64] diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs new file mode 100644 index 000000000000..03401fe8895b --- /dev/null +++ b/library/std/src/os/darwin/mod.rs @@ -0,0 +1,20 @@ +//! Platform-specific extensions to `std` 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. + +pub(crate) mod fs; +// 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. +pub(super) mod raw; diff --git a/library/std/src/os/ios/raw.rs b/library/std/src/os/darwin/raw.rs similarity index 87% rename from library/std/src/os/ios/raw.rs rename to library/std/src/os/darwin/raw.rs index af12aeebe5d0..047727f45325 100644 --- a/library/std/src/os/ios/raw.rs +++ b/library/std/src/os/darwin/raw.rs @@ -1,15 +1,4 @@ -//! iOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - +//! Apple-specific raw type definitions use crate::os::raw::c_long; #[stable(feature = "raw_ext", since = "1.1.0")] @@ -35,6 +24,7 @@ pub type pthread_t = usize; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(dead_code)] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] pub st_dev: i32, diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs deleted file mode 100644 index e5df4de0b7f7..000000000000 --- a/library/std/src/os/ios/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use super::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/ios/mod.rs b/library/std/src/os/ios/mod.rs index fdefa1f6b21c..5e130d77b7bf 100644 --- a/library/std/src/os/ios/mod.rs +++ b/library/std/src/os/ios/mod.rs @@ -2,5 +2,29 @@ #![stable(feature = "raw_ext", since = "1.1.0")] -pub mod fs; -pub mod raw; +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub mod fs { + #[doc(inline)] + #[stable(feature = "file_set_times", since = "1.75.0")] + pub use crate::os::darwin::fs::FileTimesExt; + + #[doc(inline)] + #[stable(feature = "metadata_ext", since = "1.1.0")] + pub use crate::os::darwin::fs::MetadataExt; +} + +/// iOS-specific raw type definitions +#[stable(feature = "raw_ext", since = "1.1.0")] +#[deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#[allow(deprecated)] +pub mod raw { + #[doc(inline)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub use crate::os::darwin::raw::*; +} diff --git a/library/std/src/os/macos/mod.rs b/library/std/src/os/macos/mod.rs index 791d703b142c..3638406b1807 100644 --- a/library/std/src/os/macos/mod.rs +++ b/library/std/src/os/macos/mod.rs @@ -2,5 +2,29 @@ #![stable(feature = "raw_ext", since = "1.1.0")] -pub mod fs; -pub mod raw; +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub mod fs { + #[doc(inline)] + #[stable(feature = "file_set_times", since = "1.75.0")] + pub use crate::os::darwin::fs::FileTimesExt; + + #[doc(inline)] + #[stable(feature = "metadata_ext", since = "1.1.0")] + pub use crate::os::darwin::fs::MetadataExt; +} + +/// macOS-specific raw type definitions +#[stable(feature = "raw_ext", since = "1.1.0")] +#[deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#[allow(deprecated)] +pub mod raw { + #[doc(inline)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub use crate::os::darwin::raw::*; +} diff --git a/library/std/src/os/macos/raw.rs b/library/std/src/os/macos/raw.rs deleted file mode 100644 index 0b21f6ee5e49..000000000000 --- a/library/std/src/os/macos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! macOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index d2a7b316b813..020a8b324f41 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -2,6 +2,7 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, nonstandard_style, missing_debug_implementations)] +#![allow(unsafe_op_in_unsafe_fn)] pub mod raw; @@ -14,7 +15,7 @@ pub mod raw; // documented don't compile (missing things in `libc` which is empty), // so just omit them with an empty module and add the "unstable" attribute. -// Unix, linux, wasi and windows are handled a bit differently. +// unix, linux, wasi and windows are handled a bit differently. #[cfg(all( doc, any( @@ -104,6 +105,8 @@ pub mod windows; pub mod aix; #[cfg(target_os = "android")] pub mod android; +#[cfg(target_vendor = "apple")] +pub(crate) mod darwin; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "emscripten")] @@ -144,19 +147,12 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; -#[cfg(target_os = "tvos")] -#[path = "ios/mod.rs"] -pub(crate) mod tvos; #[cfg(target_os = "uefi")] pub mod uefi; -#[cfg(target_os = "visionos")] -pub(crate) mod visionos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] pub mod vxworks; -#[cfg(target_os = "watchos")] -pub(crate) mod watchos; #[cfg(target_os = "xous")] pub mod xous; diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index d7a622012a5a..c6581b9c4c8c 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -41,6 +41,8 @@ mod platform { pub use crate::os::aix::*; #[cfg(target_os = "android")] pub use crate::os::android::*; + #[cfg(target_vendor = "apple")] + pub(super) use crate::os::darwin::*; #[cfg(target_os = "dragonfly")] pub use crate::os::dragonfly::*; #[cfg(target_os = "emscripten")] @@ -59,14 +61,10 @@ mod platform { pub use crate::os::hurd::*; #[cfg(target_os = "illumos")] pub use crate::os::illumos::*; - #[cfg(target_os = "ios")] - pub use crate::os::ios::*; #[cfg(target_os = "l4re")] pub use crate::os::l4re::*; #[cfg(target_os = "linux")] pub use crate::os::linux::*; - #[cfg(target_os = "macos")] - pub use crate::os::macos::*; #[cfg(target_os = "netbsd")] pub use crate::os::netbsd::*; #[cfg(target_os = "nto")] @@ -77,16 +75,10 @@ mod platform { pub use crate::os::redox::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; - #[cfg(target_os = "tvos")] - pub use crate::os::tvos::*; - #[cfg(target_os = "visionos")] - pub use crate::os::visionos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] pub use crate::os::vxworks::*; - #[cfg(target_os = "watchos")] - pub use crate::os::watchos::*; } pub mod ffi; diff --git a/library/std/src/os/visionos/fs.rs b/library/std/src/os/visionos/fs.rs deleted file mode 100644 index e5df4de0b7f7..000000000000 --- a/library/std/src/os/visionos/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use super::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/visionos/mod.rs b/library/std/src/os/visionos/mod.rs deleted file mode 100644 index f4b061ffda89..000000000000 --- a/library/std/src/os/visionos/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! visionos-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod fs; -pub mod raw; diff --git a/library/std/src/os/visionos/raw.rs b/library/std/src/os/visionos/raw.rs deleted file mode 100644 index 2b3eca6f493d..000000000000 --- a/library/std/src/os/visionos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! visionos-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/library/std/src/os/watchos/fs.rs b/library/std/src/os/watchos/fs.rs deleted file mode 100644 index ee215dd59844..000000000000 --- a/library/std/src/os/watchos/fs.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::{self, Metadata}; -use crate::sealed::Sealed; -use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; -use crate::time::SystemTime; - -#[allow(deprecated)] -use crate::os::watchos::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: crate::fs::Metadata -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - -/// OS-specific extensions to [`fs::FileTimes`]. -#[stable(feature = "file_set_times", since = "1.75.0")] -pub trait FileTimesExt: Sealed { - /// Set the creation time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - fn set_created(self, t: SystemTime) -> Self; -} - -#[stable(feature = "file_set_times", since = "1.75.0")] -impl FileTimesExt for fs::FileTimes { - fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self - } -} diff --git a/library/std/src/os/watchos/mod.rs b/library/std/src/os/watchos/mod.rs deleted file mode 100644 index cd6454ebbf99..000000000000 --- a/library/std/src/os/watchos/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! watchOS-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod fs; -pub mod raw; diff --git a/library/std/src/os/watchos/raw.rs b/library/std/src/os/watchos/raw.rs deleted file mode 100644 index 630a533d9aaf..000000000000 --- a/library/std/src/os/watchos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! watchOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] - -use crate::os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 770583a9ce3e..343cc6e4a8a5 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -159,10 +159,12 @@ fn stdio_handle(raw: RawHandle) -> RawHandle { impl FromRawHandle for fs::File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - let handle = handle as sys::c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( - OwnedHandle::from_raw_handle(handle), - ))) + unsafe { + let handle = handle as sys::c::HANDLE; + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } } } @@ -260,24 +262,30 @@ impl AsRawSocket for net::UdpSocket { impl FromRawSocket for net::TcpStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::UdpSocket { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + } } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 6ffdf907c8ed..4334d041439d 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -76,7 +76,7 @@ impl BorrowedSocket<'_> { #[stable(feature = "io_safety", since = "1.63.0")] pub const unsafe fn borrow_raw(socket: RawSocket) -> Self { assert!(socket != sys::c::INVALID_SOCKET as RawSocket); - Self { socket, _phantom: PhantomData } + unsafe { Self { socket, _phantom: PhantomData } } } } @@ -201,8 +201,10 @@ impl IntoRawSocket for OwnedSocket { impl FromRawSocket for OwnedSocket { #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { - debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); - Self { socket } + unsafe { + debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket); + Self { socket } + } } } diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 52eb3b7c0676..f452403ee842 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -24,6 +24,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] +#![deny(unsafe_op_in_unsafe_fn)] pub mod ffi; pub mod fs; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 05ffb8925a1f..3927b2ed9bb5 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -16,7 +16,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = sys::handle::Handle::from_raw_handle(handle as *mut _); + let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; let io = sys::process::Stdio::Handle(handle); process::Stdio::from_inner(io) } @@ -407,7 +407,7 @@ impl CommandExt for process::Command { attribute: usize, value: T, ) -> &mut process::Command { - self.as_inner_mut().raw_attribute(attribute, value); + unsafe { self.as_inner_mut().raw_attribute(attribute, value) }; self } } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ebd054156951..418a855fb728 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -253,16 +253,20 @@ fn default_hook(info: &PanicHookInfo<'_>) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut dyn crate::io::Write| { + // Use a lock to prevent mixed output in multithreading context. + // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. + let mut lock = backtrace::lock(); let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); match backtrace { + // SAFETY: we took out a lock just a second ago. Some(BacktraceStyle::Short) => { - drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Short)) + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short)) } Some(BacktraceStyle::Full) => { - drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full)) + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full)) } Some(BacktraceStyle::Off) => { if FIRST_PANIC.swap(false, Ordering::Relaxed) { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f351dab78dc1..fc86578a5ff2 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -96,9 +96,9 @@ //! child processes must agree on how the commandline string is encoded. //! //! Most programs use the standard C run-time `argv`, which in practice results -//! in consistent argument handling. However some programs have their own way of +//! in consistent argument handling. However, some programs have their own way of //! parsing the commandline string. In these cases using [`arg`] or [`args`] may -//! result in the child process seeing a different array of arguments then the +//! result in the child process seeing a different array of arguments than the //! parent process intended. //! //! Two ways of mitigating this are: diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 63455a274faa..055601d03079 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -385,29 +385,25 @@ fn test_interior_nul_in_env_value_is_error() { #[cfg(windows)] fn test_creation_flags() { use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, DWORD, INFINITE}; - #[repr(C, packed)] + use crate::sys::c::{BOOL, INFINITE}; + #[repr(C)] struct DEBUG_EVENT { - pub event_code: DWORD, - pub process_id: DWORD, - pub thread_id: DWORD, + pub event_code: u32, + pub process_id: u32, + pub thread_id: u32, // This is a union in the real struct, but we don't // need this data for the purposes of this test. pub _junk: [u8; 164], } extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent( - dwProcessId: DWORD, - dwThreadId: DWORD, - dwContinueStatus: DWORD, - ) -> BOOL; + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL; + fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL; } - const DEBUG_PROCESS: DWORD = 1; - const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; - const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + const DEBUG_PROCESS: u32 = 1; + const EXIT_PROCESS_DEBUG_EVENT: u32 = 5; + const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; let mut child = Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap(); diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index b03fa1c01f26..d030017cfb4e 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -90,13 +90,14 @@ macro_rules! rtunwrap { // `compiler/rustc_session/src/config/sigpipe.rs`. #[cfg_attr(test, allow(dead_code))] unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { + #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] unsafe { - sys::init(argc, argv, sigpipe); + sys::init(argc, argv, sigpipe) + }; - // Set up the current thread to give it the right name. - let thread = Thread::new_main(); - thread::set_current(thread); - } + // Set up the current thread to give it the right name. + let thread = Thread::new_main(); + thread::set_current(thread); } // One-time runtime cleanup. @@ -144,6 +145,9 @@ fn lang_start_internal( rtabort!("drop of the panic payload panicked"); }); panic::catch_unwind(cleanup).map_err(rt_abort)?; + // Guard against multple threads calling `libc::exit` concurrently. + // See the documentation for `unique_thread_exit` for more information. + panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?; ret_code } diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index f9f83fb4f63c..08d46f356d9f 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -35,6 +35,7 @@ impl WaitTimeoutResult { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// + /// # let handle = /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// @@ -58,6 +59,8 @@ impl WaitTimeoutResult { /// break /// } /// } + /// # // Prevent leaks for Miri. + /// # let _ = handle.join(); /// ``` #[must_use] #[stable(feature = "wait_timeout", since = "1.5.0")] diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index b70c041fa428..18906aceffa3 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -107,7 +107,7 @@ impl T> LazyLock { /// # Examples /// /// ``` - /// #![feature(lazy_cell_consume)] + /// #![feature(lazy_cell_into_inner)] /// /// use std::sync::LazyLock; /// @@ -118,7 +118,7 @@ impl T> LazyLock { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "125623")] + #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 492e21d9bdb6..185319add745 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -200,11 +200,12 @@ impl Channel { return Err(msg); } - let slot: &Slot = &*(token.array.slot as *const Slot); - // Write the message into the slot and update the stamp. - slot.msg.get().write(MaybeUninit::new(msg)); - slot.stamp.store(token.array.stamp, Ordering::Release); + unsafe { + let slot: &Slot = &*(token.array.slot as *const Slot); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.stamp.store(token.array.stamp, Ordering::Release); + } // Wake a sleeping receiver. self.receivers.notify(); @@ -291,11 +292,14 @@ impl Channel { return Err(()); } - let slot: &Slot = &*(token.array.slot as *const Slot); - // Read the message from the slot and update the stamp. - let msg = slot.msg.get().read().assume_init(); - slot.stamp.store(token.array.stamp, Ordering::Release); + let msg = unsafe { + let slot: &Slot = &*(token.array.slot as *const Slot); + + let msg = slot.msg.get().read().assume_init(); + slot.stamp.store(token.array.stamp, Ordering::Release); + msg + }; // Wake a sleeping sender. self.senders.notify(); @@ -471,7 +475,7 @@ impl Channel { false }; - self.discard_all_messages(tail); + unsafe { self.discard_all_messages(tail) }; disconnected } diff --git a/library/std/src/sync/mpmc/counter.rs b/library/std/src/sync/mpmc/counter.rs index a5a6bdc67f13..3478cf41dc9d 100644 --- a/library/std/src/sync/mpmc/counter.rs +++ b/library/std/src/sync/mpmc/counter.rs @@ -63,7 +63,7 @@ impl Sender { disconnect(&self.counter().chan); if self.counter().destroy.swap(true, Ordering::AcqRel) { - drop(Box::from_raw(self.counter)); + drop(unsafe { Box::from_raw(self.counter) }); } } } @@ -116,7 +116,7 @@ impl Receiver { disconnect(&self.counter().chan); if self.counter().destroy.swap(true, Ordering::AcqRel) { - drop(Box::from_raw(self.counter)); + drop(unsafe { Box::from_raw(self.counter) }); } } } diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 9e7148c716cd..edac7a0cb183 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -91,7 +91,7 @@ impl Block { // It is not necessary to set the `DESTROY` bit in the last slot because that slot has // begun destruction of the block. for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); + let slot = unsafe { (*this).slots.get_unchecked(i) }; // Mark the `DESTROY` bit if a thread is still using the slot. if slot.state.load(Ordering::Acquire) & READ == 0 @@ -103,7 +103,7 @@ impl Block { } // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); + drop(unsafe { Box::from_raw(this) }); } } @@ -265,9 +265,11 @@ impl Channel { // Write the message into the slot. let block = token.list.block as *mut Block; let offset = token.list.offset; - let slot = (*block).slots.get_unchecked(offset); - slot.msg.get().write(MaybeUninit::new(msg)); - slot.state.fetch_or(WRITE, Ordering::Release); + unsafe { + let slot = (*block).slots.get_unchecked(offset); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.state.fetch_or(WRITE, Ordering::Release); + } // Wake a sleeping receiver. self.receivers.notify(); @@ -369,19 +371,21 @@ impl Channel { // Read the message. let block = token.list.block as *mut Block; let offset = token.list.offset; - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let msg = slot.msg.get().read().assume_init(); + unsafe { + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let msg = slot.msg.get().read().assume_init(); - // Destroy the block if we've reached the end, or if another thread wanted to destroy but - // couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); + // Destroy the block if we've reached the end, or if another thread wanted to destroy but + // couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + Ok(msg) } - - Ok(msg) } /// Attempts to send a message into the channel. diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 1b82713edc74..6d1c9d64e7a7 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -103,9 +103,11 @@ impl Channel { return Err(msg); } - let packet = &*(token.zero.0 as *const Packet); - packet.msg.get().write(Some(msg)); - packet.ready.store(true, Ordering::Release); + unsafe { + let packet = &*(token.zero.0 as *const Packet); + packet.msg.get().write(Some(msg)); + packet.ready.store(true, Ordering::Release); + } Ok(()) } @@ -116,22 +118,24 @@ impl Channel { return Err(()); } - let packet = &*(token.zero.0 as *const Packet); + let packet = unsafe { &*(token.zero.0 as *const Packet) }; if packet.on_stack { // The message has been in the packet from the beginning, so there is no need to wait // for it. However, after reading the message, we need to set `ready` to `true` in // order to signal that the packet can be destroyed. - let msg = packet.msg.get().replace(None).unwrap(); + let msg = unsafe { packet.msg.get().replace(None) }.unwrap(); packet.ready.store(true, Ordering::Release); Ok(msg) } else { // Wait until the message becomes available, then read it and destroy the // heap-allocated packet. packet.wait_ready(); - let msg = packet.msg.get().replace(None).unwrap(); - drop(Box::from_raw(token.zero.0 as *mut Packet)); - Ok(msg) + unsafe { + let msg = packet.msg.get().replace(None).unwrap(); + drop(Box::from_raw(token.zero.0 as *mut Packet)); + Ok(msg) + } } } diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index fe243550606f..94955beaf37b 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -502,7 +502,7 @@ impl OnceLock { #[inline] unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); - (&*self.value.get()).assume_init_ref() + unsafe { (&*self.value.get()).assume_init_ref() } } /// # Safety @@ -511,7 +511,7 @@ impl OnceLock { #[inline] unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); - (&mut *self.value.get()).assume_init_mut() + unsafe { (&mut *self.value.get()).assume_init_mut() } } } diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index f7fe8eb1c7fd..042c439394e0 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -244,7 +244,9 @@ impl ReentrantLock { } unsafe fn increment_lock_count(&self) -> Option<()> { - *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; + unsafe { + *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; + } Some(()) } } diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index e0a8a7603d71..a4ec52a4abe6 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -578,7 +578,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { // successfully called from the same thread before instantiating this object. unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { - data: NonNull::new_unchecked(lock.data.get()), + data: unsafe { NonNull::new_unchecked(lock.data.get()) }, inner_lock: &lock.inner, }) } diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index 0b2338fd7de9..7401d8ce3208 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -7,44 +7,41 @@ use crate::fmt; use crate::io; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; -use crate::sync::{Mutex, PoisonError}; +use crate::sync::{Mutex, MutexGuard, PoisonError}; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -pub fn lock() -> impl Drop { +pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>); + +pub(crate) fn lock<'a>() -> BacktraceLock<'a> { static LOCK: Mutex<()> = Mutex::new(()); - LOCK.lock().unwrap_or_else(PoisonError::into_inner) + BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner)) } -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - // There are issues currently linking libbacktrace into tests, and in - // general during std's own unit tests we're not testing this path. In - // test mode immediately return here to optimize away any references to the - // libbacktrace symbols - if cfg!(test) { - return Ok(()); - } - - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also requires it, like `SymFromAddr` on Windows. - unsafe { - let _lock = lock(); - _print(w, format) - } -} - -unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - struct DisplayBacktrace { - format: PrintFmt, - } - impl fmt::Display for DisplayBacktrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - unsafe { _print_fmt(fmt, self.format) } +impl BacktraceLock<'_> { + /// Prints the current backtrace. + /// + /// NOTE: this function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. + pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + // There are issues currently linking libbacktrace into tests, and in + // general during std's own unit tests we're not testing this path. In + // test mode immediately return here to optimize away any references to the + // libbacktrace symbols + if cfg!(test) { + return Ok(()); } + + struct DisplayBacktrace { + format: PrintFmt, + } + impl fmt::Display for DisplayBacktrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { _print_fmt(fmt, self.format) } + } + } + write!(w, "{}", DisplayBacktrace { format }) } - write!(w, "{}", DisplayBacktrace { format }) } unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs new file mode 100644 index 000000000000..5a090f506661 --- /dev/null +++ b/library/std/src/sys/exit_guard.rs @@ -0,0 +1,72 @@ +cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + /// pthread_t is a pointer on some platforms, + /// so we wrap it in this to impl Send + Sync. + #[derive(Clone, Copy)] + #[repr(transparent)] + struct PThread(libc::pthread_t); + // Safety: pthread_t is safe to send between threads + unsafe impl Send for PThread {} + // Safety: pthread_t is safe to share between threads + unsafe impl Sync for PThread {} + /// Mitigation for + /// + /// On glibc, `libc::exit` has been observed to not always be thread-safe. + /// It is currently unclear whether that is a glibc bug or allowed by the standard. + /// To mitigate this problem, we ensure that only one + /// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before + /// calling `libc::exit` (or returning from `main`). + /// + /// Technically, this is not enough to ensure soundness, since other code directly calling + /// `libc::exit` will still race with this. + /// + /// *This function does not itself call `libc::exit`.* This is so it can also be used + /// to guard returning from `main`. + /// + /// This function will return only the first time it is called in a process. + /// + /// * If it is called again on the same thread as the first call, it will abort. + /// * If it is called again on a different thread, it will wait in a loop + /// (waiting for the process to exit). + #[cfg_attr(any(test, doctest), allow(dead_code))] + pub(crate) fn unique_thread_exit() { + let this_thread_id = unsafe { libc::pthread_self() }; + use crate::sync::{Mutex, PoisonError}; + static EXITING_THREAD_ID: Mutex> = Mutex::new(None); + let mut exiting_thread_id = + EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); + match *exiting_thread_id { + None => { + // This is the first thread to call `unique_thread_exit`, + // and this is the first time it is called. + // Set EXITING_THREAD_ID to this thread's ID and return. + *exiting_thread_id = Some(PThread(this_thread_id)); + }, + Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => { + // This is the first thread to call `unique_thread_exit`, + // but this is the second time it is called. + // Abort the process. + core::panicking::panic_nounwind("std::process::exit called re-entrantly") + } + Some(_) => { + // This is not the first thread to call `unique_thread_exit`. + // Pause until the process exits. + drop(exiting_thread_id); + loop { + // Safety: libc::pause is safe to call. + unsafe { libc::pause(); } + } + } + } + } + } else { + /// Mitigation for + /// + /// Mitigation is ***NOT*** implemented on this platform, either because this platform + /// is not affected, or because mitigation is not yet implemented for this platform. + #[cfg_attr(any(test, doctest), allow(dead_code))] + pub(crate) fn unique_thread_exit() { + // Mitigation not required on platforms where `exit` is thread-safe. + } + } +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8aa35c40fe05..e50758ce00d8 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,3 +1,5 @@ +#![allow(unsafe_op_in_unsafe_fn)] + /// The PAL (platform abstraction layer) contains platform-specific abstractions /// for implementing the features in the other submodules, e.g. UNIX file /// descriptors. @@ -7,6 +9,7 @@ mod personality; pub mod backtrace; pub mod cmath; +pub mod exit_guard; pub mod os_str; pub mod path; pub mod sync; diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 8c75ac652998..df0176244489 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -94,36 +94,5 @@ cfg_if::cfg_if! { } } -// Solaris/Illumos requires a wrapper around log, log2, and log10 functions -// because of their non-standard behavior (e.g., log(-n) returns -Inf instead -// of expected NaN). -#[cfg(not(test))] -#[cfg(any(target_os = "solaris", target_os = "illumos"))] -#[inline] -pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { - if n.is_finite() { - if n > 0.0 { - log_fn(n) - } else if n == 0.0 { - f64::NEG_INFINITY // log(0) = -Inf - } else { - f64::NAN // log(-n) = NaN - } - } else if n.is_nan() { - n // log(NaN) = NaN - } else if n > 0.0 { - n // log(Inf) = Inf - } else { - f64::NAN // log(-Inf) = NaN - } -} - -#[cfg(not(test))] -#[cfg(not(any(target_os = "solaris", target_os = "illumos")))] -#[inline] -pub fn log_wrapper f64>(n: f64, log_fn: F) -> f64 { - log_fn(n) -} - #[cfg(not(target_os = "uefi"))] pub type RawOsError = i32; diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index f9d6b5fbc86a..8308a48f16a9 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -2010,56 +2010,10 @@ mod remove_dir_impl { use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::{cvt, cvt_r}; - #[cfg(not(any( - all(target_os = "linux", target_env = "gnu"), - all(target_os = "macos", not(target_arch = "aarch64")) - )))] + #[cfg(not(all(target_os = "linux", target_env = "gnu")))] use libc::{fdopendir, openat, unlinkat}; #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{fdopendir, openat64 as openat, unlinkat}; - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - use macos_weak::{fdopendir, openat, unlinkat}; - - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - mod macos_weak { - use crate::sys::weak::weak; - use libc::{c_char, c_int, DIR}; - - fn get_openat_fn() -> Option c_int> { - weak!(fn openat(c_int, *const c_char, c_int) -> c_int); - openat.get() - } - - pub fn has_openat() -> bool { - get_openat_fn().is_some() - } - - pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { - get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - -1 - }) - } - - pub unsafe fn fdopendir(fd: c_int) -> *mut DIR { - #[cfg(all(target_os = "macos", target_arch = "x86"))] - weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64$UNIX2003"); - #[cfg(all(target_os = "macos", target_arch = "x86_64"))] - weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); - fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - crate::ptr::null_mut() - }) - } - - pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { - weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); - unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| { - crate::sys::pal::unix::os::set_errno(libc::ENOSYS); - -1 - }) - } - } pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { let fd = cvt_r(|| unsafe { @@ -2172,19 +2126,7 @@ mod remove_dir_impl { } } - #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64"))))] pub fn remove_dir_all(p: &Path) -> io::Result<()> { remove_dir_all_modern(p) } - - #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))] - pub fn remove_dir_all(p: &Path) -> io::Result<()> { - if macos_weak::has_openat() { - // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() - remove_dir_all_modern(p) - } else { - // fall back to classic implementation - crate::sys_common::fs::remove_dir_all(p) - } - } } diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index 6d9532f2ef1f..fb928c76fbd0 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -1,7 +1,7 @@ use crate::assert_matches::assert_matches; use crate::os::fd::{AsRawFd, RawFd}; -use crate::os::linux::process::{ChildExt, CommandExt}; -use crate::os::unix::process::ExitStatusExt; +use crate::os::linux::process::{ChildExt, CommandExt as _}; +use crate::os::unix::process::{CommandExt as _, ExitStatusExt}; use crate::process::Command; #[test] @@ -21,6 +21,7 @@ fn test_command_pidfd() { let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); assert!(flags & libc::FD_CLOEXEC != 0); } + assert!(child.id() > 0 && child.id() < -1i32 as u32); let status = child.wait().expect("error waiting on pidfd"); assert_eq!(status.code(), Some(1)); @@ -42,6 +43,17 @@ fn test_command_pidfd() { .unwrap() .pidfd() .expect_err("pidfd should not have been created"); + + // exercise the fork/exec path since the earlier attempts may have used pidfd_spawnp() + let mut child = + unsafe { Command::new("false").pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap(); + + assert!(child.id() > 0 && child.id() < -1i32 as u32); + + if pidfd_open_available { + assert!(child.pidfd().is_ok()) + } + child.wait().expect("error waiting on child"); } #[test] diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 16fc2011d708..262f9c704a88 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -305,10 +305,13 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } +/// Convert native return values to Result using the *-1 means error is in `errno`* convention. +/// Non-error values are `Ok`-wrapped. pub fn cvt(t: T) -> crate::io::Result { if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } } +/// `-1` → look at `errno` → retry on `EINTR`. Otherwise `Ok()`-wrap the closure return value. pub fn cvt_r(mut f: F) -> crate::io::Result where T: IsMinusOne, @@ -323,6 +326,7 @@ where } #[allow(dead_code)] // Not used on all platforms. +/// Zero means `Ok()`, all other values are treated as raw OS errors. Does not look at `errno`. pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 40e2d1403ef5..9adc2b94e599 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -758,6 +758,7 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { + crate::sys::exit_guard::unique_thread_exit(); unsafe { libc::exit(code as c_int) } } diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 32382d9a50cf..abd4a334783e 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -449,17 +449,82 @@ impl Command { use crate::mem::MaybeUninit; use crate::sys::weak::weak; use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used}; + #[cfg(target_os = "linux")] + use core::sync::atomic::{AtomicU8, Ordering}; if self.get_gid().is_some() || self.get_uid().is_some() || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() || self.get_groups().is_some() - || self.get_create_pidfd() { return Ok(None); } + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + weak! { + fn pidfd_spawnp( + *mut libc::c_int, + *const libc::c_char, + *const libc::posix_spawn_file_actions_t, + *const libc::posix_spawnattr_t, + *const *mut libc::c_char, + *const *mut libc::c_char + ) -> libc::c_int + } + + weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } + + static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0); + const UNKNOWN: u8 = 0; + const SPAWN: u8 = 1; + // Obtaining a pidfd via the fork+exec path might work + const FORK_EXEC: u8 = 2; + // Neither pidfd_spawn nor fork/exec will get us a pidfd. + // Instead we'll just posix_spawn if the other preconditions are met. + const NO: u8 = 3; + + if self.get_create_pidfd() { + let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed); + if support == FORK_EXEC { + return Ok(None); + } + if support == UNKNOWN { + support = NO; + let our_pid = crate::process::id(); + let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int); + match pidfd { + Ok(pidfd) => { + support = FORK_EXEC; + if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) { + if pidfd_spawnp.get().is_some() && pid as u32 == our_pid { + support = SPAWN + } + } + unsafe { libc::close(pidfd) }; + } + Err(e) if e.raw_os_error() == Some(libc::EMFILE) => { + // We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail + // Don't update the support flag so we can probe again later. + return Err(e) + } + _ => {} + } + PIDFD_SUPPORTED.store(support, Ordering::Relaxed); + if support == FORK_EXEC { + return Ok(None); + } + } + core::assert_matches::debug_assert_matches!(support, SPAWN | NO); + } + } else { + if self.get_create_pidfd() { + unreachable!("only implemented on linux") + } + } + } + // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. #[cfg(all(target_os = "linux", target_env = "gnu"))] { @@ -543,9 +608,6 @@ impl Command { let pgroup = self.get_pgroup(); - // Safety: -1 indicates we don't have a pidfd. - let mut p = unsafe { Process::new(0, -1) }; - struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit); impl Drop for PosixSpawnFileActions<'_> { @@ -640,6 +702,47 @@ impl Command { #[cfg(target_os = "nto")] let spawn_fn = retrying_libc_posix_spawnp; + #[cfg(target_os = "linux")] + if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN { + let mut pidfd: libc::c_int = -1; + let spawn_res = pidfd_spawnp.get().unwrap()( + &mut pidfd, + self.get_program_cstr().as_ptr(), + file_actions.0.as_ptr(), + attrs.0.as_ptr(), + self.get_argv().as_ptr() as *const _, + envp as *const _, + ); + + let spawn_res = cvt_nz(spawn_res); + if let Err(ref e) = spawn_res + && e.raw_os_error() == Some(libc::ENOSYS) + { + PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed); + return Ok(None); + } + spawn_res?; + + let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) { + Ok(pid) => pid, + Err(e) => { + // The child has been spawned and we are holding its pidfd. + // But we cannot obtain its pid even though pidfd_getpid support was verified earlier. + // This might happen if libc can't open procfs because the file descriptor limit has been reached. + libc::close(pidfd); + return Err(Error::new( + e.kind(), + "pidfd_spawnp succeeded but the child's PID could not be obtained", + )); + } + }; + + return Ok(Some(Process::new(pid, pidfd))); + } + + // Safety: -1 indicates we don't have a pidfd. + let mut p = Process::new(0, -1); + let spawn_res = spawn_fn( &mut p.pid, self.get_program_cstr().as_ptr(), @@ -786,6 +889,12 @@ pub struct Process { impl Process { #[cfg(target_os = "linux")] + /// # Safety + /// + /// `pidfd` must either be -1 (representing no file descriptor) or a valid, exclusively owned file + /// descriptor (See [I/O Safety]). + /// + /// [I/O Safety]: crate::io#io-safety unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self { use crate::os::unix::io::FromRawFd; use crate::sys_common::FromInner; diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 24c237b5eb03..9f0194492b0a 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -4,7 +4,7 @@ use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering}; -use crate::sys::c; +use crate::sys::c::{self, windows_targets}; use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN}; use core::mem::MaybeUninit; @@ -15,76 +15,73 @@ mod tests; // See https://docs.microsoft.com/windows/win32/api/heapapi/ // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed. -const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008; +const HEAP_ZERO_MEMORY: u32 = 0x00000008; -#[link(name = "kernel32")] -extern "system" { - // Get a handle to the default heap of the current process, or null if the operation fails. - // - // SAFETY: Successful calls to this function within the same process are assumed to - // always return the same handle, which remains valid for the entire lifetime of the process. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap - fn GetProcessHeap() -> c::HANDLE; +// Get a handle to the default heap of the current process, or null if the operation fails. +// +// SAFETY: Successful calls to this function within the same process are assumed to +// always return the same handle, which remains valid for the entire lifetime of the process. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap +windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE); - // Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`. - // The allocated memory may be uninitialized, or zeroed if `dwFlags` is - // set to `HEAP_ZERO_MEMORY`. - // - // Returns a pointer to the newly-allocated memory or null if the operation fails. - // The returned pointer will be aligned to at least `MIN_ALIGN`. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`. - // - // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc - fn HeapAlloc(hHeap: c::HANDLE, dwFlags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID; +// Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`. +// The allocated memory may be uninitialized, or zeroed if `dwFlags` is +// set to `HEAP_ZERO_MEMORY`. +// +// Returns a pointer to the newly-allocated memory or null if the operation fails. +// The returned pointer will be aligned to at least `MIN_ALIGN`. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`. +// +// Note that `dwBytes` is allowed to be zero, contrary to some other allocators. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc +windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void); - // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, - // to a block of at least `dwBytes` bytes, either shrinking the block in place, - // or allocating at a new location, copying memory, and freeing the original location. - // - // Returns a pointer to the reallocated memory or null if the operation fails. - // The returned pointer will be aligned to at least `MIN_ALIGN`. - // If the operation fails the given block will never have been freed. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to zero. - // - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or - // `HeapReAlloc`, that has not already been freed. - // If the block was successfully reallocated at a new location, pointers pointing to - // the freed memory, such as `lpMem`, must not be dereferenced ever again. - // - // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc - fn HeapReAlloc( - hHeap: c::HANDLE, - dwFlags: c::DWORD, - lpMem: c::LPVOID, - dwBytes: c::SIZE_T, - ) -> c::LPVOID; +// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, +// to a block of at least `dwBytes` bytes, either shrinking the block in place, +// or allocating at a new location, copying memory, and freeing the original location. +// +// Returns a pointer to the reallocated memory or null if the operation fails. +// The returned pointer will be aligned to at least `MIN_ALIGN`. +// If the operation fails the given block will never have been freed. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to zero. +// - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or +// `HeapReAlloc`, that has not already been freed. +// If the block was successfully reallocated at a new location, pointers pointing to +// the freed memory, such as `lpMem`, must not be dereferenced ever again. +// +// Note that `dwBytes` is allowed to be zero, contrary to some other allocators. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc +windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( + hheap: c::HANDLE, + dwflags : u32, + lpmem: *const core::ffi::c_void, + dwbytes: usize +) -> *mut core::ffi::c_void); - // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. - // Returns a nonzero value if the operation is successful, and zero if the operation fails. - // - // SAFETY: - // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. - // - `dwFlags` must be set to zero. - // - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`, - // that has not already been freed. - // If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`, - // must not be dereferenced ever again. - // - // Note that `lpMem` is allowed to be null, which will not cause the operation to fail. - // - // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree - fn HeapFree(hHeap: c::HANDLE, dwFlags: c::DWORD, lpMem: c::LPVOID) -> c::BOOL; -} +// Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. +// Returns a nonzero value if the operation is successful, and zero if the operation fails. +// +// SAFETY: +// - `hHeap` must be a non-null handle returned by `GetProcessHeap`. +// - `dwFlags` must be set to zero. +// - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`, +// that has not already been freed. +// If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`, +// must not be dereferenced ever again. +// +// Note that `lpMem` is allowed to be null, which will not cause the operation to fail. +// +// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree +windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL); // Cached handle to the default heap of the current process. // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. @@ -116,9 +113,9 @@ fn init_or_get_process_heap() -> c::HANDLE { #[cold] extern "C" fn process_heap_init_and_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc` - flags: c::DWORD, - dwBytes: c::SIZE_T, -) -> c::LPVOID { + flags: u32, + dwBytes: usize, +) -> *mut c_void { let heap = init_or_get_process_heap(); if core::intrinsics::unlikely(heap.is_null()) { return ptr::null_mut(); @@ -130,9 +127,9 @@ extern "C" fn process_heap_init_and_alloc( #[inline(never)] fn process_heap_alloc( _heap: MaybeUninit, // We pass this argument to match the ABI of `HeapAlloc`, - flags: c::DWORD, - dwBytes: c::SIZE_T, -) -> c::LPVOID { + flags: u32, + dwBytes: usize, +) -> *mut c_void { let heap = HEAP.load(Ordering::Relaxed); if core::intrinsics::likely(!heap.is_null()) { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. @@ -243,7 +240,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `block` is a pointer to the start of an allocated block. - unsafe { HeapFree(heap, 0, block as c::LPVOID) }; + unsafe { HeapFree(heap, 0, block.cast::()) }; } #[inline] @@ -256,7 +253,7 @@ unsafe impl GlobalAlloc for System { // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, // `ptr` is a pointer to the start of an allocated block. // The returned pointer points to the start of an allocated block. - unsafe { HeapReAlloc(heap, 0, ptr as c::LPVOID, new_size) as *mut u8 } + unsafe { HeapReAlloc(heap, 0, ptr.cast::(), new_size).cast::() } } else { // SAFETY: `realloc_fallback` is implemented using `dealloc` and `alloc`, which will // correctly handle `ptr` and return a pointer satisfying the guarantees of `System` diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 17a0e47ad595..00c816a6c09b 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -227,8 +227,10 @@ pub fn set_file_information_by_handle( info: *const c_void, size: u32, ) -> Result<(), WinError> { - let result = c::SetFileInformationByHandle(handle, class, info, size); - (result != 0).then_some(()).ok_or_else(get_last_error) + unsafe { + let result = c::SetFileInformationByHandle(handle, class, info, size); + (result != 0).then_some(()).ok_or_else(get_last_error) + } } // SAFETY: The `SetFileInformation` trait ensures that this is safe. unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 27aa35f69f1b..296d19a926d9 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -4,44 +4,23 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] +#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::mem; -use crate::num::NonZero; -pub use crate::os::raw::c_int; -use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; -mod windows_targets; +pub(super) mod windows_targets; mod windows_sys; pub use windows_sys::*; -pub type DWORD = c_ulong; -pub type NonZeroDWORD = NonZero; -pub type LARGE_INTEGER = c_longlong; -#[cfg_attr(target_vendor = "uwp", allow(unused))] -pub type LONG = c_long; -pub type UINT = c_uint; pub type WCHAR = u16; -pub type USHORT = c_ushort; -pub type SIZE_T = usize; -pub type CHAR = c_char; -pub type ULONG = c_ulong; - -pub type LPCVOID = *const c_void; -pub type LPOVERLAPPED = *mut OVERLAPPED; -pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; -pub type LPVOID = *mut c_void; -pub type LPWCH = *mut WCHAR; -pub type LPWSTR = *mut WCHAR; - -#[cfg(target_vendor = "win7")] -pub type PSRWLOCK = *mut SRWLOCK; pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = USHORT; +pub type ADDRESS_FAMILY = c_ushort; pub use FD_SET as fd_set; pub use LINGER as linger; pub use TIMEVAL as timeval; @@ -151,25 +130,25 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [CHAR; 6], + pub __ss_pad1: [c_char; 6], pub __ss_align: i64, - pub __ss_pad2: [CHAR; 112], + pub __ss_pad2: [c_char; 112], } #[repr(C)] #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_family: ADDRESS_FAMILY, - pub sin_port: USHORT, + pub sin_port: c_ushort, pub sin_addr: in_addr, - pub sin_zero: [CHAR; 8], + pub sin_zero: [c_char; 8], } #[repr(C)] #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: USHORT, + pub sin6_port: c_ushort, pub sin6_flowinfo: c_ulong, pub sin6_addr: in6_addr, pub sin6_scope_id: c_ulong, @@ -271,9 +250,9 @@ pub unsafe fn NtReadFile( apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, - length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, - key: Option<&ULONG>, + length: u32, + byteoffset: Option<&i64>, + key: Option<&u32>, ) -> NTSTATUS { windows_sys::NtReadFile( filehandle.as_raw_handle(), @@ -294,9 +273,9 @@ pub unsafe fn NtWriteFile( apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, - length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, - key: Option<&ULONG>, + length: u32, + byteoffset: Option<&i64>, + key: Option<&u32>, ) -> NTSTATUS { windows_sys::NtWriteFile( filehandle.as_raw_handle(), @@ -336,13 +315,13 @@ compat_fn_with_fallback! { // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } // >= Win8 / Server 2012 @@ -403,27 +382,27 @@ compat_fn_with_fallback! { #[cfg(target_vendor = "win7")] pub fn NtCreateKeyedEvent( KeyedEventHandle: *mut HANDLE, - DesiredAccess: DWORD, - ObjectAttributes: LPVOID, - Flags: ULONG + DesiredAccess: u32, + ObjectAttributes: *mut c_void, + Flags: u32 ) -> NTSTATUS { panic!("keyed events not available") } #[cfg(target_vendor = "win7")] pub fn NtReleaseKeyedEvent( EventHandle: HANDLE, - Key: LPVOID, + Key: *const c_void, Alertable: BOOLEAN, - Timeout: *mut c_longlong + Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") } #[cfg(target_vendor = "win7")] pub fn NtWaitForKeyedEvent( EventHandle: HANDLE, - Key: LPVOID, + Key: *const c_void, Alertable: BOOLEAN, - Timeout: *mut c_longlong + Timeout: *mut i64 ) -> NTSTATUS { panic!("keyed events not available") } @@ -453,9 +432,9 @@ compat_fn_with_fallback! { apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *mut crate::mem::MaybeUninit, - length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, - key: Option<&ULONG> + length: u32, + byteoffset: Option<&i64>, + key: Option<&u32> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } @@ -467,9 +446,9 @@ compat_fn_with_fallback! { apccontext: *mut c_void, iostatusblock: &mut IO_STATUS_BLOCK, buffer: *const u8, - length: ULONG, - byteoffset: Option<&LARGE_INTEGER>, - key: Option<&ULONG> + length: u32, + byteoffset: Option<&i64>, + key: Option<&u32> ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs index 56c563462d36..252bceb70942 100644 --- a/library/std/src/sys/pal/windows/c/windows_targets.rs +++ b/library/std/src/sys/pal/windows/c/windows_targets.rs @@ -3,6 +3,18 @@ //! This is a simple wrapper around an `extern` block with a `#[link]` attribute. //! It's very roughly equivalent to the windows-targets crate. +#[cfg(feature = "windows_raw_dylib")] +pub macro link { + ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] + #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] + extern $abi { + $(#[link_name=$link_name])? + pub fn $($function)*; + } + ) +} +#[cfg(not(feature = "windows_raw_dylib"))] pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't @@ -17,6 +29,7 @@ pub macro link { ) } +#[cfg(not(feature = "windows_raw_dylib"))] #[link(name = "advapi32")] #[link(name = "ntdll")] #[link(name = "userenv")] diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index f5d57a28db69..49fa1603f3e1 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -112,8 +112,10 @@ impl Module { /// (e.g. kernel32 and ntdll). pub unsafe fn new(name: &CStr) -> Option { // SAFETY: A CStr is always null terminated. - let module = c::GetModuleHandleA(name.as_ptr().cast::()); - NonNull::new(module).map(Self) + unsafe { + let module = c::GetModuleHandleA(name.as_ptr().cast::()); + NonNull::new(module).map(Self) + } } // Try to get the address of a function. diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index cc68f5ef5f08..85fd9153d537 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use core::ptr::addr_of; use crate::os::windows::prelude::*; @@ -28,12 +29,12 @@ pub struct File { #[derive(Clone)] pub struct FileAttr { - attributes: c::DWORD, + attributes: u32, creation_time: c::FILETIME, last_access_time: c::FILETIME, last_write_time: c::FILETIME, file_size: u64, - reparse_tag: c::DWORD, + reparse_tag: u32, volume_serial_number: Option, number_of_links: Option, file_index: Option, @@ -41,8 +42,8 @@ pub struct FileAttr { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType { - attributes: c::DWORD, - reparse_tag: c::DWORD, + attributes: u32, + reparse_tag: u32, } pub struct ReadDir { @@ -75,16 +76,16 @@ pub struct OpenOptions { create_new: bool, // system-specific custom_flags: u32, - access_mode: Option, - attributes: c::DWORD, - share_mode: c::DWORD, - security_qos_flags: c::DWORD, - security_attributes: c::LPSECURITY_ATTRIBUTES, + access_mode: Option, + attributes: u32, + share_mode: u32, + security_qos_flags: u32, + security_attributes: *mut c::SECURITY_ATTRIBUTES, } #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { - attrs: c::DWORD, + attrs: u32, } #[derive(Copy, Clone, Debug, Default)] @@ -241,11 +242,11 @@ impl OpenOptions { // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on. self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT; } - pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) { + pub fn security_attributes(&mut self, attrs: *mut c::SECURITY_ATTRIBUTES) { self.security_attributes = attrs; } - fn get_access_mode(&self) -> io::Result { + fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append, self.access_mode) { (.., Some(mode)) => Ok(mode), (true, false, false, None) => Ok(c::GENERIC_READ), @@ -261,7 +262,7 @@ impl OpenOptions { } } - fn get_creation_mode(&self) -> io::Result { + fn get_creation_mode(&self) -> io::Result { match (self.write, self.append) { (true, false) => {} (false, false) => { @@ -287,7 +288,7 @@ impl OpenOptions { }) } - fn get_flags_and_attributes(&self) -> c::DWORD { + fn get_flags_and_attributes(&self) -> u32 { self.custom_flags | self.attributes | self.security_qos_flags @@ -397,21 +398,21 @@ impl File { self.handle.as_raw_handle(), c::FileBasicInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; let mut attr = FileAttr { attributes: info.FileAttributes, creation_time: c::FILETIME { - dwLowDateTime: info.CreationTime as c::DWORD, - dwHighDateTime: (info.CreationTime >> 32) as c::DWORD, + dwLowDateTime: info.CreationTime as u32, + dwHighDateTime: (info.CreationTime >> 32) as u32, }, last_access_time: c::FILETIME { - dwLowDateTime: info.LastAccessTime as c::DWORD, - dwHighDateTime: (info.LastAccessTime >> 32) as c::DWORD, + dwLowDateTime: info.LastAccessTime as u32, + dwHighDateTime: (info.LastAccessTime >> 32) as u32, }, last_write_time: c::FILETIME { - dwLowDateTime: info.LastWriteTime as c::DWORD, - dwHighDateTime: (info.LastWriteTime >> 32) as c::DWORD, + dwLowDateTime: info.LastWriteTime as u32, + dwHighDateTime: (info.LastWriteTime >> 32) as u32, }, file_size: 0, reparse_tag: 0, @@ -425,7 +426,7 @@ impl File { self.handle.as_raw_handle(), c::FileStandardInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); @@ -495,7 +496,7 @@ impl File { SeekFrom::End(n) => (c::FILE_END, n), SeekFrom::Current(n) => (c::FILE_CURRENT, n), }; - let pos = pos as c::LARGE_INTEGER; + let pos = pos as i64; let mut newpos = 0; cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?; Ok(newpos as u64) @@ -511,7 +512,7 @@ impl File { fn reparse_point( &self, space: &mut Align8<[MaybeUninit]>, - ) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> { + ) -> io::Result<(u32, *mut c::REPARSE_DATA_BUFFER)> { unsafe { let mut bytes = 0; cvt({ @@ -524,7 +525,7 @@ impl File { ptr::null_mut(), 0, space.0.as_mut_ptr().cast(), - len as c::DWORD, + len as u32, &mut bytes, ptr::null_mut(), ) @@ -609,8 +610,7 @@ impl File { "Cannot set file timestamp to 0", )); } - let is_max = - |t: c::FILETIME| t.dwLowDateTime == c::DWORD::MAX && t.dwHighDateTime == c::DWORD::MAX; + let is_max = |t: c::FILETIME| t.dwLowDateTime == u32::MAX && t.dwHighDateTime == u32::MAX; if times.accessed.map_or(false, is_max) || times.modified.map_or(false, is_max) || times.created.map_or(false, is_max) @@ -641,7 +641,7 @@ impl File { self.handle.as_raw_handle(), c::FileBasicInfo, core::ptr::addr_of_mut!(info) as *mut c_void, - size as c::DWORD, + size as u32, ))?; Ok(info) } @@ -1020,7 +1020,7 @@ impl FileTimes { } impl FileType { - fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { + fn new(attrs: u32, reparse_tag: u32) -> FileType { FileType { attributes: attrs, reparse_tag } } pub fn is_dir(&self) -> bool { @@ -1417,16 +1417,16 @@ pub fn canonicalize(p: &Path) -> io::Result { pub fn copy(from: &Path, to: &Path) -> io::Result { unsafe extern "system" fn callback( - _TotalFileSize: c::LARGE_INTEGER, - _TotalBytesTransferred: c::LARGE_INTEGER, - _StreamSize: c::LARGE_INTEGER, - StreamBytesTransferred: c::LARGE_INTEGER, - dwStreamNumber: c::DWORD, - _dwCallbackReason: c::DWORD, + _TotalFileSize: i64, + _TotalBytesTransferred: i64, + _StreamSize: i64, + StreamBytesTransferred: i64, + dwStreamNumber: u32, + _dwCallbackReason: u32, _hSourceFile: c::HANDLE, _hDestinationFile: c::HANDLE, - lpData: c::LPCVOID, - ) -> c::DWORD { + lpData: *const c_void, + ) -> u32 { if dwStreamNumber == 1 { *(lpData as *mut i64) = StreamBytesTransferred; } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 3f85bb0a099a..ae9ea8ff584e 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -1,4 +1,5 @@ #![unstable(issue = "none", feature = "windows_handle")] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -141,7 +142,7 @@ impl Handle { buf: &mut [u8], overlapped: *mut c::OVERLAPPED, ) -> io::Result> { - let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; let mut amt = 0; let res = cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped)); @@ -209,12 +210,7 @@ impl Handle { Ok(Self(self.0.try_clone()?)) } - pub fn duplicate( - &self, - access: c::DWORD, - inherit: bool, - options: c::DWORD, - ) -> io::Result { + pub fn duplicate(&self, access: u32, inherit: bool, options: u32) -> io::Result { Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?)) } @@ -233,7 +229,7 @@ impl Handle { let mut io_status = c::IO_STATUS_BLOCK::PENDING; // The length is clamped at u32::MAX. - let len = cmp::min(len, c::DWORD::MAX as usize) as c::DWORD; + let len = cmp::min(len, u32::MAX as usize) as u32; let status = c::NtReadFile( self.as_handle(), ptr::null_mut(), @@ -281,7 +277,7 @@ impl Handle { let mut io_status = c::IO_STATUS_BLOCK::PENDING; // The length is clamped at u32::MAX. - let len = cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; let status = unsafe { c::NtWriteFile( self.as_handle(), diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 77b8f3c410eb..86d457db50a3 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::marker::PhantomData; use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; @@ -15,9 +16,9 @@ pub struct IoSlice<'a> { impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); + assert!(buf.len() <= u32::MAX as usize); IoSlice { - vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_ptr() as *mut u8 }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, _p: PhantomData, } } @@ -29,7 +30,7 @@ impl<'a> IoSlice<'a> { } unsafe { - self.vec.len -= n as c::ULONG; + self.vec.len -= n as u32; self.vec.buf = self.vec.buf.add(n); } } @@ -49,9 +50,9 @@ pub struct IoSliceMut<'a> { impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= c::ULONG::MAX as usize); + assert!(buf.len() <= u32::MAX as usize); IoSliceMut { - vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() }, + vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, _p: PhantomData, } } @@ -63,7 +64,7 @@ impl<'a> IoSliceMut<'a> { } unsafe { - self.vec.len -= n as c::ULONG; + self.vec.len -= n as u32; self.vec.buf = self.vec.buf.add(n); } } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 6406cec9c27d..b85a8318bcbb 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -1,4 +1,5 @@ #![allow(missing_docs, nonstandard_style)] +#![deny(unsafe_op_in_unsafe_fn)] use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; @@ -54,11 +55,13 @@ impl IoResult for Result { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { - stack_overflow::init(); + unsafe { + stack_overflow::init(); - // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already - // exists, we have to call it ourselves. - thread::Thread::set_name_wide(wide_str!("main")); + // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already + // exists, we have to call it ourselves. + thread::Thread::set_name_wide(wide_str!("main")); + } } // SAFETY: must be called only once during runtime cleanup. @@ -75,7 +78,7 @@ pub fn is_interrupted(_errno: i32) -> bool { pub fn decode_error_kind(errno: i32) -> ErrorKind { use ErrorKind::*; - match errno as c::DWORD { + match errno as u32 { c::ERROR_ACCESS_DENIED => return PermissionDenied, c::ERROR_ALREADY_EXISTS => return AlreadyExists, c::ERROR_FILE_EXISTS => return AlreadyExists, @@ -216,7 +219,7 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { // from this closure is then the return value of the function. pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result where - F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, + F1: FnMut(*mut u16, u32) -> u32, F2: FnOnce(&[u16]) -> T, { // Start off with a stack buf but then spill over to the heap if we end up @@ -238,7 +241,7 @@ where // We used `reserve` and not `reserve_exact`, so in theory we // may have gotten more than requested. If so, we'd like to use // it... so long as we won't cause overflow. - n = heap_buf.capacity().min(c::DWORD::MAX as usize); + n = heap_buf.capacity().min(u32::MAX as usize); // Safety: MaybeUninit does not need initialization heap_buf.set_len(n); &mut heap_buf[..] @@ -254,13 +257,13 @@ where // error" is still 0 then we interpret it as a 0 length buffer and // not an actual error. c::SetLastError(0); - let k = match f1(buf.as_mut_ptr().cast::(), n as c::DWORD) { + let k = match f1(buf.as_mut_ptr().cast::(), n as u32) { 0 if api::get_last_error().code == 0 => 0, 0 => return Err(crate::io::Error::last_os_error()), n => n, } as usize; if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER { - n = n.saturating_mul(2).min(c::DWORD::MAX as usize); + n = n.saturating_mul(2).min(u32::MAX as usize); } else if k > n { n = k; } else if k == n { @@ -308,7 +311,7 @@ pub fn cvt(i: I) -> crate::io::Result { if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) } } -pub fn dur2timeout(dur: Duration) -> c::DWORD { +pub fn dur2timeout(dur: Duration) -> u32 { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the // timeouts in windows APIs are typically u32 milliseconds. To translate, we // have two pieces to take care of: @@ -320,7 +323,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 })) - .map(|ms| if ms > ::MAX as u64 { c::INFINITE } else { ms as c::DWORD }) + .map(|ms| if ms > ::MAX as u64 { c::INFINITE } else { ms as u32 }) .unwrap_or(c::INFINITE) } diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 9e15b15a3513..d51fb56238f2 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -250,7 +250,7 @@ impl Socket { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nread = 0; let mut flags = 0; let result = unsafe { @@ -335,7 +335,7 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nwritten = 0; let result = unsafe { c::WSASend( @@ -371,7 +371,7 @@ impl Socket { } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = net::getsockopt(self, c::SOL_SOCKET, kind)?; if raw == 0 { Ok(None) } else { @@ -436,7 +436,7 @@ impl Socket { pub unsafe fn from_raw(raw: c::SOCKET) -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert_eq!(mem::align_of::(), mem::align_of::()); - Self::from_raw_socket(raw as RawSocket) + unsafe { Self::from_raw_socket(raw as RawSocket) } } } @@ -486,6 +486,6 @@ impl IntoRawSocket for Socket { impl FromRawSocket for Socket { unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self { - Self(FromRawSocket::from_raw_socket(raw_socket)) + unsafe { Self(FromRawSocket::from_raw_socket(raw_socket)) } } } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 62199c16bfed..0a9279e50ba1 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,6 +1,7 @@ //! Implementation of `std::os` functionality for Windows. #![allow(nonstandard_style)] +#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -52,10 +53,10 @@ pub fn error_string(mut errnum: i32) -> String { let res = c::FormatMessageW( flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, module, - errnum as c::DWORD, + errnum as u32, 0, buf.as_mut_ptr(), - buf.len() as c::DWORD, + buf.len() as u32, ptr::null(), ) as usize; if res == 0 { @@ -81,7 +82,7 @@ pub fn error_string(mut errnum: i32) -> String { } pub struct Env { - base: c::LPWCH, + base: *mut c::WCHAR, iter: EnvIterator, } @@ -126,7 +127,7 @@ impl Iterator for Env { } #[derive(Clone)] -struct EnvIterator(c::LPWCH); +struct EnvIterator(*mut c::WCHAR); impl Iterator for EnvIterator { type Item = (OsString, OsString); @@ -383,7 +384,7 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { - unsafe { c::ExitProcess(code as c::UINT) } + unsafe { c::ExitProcess(code as u32) } } pub fn getpid() -> u32 { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 67ef3ca82da0..d8b785f027c7 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::os::windows::prelude::*; use crate::ffi::OsStr; @@ -156,7 +157,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res opts.share_mode(0); let size = mem::size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, + nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), bInheritHandle: their_handle_inheritable as i32, }; @@ -225,9 +226,9 @@ fn random_number() -> usize { // Abstracts over `ReadFileEx` and `WriteFileEx` type AlertableIoFn = unsafe extern "system" fn( BorrowedHandle<'_>, - c::LPVOID, - c::DWORD, - c::LPOVERLAPPED, + *mut core::ffi::c_void, + u32, + *mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE, ) -> c::BOOL; @@ -244,7 +245,7 @@ impl AnonPipe { pub fn read(&self, buf: &mut [u8]) -> io::Result { let result = unsafe { - let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len) }; @@ -260,7 +261,7 @@ impl AnonPipe { pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { let result = unsafe { - let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32; self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) }; @@ -295,7 +296,7 @@ impl AnonPipe { pub fn write(&self, buf: &[u8]) -> io::Result { unsafe { - let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; + let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len) } } @@ -327,8 +328,8 @@ impl AnonPipe { unsafe fn alertable_io_internal( &self, io: AlertableIoFn, - buf: c::LPVOID, - len: c::DWORD, + buf: *mut core::ffi::c_void, + len: u32, ) -> io::Result { // Use "alertable I/O" to synchronize the pipe I/O. // This has four steps. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index c62764696b86..76d2cb77d474 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -19,7 +19,7 @@ use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Mutex; use crate::sys::args::{self, Arg}; -use crate::sys::c::{self, NonZeroDWORD, EXIT_FAILURE, EXIT_SUCCESS}; +use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; use crate::sys::cvt; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; @@ -174,7 +174,7 @@ pub struct Command { pub enum Stdio { Inherit, - InheritSpecific { from_stdio_id: c::DWORD }, + InheritSpecific { from_stdio_id: u32 }, Null, MakePipe, Pipe(AnonPipe), @@ -364,7 +364,7 @@ impl Command { }; si_ptr = core::ptr::addr_of_mut!(si_ex) as _; } else { - si.cb = mem::size_of::() as c::DWORD; + si.cb = mem::size_of::() as u32; si_ptr = core::ptr::addr_of_mut!(si) as _; } @@ -566,7 +566,7 @@ fn program_exists(path: &Path) -> Option> { } impl Stdio { - fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option) -> io::Result { + fn to_handle(&self, stdio_id: u32, pipe: &mut Option) -> io::Result { let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) { Ok(io) => unsafe { let io = Handle::from_raw_handle(io); @@ -601,7 +601,7 @@ impl Stdio { Stdio::Null => { let size = mem::size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, + nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), bInheritHandle: 1, }; @@ -713,11 +713,11 @@ impl Process { } #[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] -pub struct ExitStatus(c::DWORD); +pub struct ExitStatus(u32); impl ExitStatus { pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - match NonZeroDWORD::try_from(self.0) { + match NonZero::::try_from(self.0) { /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), /* was zero, couldn't convert */ Err(_) => Ok(()), } @@ -727,9 +727,9 @@ impl ExitStatus { } } -/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying. -impl From for ExitStatus { - fn from(u: c::DWORD) -> ExitStatus { +/// Converts a raw `u32` to a type-safe `ExitStatus` by wrapping it without copying. +impl From for ExitStatus { + fn from(u: u32) -> ExitStatus { ExitStatus(u) } } @@ -750,7 +750,7 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatusError(c::NonZeroDWORD); +pub struct ExitStatusError(NonZero); impl Into for ExitStatusError { fn into(self) -> ExitStatus { @@ -765,7 +765,7 @@ impl ExitStatusError { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(c::DWORD); +pub struct ExitCode(u32); impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); @@ -779,13 +779,13 @@ impl ExitCode { impl From for ExitCode { fn from(code: u8) -> Self { - ExitCode(c::DWORD::from(code)) + ExitCode(u32::from(code)) } } impl From for ExitCode { fn from(code: u32) -> Self { - ExitCode(c::DWORD::from(code)) + ExitCode(u32::from(code)) } } diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs index 09f527a09bf1..e366bb995626 100644 --- a/library/std/src/sys/pal/windows/rand.rs +++ b/library/std/src/sys/pal/windows/rand.rs @@ -20,7 +20,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { - c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as c::ULONG) + c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as u32) }; if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) } diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index f93f31026f81..ea89429cb83c 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -1,4 +1,5 @@ #![cfg_attr(test, allow(dead_code))] +#![allow(unsafe_op_in_unsafe_fn)] use crate::sys::c; use crate::thread; @@ -11,7 +12,7 @@ pub unsafe fn reserve_stack() { debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); } -unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG { +unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 { unsafe { let rec = &(*(*ExceptionInfo).ExceptionRecord); let code = rec.ExceptionCode; diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 10aeeac07ea2..c6a21665157d 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -68,7 +68,7 @@ const MAX_BUFFER_SIZE: usize = 8192; // UTF-16 to UTF-8. pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3; -pub fn get_handle(handle_id: c::DWORD) -> io::Result { +pub fn get_handle(handle_id: u32) -> io::Result { let handle = unsafe { c::GetStdHandle(handle_id) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) @@ -87,11 +87,7 @@ fn is_console(handle: c::HANDLE) -> bool { unsafe { c::GetConsoleMode(handle, &mut mode) != 0 } } -fn write( - handle_id: c::DWORD, - data: &[u8], - incomplete_utf8: &mut IncompleteUtf8, -) -> io::Result { +fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result { if data.is_empty() { return Ok(0); } @@ -182,12 +178,12 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result]) -> io::Result() as c::ULONG, + nLength: crate::mem::size_of::() as u32, nInitialChars: 0, dwCtrlWakeupMask: CTRL_Z_MASK, dwControlKeyState: 0, @@ -355,7 +351,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result]) -> io::Result io::Result { - debug_assert!(utf16.len() <= c::c_int::MAX as usize); - debug_assert!(utf8.len() <= c::c_int::MAX as usize); + debug_assert!(utf16.len() <= i32::MAX as usize); + debug_assert!(utf8.len() <= i32::MAX as usize); if utf16.is_empty() { return Ok(0); @@ -390,9 +386,9 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { c::CP_UTF8, // CodePage c::WC_ERR_INVALID_CHARS, // dwFlags utf16.as_ptr(), // lpWideCharStr - utf16.len() as c::c_int, // cchWideChar + utf16.len() as i32, // cchWideChar utf8.as_mut_ptr(), // lpMultiByteStr - utf8.len() as c::c_int, // cbMultiByte + utf8.len() as i32, // cbMultiByte ptr::null(), // lpDefaultChar ptr::null_mut(), // lpUsedDefaultChar ) diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 70099e0a3b56..3648272a343a 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -1,3 +1,4 @@ +#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::io; use crate::num::NonZero; @@ -45,7 +46,7 @@ impl Thread { Err(io::Error::last_os_error()) }; - unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { + unsafe extern "system" fn thread_start(main: *mut c_void) -> u32 { // Next, reserve some stack space for if we otherwise run out of stack. stack_overflow::reserve_stack(); // Finally, let's run some code. diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 09e78a29304f..b853daeffebd 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -76,8 +76,8 @@ impl SystemTime { fn from_intervals(intervals: i64) -> SystemTime { SystemTime { t: c::FILETIME { - dwLowDateTime: intervals as c::DWORD, - dwHighDateTime: (intervals >> 32) as c::DWORD, + dwLowDateTime: intervals as u32, + dwHighDateTime: (intervals >> 32) as u32, }, } } @@ -172,7 +172,7 @@ mod perf_counter { use crate::time::Duration; pub struct PerformanceCounterInstant { - ts: c::LARGE_INTEGER, + ts: i64, } impl PerformanceCounterInstant { pub fn now() -> Self { @@ -196,7 +196,7 @@ mod perf_counter { } } - fn frequency() -> c::LARGE_INTEGER { + fn frequency() -> i64 { // Either the cached result of `QueryPerformanceFrequency` or `0` for // uninitialized. Storing this as a single `AtomicU64` allows us to use // `Relaxed` operations, as we are only interested in the effects on a @@ -206,7 +206,7 @@ mod perf_counter { let cached = FREQUENCY.load(Ordering::Relaxed); // If a previous thread has filled in this global state, use that. if cached != 0 { - return cached as c::LARGE_INTEGER; + return cached as i64; } // ... otherwise learn for ourselves ... let mut frequency = 0; @@ -218,8 +218,8 @@ mod perf_counter { frequency } - fn query() -> c::LARGE_INTEGER { - let mut qpc_value: c::LARGE_INTEGER = 0; + fn query() -> i64 { + let mut qpc_value: i64 = 0; cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap(); qpc_value } diff --git a/library/std/src/sys/sync/mutex/windows7.rs b/library/std/src/sys/sync/mutex/windows7.rs index ef2f84082cd5..689dba10f01e 100644 --- a/library/std/src/sys/sync/mutex/windows7.rs +++ b/library/std/src/sys/sync/mutex/windows7.rs @@ -25,7 +25,7 @@ unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} #[inline] -pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { +pub unsafe fn raw(m: &Mutex) -> *mut c::SRWLOCK { m.srwlock.get() } diff --git a/library/std/src/sys/sync/thread_parking/windows.rs b/library/std/src/sys/sync/thread_parking/windows.rs index 4b8102d505a1..3a8d40dc5cfa 100644 --- a/library/std/src/sys/sync/thread_parking/windows.rs +++ b/library/std/src/sys/sync/thread_parking/windows.rs @@ -64,6 +64,7 @@ use crate::sync::atomic::{ }; use crate::sys::{c, dur2timeout}; use crate::time::Duration; +use core::ffi::c_void; pub struct Parker { state: AtomicI8, @@ -117,7 +118,7 @@ impl Parker { loop { // Wait for something to happen, assuming it's still set to PARKED. - c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as *const c_void, 1, c::INFINITE); // Change NOTIFIED=>EMPTY but leave PARKED alone. if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { // Actually woken up by unpark(). @@ -144,7 +145,7 @@ impl Parker { } // Wait for something to happen, assuming it's still set to PARKED. - c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as *const c_void, 1, dur2timeout(timeout)); // Set the state back to EMPTY (from either PARKED or NOTIFIED). // Note that we don't just write EMPTY, but use swap() to also // include an acquire-ordered read to synchronize with unpark()'s @@ -177,8 +178,8 @@ impl Parker { } } - fn ptr(&self) -> c::LPVOID { - core::ptr::addr_of!(self.state) as c::LPVOID + fn ptr(&self) -> *const c_void { + core::ptr::addr_of!(self.state).cast::() } } diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index 81797f55170d..f6cd457046ff 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -65,6 +65,7 @@ use crate::ptr; use crate::sys::c; +use core::ffi::c_void; pub fn enable() { // When destructors are used, we don't want LLVM eliminating CALLBACK for any @@ -74,9 +75,9 @@ pub fn enable() { #[link_section = ".CRT$XLB"] #[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section` -pub static CALLBACK: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = tls_callback; +pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback; -unsafe extern "system" fn tls_callback(_h: c::LPVOID, dw_reason: c::DWORD, _pv: c::LPVOID) { +unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) { // See comments above for what this is doing. Note that we don't need this // trickery on GNU windows, just on MSVC. #[cfg(all(target_env = "msvc", not(target_thread_local)))] diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index baf23979c7c6..8b43e558d5d9 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -33,11 +33,11 @@ use crate::sync::atomic::{ use crate::sys::c; use crate::sys::thread_local::guard; -pub type Key = c::DWORD; +pub type Key = u32; type Dtor = unsafe extern "C" fn(*mut u8); pub struct LazyKey { - /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX + /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == u32::MAX /// is not a valid key value, this allows us to use zero as sentinel value /// without risking overflow. key: AtomicU32, diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 117a3e23044e..6aeeb6259285 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -602,7 +602,8 @@ impl Wtf8 { /// marked unsafe. #[inline] pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - mem::transmute(value) + // SAFETY: start with &[u8], end with fancy &[u8] + unsafe { &*(value as *const [u8] as *const Wtf8) } } /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. @@ -611,7 +612,8 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - mem::transmute(value) + // SAFETY: start with &mut [u8], end with fancy &mut [u8] + unsafe { &mut *(value as *mut [u8] as *mut Wtf8) } } /// Returns the length, in WTF-8 bytes. @@ -942,8 +944,12 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) { /// Copied from core::str::raw::slice_unchecked #[inline] pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // memory layout of a &[u8] and &Wtf8 are the same - Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin)) + // SAFETY: memory layout of a &[u8] and &Wtf8 are the same + unsafe { + let len = end - begin; + let start = s.as_bytes().as_ptr().add(begin); + Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len)) + } } /// Copied from core::str::raw::slice_error_fail diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 1ddacd92e6b9..169eeeca8c2e 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -27,3 +27,4 @@ profiler = ["std/profiler"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] std_detect_env_override = ["std/std_detect_env_override"] +windows_raw_dylib = ["std/windows_raw_dylib"] diff --git a/rustfmt.toml b/rustfmt.toml index b15ffdca38a0..e060fd8fe8bf 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -22,6 +22,8 @@ ignore = [ "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui-fulldeps/", # Some are whitespace-sensitive (e.g. `// ~ERROR` comments). + # #[cfg(bootstrap)] so that t-release sees this when they search for it + "/tests/rustdoc-json/impl-trait-precise-capturing.rs", # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index c095127da140..de0924c0f423 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -48,7 +48,6 @@ dependencies = [ "clap_complete", "cmake", "fd-lock", - "filetime", "home", "ignore", "junction", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index df7b5b881931..f723407c3ce3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,7 +44,6 @@ build_helper = { path = "../tools/build_helper" } clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.4" fd-lock = "4.0" -filetime = "0.2" home = "0.5" ignore = "0.4" libc = "0.2" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index fb3c86270430..0ac58645d2df 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -1,7 +1,7 @@ -# rustbuild - Bootstrapping Rust +# Bootstrapping Rust This README is aimed at helping to explain how Rust is bootstrapped, -and some of the technical details of the build system. +and some of the technical details of the bootstrap build system. Note that this README only covers internal information, not how to use the tool. Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information. @@ -12,17 +12,17 @@ Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further info The build system defers most of the complicated logic of managing invocations of rustc and rustdoc to Cargo itself. However, moving through various stages -and copying artifacts is still necessary for it to do. Each time rustbuild +and copying artifacts is still necessary for it to do. Each time bootstrap is invoked, it will iterate through the list of predefined steps and execute each serially in turn if it matches the paths passed or is a default rule. -For each step, rustbuild relies on the step internally being incremental and -parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded +For each step, bootstrap relies on the step internally being incremental and +parallel. Note, though, that the `-j` parameter to bootstrap gets forwarded to appropriate test harnesses and such. ## Build phases -The rustbuild build system goes through a few phases to actually build the -compiler. What actually happens when you invoke rustbuild is: +Bootstrap build system goes through a few phases to actually build the +compiler. What actually happens when you invoke bootstrap is: 1. The entry point script (`x` for unix like systems, `x.ps1` for windows systems, `x.py` cross-platform) is run. This script is responsible for downloading the stage0 @@ -151,9 +151,9 @@ build/ stage3/ ``` -## Extending rustbuild +## Extending bootstrap -When you use the bootstrap system, you'll call it through the entry point script +When you use bootstrap, you'll call it through the entry point script (`x`, `x.ps1`, or `x.py`). However, most of the code lives in `src/bootstrap`. `bootstrap` has a difficult problem: it is written in Rust, but yet it is run before the Rust compiler is built! To work around this, there are two components diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7e47b373ff9d..4e8e0fd2532f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1038,7 +1038,7 @@ class RustBuild(object): def check_vendored_status(self): """Check that vendoring is configured properly""" - # keep this consistent with the equivalent check in rustbuild: + # keep this consistent with the equivalent check in bootstrap: # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405 if 'SUDO_USER' in os.environ and not self.use_vendored_sources: if os.getuid() == 0: diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index cab37e0da473..7e38a0996e59 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -20,7 +20,7 @@ all: $(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS) help: - $(Q)echo 'Welcome to the rustbuild build system!' + $(Q)echo 'Welcome to bootstrap, the Rust build system!' $(Q)echo $(Q)echo This makefile is a thin veneer over the ./x.py script located $(Q)echo in this directory. To get the full power of the build system @@ -58,9 +58,8 @@ check-aux: library/core \ library/alloc \ --no-doc - # Some doctests have intentional memory leaks. - # Some use file system operations to demonstrate dealing with `Result`. - $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + # Some doctests use file system operations to demonstrate dealing with `Result`. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ library/alloc \ @@ -70,7 +69,7 @@ check-aux: $(BOOTSTRAP) miri --stage 2 library/std \ --no-doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: - $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ --doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 44fb1911fc6d..a7d21ba6ae12 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -1,4 +1,4 @@ -//! rustbuild, the Rust build system +//! bootstrap, the Rust build system //! //! This is the entry point for the build system used to compile the `rustc` //! compiler. Lots of documentation can be found in the `README.md` file in the diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11a7a4045351..ba2ad53a94ea 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1,7 +1,7 @@ //! Implementation of compiling various phases of the compiler and standard //! library. //! -//! This module contains some of the real meat in the rustbuild build system +//! This module contains some of the real meat in the bootstrap build system //! which is where Cargo is used to compile the standard library, libtest, and //! the compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. @@ -14,7 +14,7 @@ use std::fs; use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Stdio; use std::str; use serde_derive::Deserialize; @@ -33,7 +33,6 @@ use crate::utils::helpers::{ }; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; -use filetime::FileTime; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { @@ -696,10 +695,10 @@ fn copy_sanitizers( || target == "x86_64-apple-ios" { // Update the library’s install name to reflect that it has been renamed. - apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name)); + apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name)); // Upon renaming the install name, the code signature of the file will invalidate, // so we will sign it again. - apple_darwin_sign_file(&dst); + apple_darwin_sign_file(builder, &dst); } target_deps.push(dst); @@ -708,25 +707,17 @@ fn copy_sanitizers( target_deps } -fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) { - let status = Command::new("install_name_tool") - .arg("-id") - .arg(new_name) - .arg(library_path) - .status() - .expect("failed to execute `install_name_tool`"); - assert!(status.success()); +fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) { + command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder); } -fn apple_darwin_sign_file(file_path: &Path) { - let status = Command::new("codesign") +fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) { + command("codesign") .arg("-f") // Force to rewrite the existing signature .arg("-s") .arg("-") .arg(file_path) - .status() - .expect("failed to execute `codesign`"); - assert!(status.success()); + .run(builder); } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -818,8 +809,8 @@ pub struct Rustc { pub compiler: Compiler, /// Whether to build a subset of crates, rather than the whole compiler. /// - /// This should only be requested by the user, not used within rustbuild itself. - /// Using it within rustbuild can lead to confusing situation where lints are replayed + /// This should only be requested by the user, not used within bootstrap itself. + /// Using it within bootstrap can lead to confusing situation where lints are replayed /// in two different steps. crates: Vec, } @@ -1172,7 +1163,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_profile_generate && target.is_msvc() { if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { // Add clang's runtime library directory to the search path - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); } } @@ -1213,8 +1204,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_use_libcxx { cargo.env("LLVM_USE_LIBCXX", "1"); } - if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { - cargo.env("LLVM_NDEBUG", "1"); + if builder.config.llvm_assertions { + cargo.env("LLVM_ASSERTIONS", "1"); } } @@ -2080,7 +2071,8 @@ pub fn stream_cargo( tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { - let mut cargo = cargo.into_cmd().command; + let mut cmd = cargo.into_cmd(); + let cargo = cmd.as_command_mut(); // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { @@ -2160,9 +2152,11 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) return; } - let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap()); + let previous_mtime = t!(t!(path.metadata()).modified()); command("strip").capture().arg("--strip-debug").arg(path).run(builder); + let file = t!(fs::File::open(path)); + // After running `strip`, we have to set the file modification time to what it was before, // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time // bootstrap is invoked. @@ -2175,5 +2169,5 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) // In the second invocation of bootstrap, Cargo will see that the mtime of librustc_driver.so // is greater than the mtime of rustc-main, and will rebuild rustc-main. That will then cause // everything else (standard library, future stages...) to be rebuilt. - t!(filetime::set_file_mtime(path, previous_mtime)); + t!(file.set_modified(previous_mtime)); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7bc5405e92f9..1e9d2025bc78 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1060,11 +1060,7 @@ impl Step for PlainSourceTarball { cmd.arg("--sync").arg(manifest_path); } - let config = if !builder.config.dry_run() { - cmd.capture().run(builder).stdout() - } else { - String::new() - }; + let config = cmd.capture().run(builder).stdout(); let cargo_config_dir = plain_dst_src.join(".cargo"); builder.create_dir(&cargo_config_dir); @@ -2072,11 +2068,7 @@ fn maybe_install_llvm( let mut cmd = command(llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); - let files = if builder.config.dry_run() { - "".into() - } else { - cmd.capture_stdout().run(builder).stdout() - }; + let files = cmd.capture_stdout().run(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); for file in files.trim_end().split(' ') { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 4b35d6c5d4c9..633e66afe598 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1,4 +1,4 @@ -//! Documentation generation for rustbuilder. +//! Documentation generation for bootstrap. //! //! This module implements generation for all bits and pieces of documentation //! for the Rust project. This notably includes suites like the rust book, the @@ -146,7 +146,6 @@ impl Step for RustbookSrc

{ let out = out.join(&name); let index = out.join("index.html"); let rustbook = builder.tool_exe(Tool::Rustbook); - let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); if !builder.config.dry_run() && (!up_to_date(&src, &index) || !up_to_date(&rustbook, &index)) @@ -154,7 +153,13 @@ impl Step for RustbookSrc

{ builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); + builder + .tool_cmd(Tool::Rustbook) + .arg("build") + .arg(&src) + .arg("-d") + .arg(&out) + .run(builder); for lang in &self.languages { let out = out.join(lang); @@ -253,10 +258,6 @@ impl Step for TheBook { // build the version info page and CSS let shared_assets = builder.ensure(SharedAssets { target }); - // build the command first so we don't nest GHA groups - // FIXME: this doesn't do anything! - builder.rustdoc_cmd(compiler); - // build the redirect pages let _guard = builder.msg_doc(compiler, "book redirect pages", target); for file in t!(fs::read_dir(redirect_path)) { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 872823506f88..888290a0479b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -125,6 +125,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { generate_smart_stamp_hash( + builder, &builder.config.src.join("src/llvm-project"), builder.in_tree_llvm_info.sha().unwrap_or_default(), ) @@ -172,7 +173,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` config.src.join("src/version"), ]); - output(&mut rev_list.command).trim().to_owned() + output(rev_list.as_command_mut()).trim().to_owned() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { @@ -254,7 +255,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { // `true` here. let llvm_sha = detect_llvm_sha(config, true); let head_sha = - output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command); + output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut()); let head_sha = head_sha.trim(); llvm_sha == head_sha } @@ -912,7 +913,7 @@ impl Step for Lld { if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() { // Find clang's runtime library directory and push that as a search path to the // cmake linker flags. - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display())); } } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index e6a09e8cb8e8..226b3729c10c 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -8,6 +8,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; +use crate::utils::exec::command; use crate::utils::helpers::{self, hex_encode}; use crate::Config; use sha2::Digest; @@ -16,7 +17,6 @@ use std::fmt::Write as _; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; -use std::process::Command; use std::str::FromStr; use std::{fmt, fs, io}; @@ -266,20 +266,16 @@ impl Step for Link { } let stage_path = ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR); - if !rustup_installed() { + if !rustup_installed(builder) { eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() { - attempt_toolchain_link(&stage_path[..]); + attempt_toolchain_link(builder, &stage_path[..]); } } } -fn rustup_installed() -> bool { - Command::new("rustup") - .arg("--version") - .stdout(std::process::Stdio::null()) - .output() - .map_or(false, |output| output.status.success()) +fn rustup_installed(builder: &Builder<'_>) -> bool { + command("rustup").capture_stdout().arg("--version").run(builder).is_success() } fn stage_dir_exists(stage_path: &str) -> bool { @@ -289,8 +285,8 @@ fn stage_dir_exists(stage_path: &str) -> bool { } } -fn attempt_toolchain_link(stage_path: &str) { - if toolchain_is_linked() { +fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { + if toolchain_is_linked(builder) { return; } @@ -301,7 +297,7 @@ fn attempt_toolchain_link(stage_path: &str) { return; } - if try_link_toolchain(stage_path) { + if try_link_toolchain(builder, stage_path) { println!( "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); @@ -315,14 +311,16 @@ fn attempt_toolchain_link(stage_path: &str) { } } -fn toolchain_is_linked() -> bool { - match Command::new("rustup") +fn toolchain_is_linked(builder: &Builder<'_>) -> bool { + match command("rustup") + .capture_stdout() + .allow_failure() .args(["toolchain", "list"]) - .stdout(std::process::Stdio::piped()) - .output() + .run(builder) + .stdout_if_ok() { - Ok(toolchain_list) => { - if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") { + Some(toolchain_list) => { + if !toolchain_list.contains("stage1") { return false; } // The toolchain has already been linked. @@ -330,7 +328,7 @@ fn toolchain_is_linked() -> bool { "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" ); } - Err(_) => { + None => { // In this case, we don't know if the `stage1` toolchain has been linked; // but `rustup` failed, so let's not go any further. println!( @@ -341,12 +339,12 @@ fn toolchain_is_linked() -> bool { true } -fn try_link_toolchain(stage_path: &str) -> bool { - Command::new("rustup") - .stdout(std::process::Stdio::null()) +fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool { + command("rustup") + .capture_stdout() .args(["toolchain", "link", "stage1", stage_path]) - .output() - .map_or(false, |output| output.status.success()) + .run(builder) + .is_success() } fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool { @@ -476,20 +474,18 @@ impl Step for Hook { if config.dry_run() { return; } - t!(install_git_hook_maybe(config)); + t!(install_git_hook_maybe(builder, config)); } } // install a git hook to automatically run tidy, if they want -fn install_git_hook_maybe(config: &Config) -> io::Result<()> { +fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) + .capture() .args(["rev-parse", "--git-common-dir"]) - .command - .output() - .map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })?; + .run(builder) + .stdout(); + let git = PathBuf::from(git.trim()); let hooks_dir = git.join("hooks"); let dst = hooks_dir.join("pre-push"); if dst.exists() { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0b60587bb792..3f0cbde64e39 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -9,7 +9,6 @@ use std::ffi::OsString; use std::fs; use std::iter; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; use clap_complete::shells; @@ -169,12 +168,8 @@ You can skip linkcheck with --skip src/tools/linkchecker" } } -fn check_if_tidy_is_installed() -> bool { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) +fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool { + command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -188,8 +183,9 @@ impl Step for HtmlCheck { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; let run = run.path("src/tools/html-checker"); - run.lazy_default_condition(Box::new(check_if_tidy_is_installed)) + run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder))) } fn make_run(run: RunConfig<'_>) { @@ -197,7 +193,7 @@ impl Step for HtmlCheck { } fn run(self, builder: &Builder<'_>) { - if !check_if_tidy_is_installed() { + if !check_if_tidy_is_installed(builder) { eprintln!("not running HTML-check tool because `tidy` is missing"); eprintln!( "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager." @@ -471,16 +467,12 @@ impl Miri { // We re-use the `cargo` from above. cargo.arg("--print-sysroot"); - if builder.config.dry_run() { - String::new() - } else { - builder.verbose(|| println!("running: {cargo:?}")); - let stdout = cargo.capture_stdout().run(builder).stdout(); - // Output is "\n". - let sysroot = stdout.trim_end(); - builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); - sysroot.to_owned() - } + builder.verbose(|| println!("running: {cargo:?}")); + let stdout = cargo.capture_stdout().run(builder).stdout(); + // Output is "\n". + let sysroot = stdout.trim_end(); + builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + sysroot.to_owned() } } @@ -686,6 +678,8 @@ impl Step for CompiletestTest { let mut cargo = tool::prepare_tool_cargo( builder, compiler, + // compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks + // when std sources change. Mode::ToolStd, host, "test", @@ -1325,13 +1319,12 @@ impl Step for CrateRunMakeSupport { /// Runs `cargo test` for run-make-support. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(builder.top_stage, host); + let compiler = builder.compiler(0, host); - builder.ensure(compile::Std::new(compiler, host)); let mut cargo = tool::prepare_tool_cargo( builder, compiler, - Mode::ToolStd, + Mode::ToolBootstrap, host, "test", "src/tools/run-make-support", @@ -1352,6 +1345,52 @@ impl Step for CrateRunMakeSupport { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateBuildHelper { + host: TargetSelection, +} + +impl Step for CrateBuildHelper { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build_helper") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CrateBuildHelper { host: run.target }); + } + + /// Runs `cargo test` for build_helper. + fn run(self, builder: &Builder<'_>) { + let host = self.host; + let compiler = builder.compiler(0, host); + + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + host, + "test", + "src/tools/build_helper", + SourceType::InTree, + &[], + ); + cargo.allow_features("test"); + run_cargo_test( + cargo, + &[], + &[], + "build_helper", + "build_helper self test", + compiler, + host, + builder, + ); + } +} + default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); @@ -2056,9 +2095,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let git_config = builder.config.git_config(); cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); - - // FIXME: Move CiEnv back to bootstrap, it is only used here anyway - builder.ci_env.force_coloring_in_ci(&mut cmd.command); + cmd.force_coloring_in_ci(builder.ci_env); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( @@ -3001,7 +3038,7 @@ impl Step for Bootstrap { // https://github.com/rust-lang/rust/issues/49215 cmd.env("RUSTFLAGS", flags); } - // rustbuild tests are racy on directory creation so just run them one at a time. + // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder); } diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index e3e7931a5a2a..2ab0ce7454b1 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -99,24 +99,16 @@ fn print_error(tool: &str, submodule: &str) { crate::exit!(3); } -fn check_changed_files(toolstates: &HashMap, ToolState>) { +fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap, ToolState>) { // Changed files let output = helpers::git(None) + .capture() .arg("diff") .arg("--name-status") .arg("HEAD") .arg("HEAD^") - .command - .output(); - let output = match output { - Ok(o) => o, - Err(e) => { - eprintln!("Failed to get changed files: {e:?}"); - crate::exit!(1); - } - }; - - let output = t!(String::from_utf8(output.stdout)); + .run(builder) + .stdout(); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule)); @@ -186,8 +178,8 @@ impl Step for ToolStateCheck { crate::exit!(1); } - check_changed_files(&toolstates); - checkout_toolstate_repo(); + check_changed_files(builder, &toolstates); + checkout_toolstate_repo(builder); let old_toolstate = read_old_toolstate(); for (tool, _) in STABLE_TOOLS.iter() { @@ -231,7 +223,7 @@ impl Step for ToolStateCheck { } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { - commit_toolstate_change(&toolstates); + commit_toolstate_change(builder, &toolstates); } } @@ -315,50 +307,34 @@ fn toolstate_repo() -> String { const TOOLSTATE_DIR: &str = "rust-toolstate"; /// Checks out the toolstate repo into `TOOLSTATE_DIR`. -fn checkout_toolstate_repo() { +fn checkout_toolstate_repo(builder: &Builder<'_>) { if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") { - prepare_toolstate_config(&token); + prepare_toolstate_config(builder, &token); } if Path::new(TOOLSTATE_DIR).exists() { eprintln!("Cleaning old toolstate directory..."); t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = helpers::git(None) + helpers::git(None) .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) .arg(TOOLSTATE_DIR) - .command - .status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git clone unsuccessful (status: {status:?})"); - } + .run(builder); } /// Sets up config and authentication for modifying the toolstate repo. -fn prepare_toolstate_config(token: &str) { - fn git_config(key: &str, value: &str) { - let status = - helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git config key={key} value={value} failed (status: {status:?})"); - } +fn prepare_toolstate_config(builder: &Builder<'_>, token: &str) { + fn git_config(builder: &Builder<'_>, key: &str, value: &str) { + helpers::git(None).arg("config").arg("--global").arg(key).arg(value).run(builder); } // If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date // as well. - git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); - git_config("user.name", "Rust Toolstate Update"); - git_config("credential.helper", "store"); + git_config(builder, "user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); + git_config(builder, "user.name", "Rust Toolstate Update"); + git_config(builder, "credential.helper", "store"); let credential = format!("https://{token}:x-oauth-basic@github.com\n",); let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials"); @@ -398,55 +374,51 @@ fn read_old_toolstate() -> Vec { /// /// * See /// if a private email by GitHub is wanted. -fn commit_toolstate_change(current_toolstate: &ToolstateData) { +fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) { let message = format!("({} CI update)", OS.expect("linux/windows only")); let mut success = false; for _ in 1..=5 { // Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo. // This does *not* change the "current toolstate"; that only happens post-landing // via `src/ci/docker/publish_toolstate.sh`. - publish_test_results(current_toolstate); + publish_test_results(builder, current_toolstate); // `git commit` failing means nothing to commit. - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("commit") .arg("-a") .arg("-m") .arg(&message) - .command - .status()); - if !status.success() { + .run(builder); + if !status.is_success() { success = true; break; } - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("push") .arg("origin") .arg("master") - .command - .status()); + .run(builder); // If we successfully push, exit. - if status.success() { + if status.is_success() { success = true; break; } eprintln!("Sleeping for 3 seconds before retrying push"); std::thread::sleep(std::time::Duration::from_secs(3)); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("fetch") .arg("origin") .arg("master") - .command - .status()); - assert!(status.success()); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .run(builder); + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") - .command - .status()); - assert!(status.success()); + .run(builder); } if !success { @@ -459,9 +431,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// These results will later be promoted to `latest.json` by the /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. -fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output()); - let commit = t!(String::from_utf8(commit.stdout)); +fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) { + let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout(); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 65cc1fa74782..ebd62bb032f4 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -860,6 +860,7 @@ impl<'a> Builder<'a> { test::Clippy, test::CompiletestTest, test::CrateRunMakeSupport, + test::CrateBuildHelper, test::RustdocJSStd, test::RustdocJSNotStd, test::RustdocGUI, @@ -1626,11 +1627,11 @@ impl<'a> Builder<'a> { } // This tells Cargo (and in turn, rustc) to output more complete - // dependency information. Most importantly for rustbuild, this + // dependency information. Most importantly for bootstrap, this // includes sysroot artifacts, like libstd, which means that we don't - // need to track those in rustbuild (an error prone process!). This + // need to track those in bootstrap (an error prone process!). This // feature is currently unstable as there may be some bugs and such, but - // it represents a big improvement in rustbuild's reliability on + // it represents a big improvement in bootstrap's reliability on // rebuilds, so we're using it here. // // For some additional context, see #63470 (the PR originally adding @@ -1642,7 +1643,7 @@ impl<'a> Builder<'a> { // Restrict the allowed features so we don't depend on nightly // accidentally. // - // binary-dep-depinfo is used by rustbuild itself for all + // binary-dep-depinfo is used by bootstrap itself for all // compilations. // // Lots of tools depend on proc_macro2 and proc-macro-error. @@ -1997,6 +1998,9 @@ impl<'a> Builder<'a> { if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); + // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all + // of the individual lints are satisfied. + rustflags.arg("-Wkeyword_idents_2024"); } if self.config.rust_frame_pointers { @@ -2104,7 +2108,7 @@ impl<'a> Builder<'a> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - self.ci_env.force_coloring_in_ci(&mut cargo.command); + cargo.force_coloring_in_ci(self.ci_env); // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index aa119b8c6991..97c9ece0036e 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -266,7 +266,7 @@ mod defaults { // rustdoc/rustcc/std here (the user only requested a host=B build, so // there's not really a need for us to build for target A in this case // (since we're producing stage 1 libraries/binaries). But currently - // rustbuild is just a bit buggy here; this should be fixed though. + // bootstrap is just a bit buggy here; this should be fixed though. assert_eq!( first(cache.all::()), &[ diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2d54a84331ff..f96633b059a1 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -33,7 +33,7 @@ macro_rules! check_ci_llvm { assert!( $name.is_none(), "setting {} is incompatible with download-ci-llvm.", - stringify!($name) + stringify!($name).replace("_", "-") ); }; } @@ -658,8 +658,7 @@ impl Merge for TomlConfig { } } -// We are using a decl macro instead of a derive proc macro here to reduce the compile time of -// rustbuild. +// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. macro_rules! define_config { ($(#[$attr:meta])* struct $name:ident { $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* @@ -704,7 +703,7 @@ macro_rules! define_config { // The following is a trimmed version of what serde_derive generates. All parts not relevant // for toml deserialization have been removed. This reduces the binary size and improves - // compile time of rustbuild. + // compile time of bootstrap. impl<'de> Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where @@ -1259,7 +1258,7 @@ impl Config { cmd.arg("rev-parse").arg("--show-cdup"); // Discard stderr because we expect this to fail when building from a tarball. let output = cmd - .command + .as_command_mut() .stderr(std::process::Stdio::null()) .output() .ok() @@ -1569,7 +1568,15 @@ impl Config { let mut lld_enabled = None; let mut is_user_configured_rust_channel = false; + if let Some(rust) = toml.rust { + config.download_rustc_commit = + config.download_ci_rustc_commit(rust.download_rustc.clone()); + + if config.download_rustc_commit.is_some() { + check_incompatible_options_for_ci_rustc(&rust); + } + let Rust { optimize: optimize_toml, debug: debug_toml, @@ -1617,7 +1624,7 @@ impl Config { new_symbol_mangling, profile_generate, profile_use, - download_rustc, + download_rustc: _, lto, validate_mir_opts, frame_pointers, @@ -1627,11 +1634,7 @@ impl Config { } = rust; is_user_configured_rust_channel = channel.is_some(); - set(&mut config.channel, channel); - - config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc); - - // FIXME: handle download-rustc incompatible options. + set(&mut config.channel, channel.clone()); debug = debug_toml; debug_assertions = debug_assertions_toml; @@ -2163,7 +2166,7 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); - output(&mut git.command) + output(git.as_command_mut()) } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -2466,22 +2469,14 @@ impl Config { } }; - // Handle running from a directory other than the top level - let top_level = output( - &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, - ); - let top_level = top_level.trim_end(); - let compiler = format!("{top_level}/compiler/"); - let library = format!("{top_level}/library/"); - // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - &mut helpers::git(Some(&self.src)) + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]) - .command, + .as_command_mut(), ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2494,8 +2489,10 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) - .args(["diff-index", "--quiet", commit, "--", &compiler, &library]) - .command + .args(["diff-index", "--quiet", commit]) + .arg("--") + .args([self.src.join("compiler"), self.src.join("library")]) + .as_command_mut() .status()) .success(); if has_changes { @@ -2566,20 +2563,14 @@ impl Config { option_name: &str, if_unchanged: bool, ) -> Option { - // Handle running from a directory other than the top level - let top_level = output( - &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, - ); - let top_level = top_level.trim_end(); - // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - &mut helpers::git(Some(&self.src)) + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]) - .command, + .as_command_mut(), ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2594,11 +2585,14 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.args(["diff-index", "--quiet", commit, "--"]); + // Handle running from a directory other than the top level + let top_level = &self.src; + for path in modified_paths { - git.arg(format!("{top_level}/{path}")); + git.arg(top_level.join(path)); } - let has_changes = !t!(git.command.status()).success(); + let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { if if_unchanged { if self.verbose > 0 { @@ -2618,6 +2612,113 @@ impl Config { } } +/// Checks the CI rustc incompatible options by destructuring the `Rust` instance +/// and makes sure that no rust options from config.toml are missed. +fn check_incompatible_options_for_ci_rustc(rust: &Rust) { + macro_rules! err { + ($name:expr) => { + assert!( + $name.is_none(), + "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`.", + stringify!($name).replace("_", "-") + ); + }; + } + + macro_rules! warn { + ($name:expr) => { + if $name.is_some() { + println!( + "WARNING: `rust.{}` has no effect with `rust.download-rustc`.", + stringify!($name).replace("_", "-") + ); + } + }; + } + + let Rust { + // Following options are the CI rustc incompatible ones. + optimize, + debug_logging, + debuginfo_level_rustc, + llvm_tools, + llvm_bitcode_linker, + lto, + stack_protector, + strip, + lld_mode, + jemalloc, + rpath, + channel, + description, + incremental, + default_linker, + + // Rest of the options can simply be ignored. + debug: _, + codegen_units: _, + codegen_units_std: _, + debug_assertions: _, + debug_assertions_std: _, + overflow_checks: _, + overflow_checks_std: _, + debuginfo_level: _, + debuginfo_level_std: _, + debuginfo_level_tools: _, + debuginfo_level_tests: _, + split_debuginfo: _, + backtrace: _, + parallel_compiler: _, + musl_root: _, + verbose_tests: _, + optimize_tests: _, + codegen_tests: _, + omit_git_hash: _, + dist_src: _, + save_toolstates: _, + codegen_backends: _, + lld: _, + deny_warnings: _, + backtrace_on_ice: _, + verify_llvm_ir: _, + thin_lto_import_instr_limit: _, + remap_debuginfo: _, + test_compare_mode: _, + llvm_libunwind: _, + control_flow_guard: _, + ehcont_guard: _, + new_symbol_mangling: _, + profile_generate: _, + profile_use: _, + download_rustc: _, + validate_mir_opts: _, + frame_pointers: _, + } = rust; + + // There are two kinds of checks for CI rustc incompatible options: + // 1. Checking an option that may change the compiler behaviour/output. + // 2. Checking an option that have no effect on the compiler behaviour/output. + // + // If the option belongs to the first category, we call `err` macro for a hard error; + // otherwise, we just print a warning with `warn` macro. + err!(optimize); + err!(debug_logging); + err!(debuginfo_level_rustc); + err!(default_linker); + err!(rpath); + err!(strip); + err!(stack_protector); + err!(lld_mode); + err!(llvm_tools); + err!(llvm_bitcode_linker); + err!(jemalloc); + err!(lto); + + warn!(channel); + warn!(description); + warn!(incremental); +} + fn set(field: &mut T, val: Option) { if let Some(v) = val { *field = v; diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index aeb608a9ea26..19f752da81c1 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -1,4 +1,4 @@ -//! Command-line interface of the rustbuild build system. +//! Command-line interface of the bootstrap build system. //! //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index a7f4bb0cf146..d01a910e815d 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -702,9 +702,13 @@ download-rustc = false // time `rustc_llvm` build script ran. However, the timestamps of the // files in the tarball are in the past, so it doesn't trigger a // rebuild. - let now = filetime::FileTime::from_system_time(std::time::SystemTime::now()); + let now = std::time::SystemTime::now(); + let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now); + let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build)); - t!(filetime::set_file_times(llvm_config, now, now)); + let llvm_config_file = t!(File::open(llvm_config)); + + t!(llvm_config_file.set_times(file_times)); if self.should_fix_bins_and_dylibs() { let llvm_lib = llvm_root.join("lib"); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 9995da3a1e5b..2be819d52ea1 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -1,4 +1,4 @@ -//! Sanity checking performed by rustbuild before actually executing anything. +//! Sanity checking performed by bootstrap before actually executing anything. //! //! This module contains the implementation of ensuring that the build //! environment looks reasonable before progressing. This will verify that @@ -209,7 +209,7 @@ than building it. #[cfg(not(feature = "bootstrap-self-test"))] let stage0_supported_target_list: HashSet = crate::utils::helpers::output( - &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command, + command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(), ) .lines() .map(|s| s.to_string()) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index f16afb297965..db1fa05a82cb 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1,9 +1,9 @@ -//! Implementation of rustbuild, the Rust build system. +//! Implementation of bootstrap, the Rust build system. //! //! This module, and its descendants, are the implementation of the Rust build //! system. Most of this build system is backed by Cargo but the outer layer //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo -//! builds, building artifacts like LLVM, etc. The goals of rustbuild are: +//! builds, building artifacts like LLVM, etc. The goals of bootstrap are: //! //! * To be an easily understandable, easily extensible, and maintainable build //! system. @@ -23,21 +23,20 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Command; use std::str; use std::sync::OnceLock; use std::time::SystemTime; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; -use filetime::FileTime; use sha2::digest::Digest; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::channel::GitInfo; use utils::helpers::hex_encode; use crate::core::builder; -use crate::core::builder::Kind; +use crate::core::builder::{Builder, Kind}; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; @@ -490,15 +489,29 @@ impl Build { return; } - let submodule_git = || helpers::git(Some(&absolute_path)); + // Submodule updating actually happens during in the dry run mode. We need to make sure that + // all the git commands below are actually executed, because some follow-up code + // in bootstrap might depend on the submodules being checked out. Furthermore, not all + // the command executions below work with an empty output (produced during dry run). + // Therefore, all commands below are marked with `run_always()`, so that they also run in + // dry run mode. + let submodule_git = || { + let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout(); + cmd.run_always(); + cmd + }; // Determine commit checked out in submodule. - let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command); + let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout(); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. - let recorded = output( - &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command, - ); + let recorded = helpers::git(Some(&self.src)) + .capture_stdout() + .run_always() + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .run(self) + .stdout(); let actual_hash = recorded .split_whitespace() .nth(2) @@ -511,6 +524,7 @@ impl Build { println!("Updating submodule {}", relative_path.display()); helpers::git(Some(&self.src)) + .run_always() .args(["submodule", "-q", "sync"]) .arg(relative_path) .run(self); @@ -519,21 +533,16 @@ impl Build { let update = |progress: bool| { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. - let current_branch = { - let output = helpers::git(Some(&self.src)) - .args(["symbolic-ref", "--short", "HEAD"]) - .command - .stderr(Stdio::inherit()) - .output(); - let output = t!(output); - if output.status.success() { - Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) - } else { - None - } - }; + let current_branch = helpers::git(Some(&self.src)) + .capture_stdout() + .run_always() + .args(["symbolic-ref", "--short", "HEAD"]) + .run(self) + .stdout_if_ok() + .map(|s| s.trim().to_owned()); - let mut git = helpers::git(Some(&self.src)); + let mut git = helpers::git(Some(&self.src)).allow_failure(); + git.run_always(); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. @@ -547,8 +556,7 @@ impl Build { git.arg(relative_path); git }; - // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. - if !update(true).command.status().map_or(false, |status| status.success()) { + if !update(true).run(self).is_success() { update(false).run(self); } @@ -934,17 +942,26 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. + #[track_caller] fn run(&self, command: &mut BootstrapCommand) -> CommandOutput { + command.mark_as_executed(); if self.config.dry_run() && !command.run_always { return CommandOutput::default(); } - self.verbose(|| println!("running: {command:?}")); + let created_at = command.get_created_location(); + let executed_at = std::panic::Location::caller(); - command.command.stdout(command.stdout.stdio()); - command.command.stderr(command.stderr.stdio()); + self.verbose(|| { + println!("running: {command:?} (created at {created_at}, executed at {executed_at})") + }); - let output = command.command.output(); + let stdout = command.stdout.stdio(); + command.as_command_mut().stdout(stdout); + let stderr = command.stderr.stdio(); + command.as_command_mut().stderr(stderr); + + let output = command.as_command_mut().output(); use std::fmt::Write; @@ -956,8 +973,11 @@ impl Build { Ok(output) => { writeln!( message, - "\n\nCommand {command:?} did not execute successfully.\ - \nExpected success, got: {}", + r#" +Command {command:?} did not execute successfully. +Expected success, got {} +Created at: {created_at} +Executed at: {executed_at}"#, output.status, ) .unwrap(); @@ -1693,9 +1713,13 @@ impl Build { panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) } t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); + + let file_times = fs::FileTimes::new() + .set_accessed(t!(metadata.accessed())) + .set_modified(t!(metadata.modified())); + + let dst_file = t!(fs::File::open(dst)); + t!(dst_file.set_times(file_times)); } } @@ -1928,22 +1952,28 @@ fn envify(s: &str) -> String { /// /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. -pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { +pub fn generate_smart_stamp_hash( + builder: &Builder<'_>, + dir: &Path, + additional_input: &str, +) -> String { let diff = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("diff") - .command - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let status = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .command - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let mut hasher = sha2::Sha256::new(); diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 2ca86bdb0ed2..f8bcb584991a 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -45,7 +45,7 @@ impl GitInfo { } // Make sure git commands work - match helpers::git(Some(dir)).arg("rev-parse").command.output() { + match helpers::git(Some(dir)).arg("rev-parse").as_command_mut().output() { Ok(ref out) if out.status.success() => {} _ => return GitInfo::Absent, } @@ -58,16 +58,17 @@ impl GitInfo { // Ok, let's scrape some info let ver_date = output( - &mut helpers::git(Some(dir)) + helpers::git(Some(dir)) .arg("log") .arg("-1") .arg("--date=short") .arg("--pretty=format:%cd") - .command, + .as_command_mut(), ); - let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command); + let ver_hash = + output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); let short_ver_hash = output( - &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command, + helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(), ); GitInfo::Present(Some(Info { commit_date: ver_date.trim().to_string(), diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index ba963f52dc2b..a60c0084f3d7 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,5 +1,8 @@ use crate::Build; +use build_helper::ci::CiEnv; +use build_helper::drop_bomb::DropBomb; use std::ffi::OsStr; +use std::fmt::{Debug, Formatter}; use std::path::Path; use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; @@ -53,17 +56,20 @@ impl OutputMode { /// /// [allow_failure]: BootstrapCommand::allow_failure /// [delay_failure]: BootstrapCommand::delay_failure -#[derive(Debug)] pub struct BootstrapCommand { - pub command: Command, + command: Command, pub failure_behavior: BehaviorOnFailure, pub stdout: OutputMode, pub stderr: OutputMode, // Run the command even during dry run pub run_always: bool, + // This field makes sure that each command is executed (or disarmed) before it is dropped, + // to avoid forgetting to execute a command. + drop_bomb: DropBomb, } impl BootstrapCommand { + #[track_caller] pub fn new>(program: S) -> Self { Command::new(program).into() } @@ -142,19 +148,67 @@ impl BootstrapCommand { } /// Run the command, returning its output. + #[track_caller] pub fn run(&mut self, builder: &Build) -> CommandOutput { builder.run(self) } + + /// Provides access to the stdlib Command inside. + /// FIXME: This function should be eventually removed from bootstrap. + pub fn as_command_mut(&mut self) -> &mut Command { + // We don't know what will happen with the returned command, so we need to mark this + // command as executed proactively. + self.mark_as_executed(); + &mut self.command + } + + /// Mark the command as being executed, disarming the drop bomb. + /// If this method is not called before the command is dropped, its drop will panic. + pub fn mark_as_executed(&mut self) { + self.drop_bomb.defuse(); + } + + /// Returns the source code location where this command was created. + pub fn get_created_location(&self) -> std::panic::Location<'static> { + self.drop_bomb.get_created_location() + } + + /// If in a CI environment, forces the command to run with colors. + pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) { + if ci_env != CiEnv::None { + // Due to use of stamp/docker, the output stream of bootstrap is not + // a TTY in CI, so coloring is by-default turned off. + // The explicit `TERM=xterm` environment is needed for + // `--color always` to actually work. This env var was lost when + // compiling through the Makefile. Very strange. + self.env("TERM", "xterm").args(["--color", "always"]); + } + } +} + +impl Debug for BootstrapCommand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.command)?; + write!( + f, + " (failure_mode={:?}, stdout_mode={:?}, stderr_mode={:?})", + self.failure_behavior, self.stdout, self.stderr + ) + } } impl From for BootstrapCommand { + #[track_caller] fn from(command: Command) -> Self { + let program = command.get_program().to_owned(); + Self { command, failure_behavior: BehaviorOnFailure::Exit, stdout: OutputMode::Print, stderr: OutputMode::Print, run_always: false, + drop_bomb: DropBomb::arm(program), } } } @@ -169,6 +223,7 @@ enum CommandStatus { /// Create a new BootstrapCommand. This is a helper function to make command creation /// shorter than `BootstrapCommand::new`. +#[track_caller] #[must_use] pub fn command>(program: S) -> BootstrapCommand { BootstrapCommand::new(program) diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 5dd3ba96786c..3c82fa189be3 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -1,4 +1,4 @@ -//! Various utility functions used throughout rustbuild. +//! Various utility functions used throughout bootstrap. //! //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. @@ -244,7 +244,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( // FIXME: get rid of this function pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { - let status = match cmd.command.status() { + let status = match cmd.as_command_mut().status() { Ok(status) => status, Err(e) => { println!("failed to execute command: {cmd:?}\nERROR: {e}"); @@ -338,13 +338,13 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime /// missing. This function returns the path to that directory. -pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { +pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> PathBuf { // Similar to how LLVM does it, to find clang's library runtime directory: // - we ask `clang-cl` to locate the `clang_rt.builtins` lib. - let mut builtins_locator = Command::new(clang_cl_path); + let mut builtins_locator = command(clang_cl_path); builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]); - let clang_rt_builtins = output(&mut builtins_locator); + let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout(); let clang_rt_builtins = Path::new(clang_rt_builtins.trim()); assert!( clang_rt_builtins.exists(), @@ -501,6 +501,7 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { /// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every /// git command creation, which is painful to ensure that the required change is applied /// on each one of them correctly. +#[track_caller] pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { let mut git = command("git"); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 2e99bc68a8b7..a3d0d36e7547 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -33,6 +33,7 @@ pub(crate) fn try_run_tests( stream: bool, ) -> bool { if builder.config.dry_run() { + cmd.mark_as_executed(); return true; } @@ -50,7 +51,7 @@ pub(crate) fn try_run_tests( } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - let cmd = &mut cmd.command; + let cmd = cmd.as_command_mut(); cmd.stdout(Stdio::piped()); builder.verbose(|| println!("running: {cmd:?}")); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 4f0104e4bbab..9378c35127f2 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -369,13 +369,13 @@ impl<'a> Tarball<'a> { // gets the same timestamp. if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date - let timestamp = helpers::output( - &mut helpers::git(Some(&self.builder.src)) - .arg("log") - .arg("-1") - .arg("--format=%ct") - .command, - ); + let timestamp = helpers::git(Some(&self.builder.src)) + .capture_stdout() + .arg("log") + .arg("-1") + .arg("--format=%ct") + .run(self.builder) + .stdout(); cmd.args(["--override-file-mtime", timestamp.trim()]); } diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile index 426e601f5d34..4d9334dde8c5 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile @@ -11,6 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-riscv64-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch new file mode 100644 index 000000000000..f688eaf8029e --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch @@ -0,0 +1,37 @@ +From 4013baf99c38f7bca06a51f8301e8fb195ccfa33 Mon Sep 17 00:00:00 2001 +From: Jim Wilson +Date: Tue, 2 Jun 2020 11:19:39 -0700 +Subject: [PATCH] RISC-V: Make __divdi3 handle div by zero same as hardware. + +The ISA manual specifies that divide by zero always returns -1 as the result. +We were failing to do that when the dividend was negative. + +Original patch from Virginie Moser. + + libgcc/ + * config/riscv/div.S (__divdi3): For negative arguments, change bgez + to bgtz. +--- + libgcc/config/riscv/div.S | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S +index 151f8e273ac77..17234324c1e41 100644 +--- a/libgcc/config/riscv/div.S ++++ b/libgcc/config/riscv/div.S +@@ -107,10 +107,12 @@ FUNC_END (__umoddi3) + /* Handle negative arguments to __divdi3. */ + .L10: + neg a0, a0 +- bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ ++ /* Zero is handled as a negative so that the result will not be inverted. */ ++ bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ ++ + neg a1, a1 +- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ +-.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ ++ j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ ++.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ + neg a1, a1 + .L12: + move t0, ra diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch new file mode 100644 index 000000000000..7ae4469428b1 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch @@ -0,0 +1,117 @@ +From 45116f342057b7facecd3d05c2091ce3a77eda59 Mon Sep 17 00:00:00 2001 +From: Nelson Chu +Date: Mon, 29 Nov 2021 04:48:20 -0800 +Subject: [PATCH] RISC-V: jal cannot refer to a default visibility symbol for + shared object. + +This is the original binutils bugzilla report, +https://sourceware.org/bugzilla/show_bug.cgi?id=28509 + +And this is the first version of the proposed binutils patch, +https://sourceware.org/pipermail/binutils/2021-November/118398.html + +After applying the binutils patch, I get the the unexpected error when +building libgcc, + +/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42: +/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC + +Therefore, this patch add an extra hidden alias symbol for __udivdi3, and +then use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. +The solution is similar to glibc as follows, +https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b + +libgcc/ChangeLog: + + * config/riscv/div.S: Add the hidden alias symbol for __udivdi3, and + then use HIDDEN_JUMPTARGET to target it since it is non-preemptible. + * config/riscv/riscv-asm.h: Added new macros HIDDEN_JUMPTARGET and + HIDDEN_DEF. +--- + libgcc/config/riscv/div.S | 15 ++++++++------- + libgcc/config/riscv/riscv-asm.h | 6 ++++++ + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S +index c9bd7879c1e36..723c3b82e48c6 100644 +--- a/libgcc/config/riscv/div.S ++++ b/libgcc/config/riscv/div.S +@@ -40,7 +40,7 @@ FUNC_BEGIN (__udivsi3) + sll a0, a0, 32 + sll a1, a1, 32 + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + sext.w a0, a0 + jr t0 + FUNC_END (__udivsi3) +@@ -52,7 +52,7 @@ FUNC_BEGIN (__umodsi3) + srl a0, a0, 32 + srl a1, a1, 32 + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + sext.w a0, a1 + jr t0 + FUNC_END (__umodsi3) +@@ -95,11 +95,12 @@ FUNC_BEGIN (__udivdi3) + .L5: + ret + FUNC_END (__udivdi3) ++HIDDEN_DEF (__udivdi3) + + FUNC_BEGIN (__umoddi3) + /* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */ + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + move a0, a1 + jr t0 + FUNC_END (__umoddi3) +@@ -111,12 +112,12 @@ FUNC_END (__umoddi3) + bgtz a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */ + + neg a1, a1 +- j __udivdi3 /* Compute __udivdi3(-a0, -a1). */ ++ j HIDDEN_JUMPTARGET(__udivdi3) /* Compute __udivdi3(-a0, -a1). */ + .L11: /* Compute __udivdi3(a0, -a1), then negate the result. */ + neg a1, a1 + .L12: + move t0, ra +- jal __udivdi3 ++ jal HIDDEN_JUMPTARGET(__udivdi3) + neg a0, a0 + jr t0 + FUNC_END (__divdi3) +@@ -126,7 +127,7 @@ FUNC_BEGIN (__moddi3) + bltz a1, .L31 + bltz a0, .L32 + .L30: +- jal __udivdi3 /* The dividend is not negative. */ ++ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is not negative. */ + move a0, a1 + jr t0 + .L31: +@@ -134,7 +135,7 @@ FUNC_BEGIN (__moddi3) + bgez a0, .L30 + .L32: + neg a0, a0 +- jal __udivdi3 /* The dividend is hella negative. */ ++ jal HIDDEN_JUMPTARGET(__udivdi3) /* The dividend is hella negative. */ + neg a0, a1 + jr t0 + FUNC_END (__moddi3) +diff --git a/libgcc/config/riscv/riscv-asm.h b/libgcc/config/riscv/riscv-asm.h +index 8550707a4a26a..96dd85b0df2e5 100644 +--- a/libgcc/config/riscv/riscv-asm.h ++++ b/libgcc/config/riscv/riscv-asm.h +@@ -33,3 +33,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + #define FUNC_ALIAS(X,Y) \ + .globl X; \ + X = Y ++ ++#define CONCAT1(a, b) CONCAT2(a, b) ++#define CONCAT2(a, b) a ## b ++#define HIDDEN_JUMPTARGET(X) CONCAT1(__hidden_, X) ++#define HIDDEN_DEF(X) FUNC_ALIAS(HIDDEN_JUMPTARGET(X), X); \ ++ .hidden HIDDEN_JUMPTARGET(X) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch new file mode 100644 index 000000000000..d267b961d347 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch @@ -0,0 +1,58 @@ +From 68389203832ab39dd0dbaabbc4059e7fff51c29b Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Thu, 28 Oct 2021 11:39:49 -0700 +Subject: [PATCH] riscv: Fix incorrect jal with HIDDEN_JUMPTARGET + +A non-local STV_DEFAULT defined symbol is by default preemptible in a +shared object. j/jal cannot target a preemptible symbol. On other +architectures, such a jump instruction either causes PLT [BZ #18822], or +if short-ranged, sometimes rejected by the linker (but not by GNU ld's +riscv port [ld PR/28509]). + +Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead. + +With this patch, ld.so and libc.so can be linked with LLD if source +files are compiled/assembled with -mno-relax/-Wa,-mno-relax. + +Acked-by: Palmer Dabbelt +Reviewed-by: Adhemerval Zanella +--- + sysdeps/riscv/setjmp.S | 2 +- + sysdeps/unix/sysv/linux/riscv/setcontext.S | 5 +++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S +index 0b92016b311..bec7ff80f49 100644 +--- a/sysdeps/riscv/setjmp.S ++++ b/sysdeps/riscv/setjmp.S +@@ -21,7 +21,7 @@ + + ENTRY (_setjmp) + li a1, 0 +- j __sigsetjmp ++ j HIDDEN_JUMPTARGET (__sigsetjmp) + END (_setjmp) + ENTRY (setjmp) + li a1, 1 +diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S +index 9510518750a..e44a68aad47 100644 +--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S ++++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S +@@ -95,6 +95,7 @@ LEAF (__setcontext) + 99: j __syscall_error + + END (__setcontext) ++libc_hidden_def (__setcontext) + weak_alias (__setcontext, setcontext) + + LEAF (__start_context) +@@ -108,7 +109,7 @@ LEAF (__start_context) + /* Invoke subsequent context if present, else exit(0). */ + mv a0, s2 + beqz s2, 1f +- jal __setcontext +-1: j exit ++ jal HIDDEN_JUMPTARGET (__setcontext) ++1: j HIDDEN_JUMPTARGET (exit) + + END (__start_context) diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig index 470cef1a84e1..f7c93a9d5fc8 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig @@ -3,6 +3,8 @@ CT_EXPERIMENTAL=y CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_PATCH_BUNDLED_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_RISCV=y # CT_DEMULTILIB is not set CT_ARCH_USE_MMU=y @@ -10,7 +12,7 @@ CT_ARCH_64=y CT_ARCH_ARCH="rv64gc" CT_KERNEL_LINUX=y CT_LINUX_V_4_20=y -CT_BINUTILS_V_2_36=y +CT_BINUTILS_V_2_40=y CT_GLIBC_V_2_29=y CT_GCC_V_8=y CT_CC_LANG_CXX=y diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index 24b9904d65c2..6103aa61248a 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -40,7 +40,7 @@ if isMacOS; then # our own clang can figure out the correct include path on its own. ciCommandSetEnv SDKROOT "$(xcrun --sdk macosx --show-sdk-path)" - # Configure `AR` specifically so rustbuild doesn't try to infer it as + # Configure `AR` specifically so bootstrap doesn't try to infer it as # `clang-ar` by accident. ciCommandSetEnv AR "ar" elif isWindows && ! isKnownToBeMingwBuild; then diff --git a/src/doc/book b/src/doc/book index f1e49bf7a8ea..67fa53676801 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64 +Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 941db8b3df45..5454de3d12b9 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c +Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac diff --git a/src/doc/embedded-book b/src/doc/embedded-book index b10c6acaf0f4..019f3928d8b9 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit b10c6acaf0f43481f6600e95d4b5013446e29f7a +Subproject commit 019f3928d8b939ec71b63722dcc2e46330156441 diff --git a/src/doc/reference b/src/doc/reference index 1ae3deebc3ac..e2f0bdc40318 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08 +Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 658c6c27cb97..89aecb6951b7 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 658c6c27cb975b92227936024816986c2d3716fb +Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d6e3a32a557d..0c4d55cb59fe 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7 +Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f5cd4bd217a3..370dbed50fa1 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -41,10 +41,10 @@ target | notes `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) -[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue]. +[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. [77071]: https://github.com/rust-lang/rust/issues/77071 -[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479 +[x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567 ## Tier 1 @@ -209,6 +209,8 @@ target | std | notes [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. +[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479 + [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607 [Fortanix ABI]: https://edp.fortanix.com/ diff --git a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md index 97b5827c1443..33e1c44e6d35 100644 --- a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md +++ b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md @@ -46,7 +46,7 @@ on how to setup a development and runtime environment. As a tier 2 target, the target is built by the Rust project. -You can configure rustbuild like so: +You can configure bootstrap like so: ```toml [build] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index aa596897fc42..a0e28d2f55c7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -228,8 +228,9 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) } - // FIXME(precise_capturing): Implement rustdoc support - hir::GenericBound::Use(..) => return None, + hir::GenericBound::Use(args, ..) => { + GenericBound::Use(args.iter().map(|arg| arg.name()).collect()) + } }) } @@ -1051,12 +1052,12 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { match literal.kind { ast::LitKind::Int(a, _) => { - let gen = func.generics.params.remove(0); + let param = func.generics.params.remove(0); if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. }, .. - } = gen + } = param { func.decl .inputs diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 58eef36677b2..1b7d84add1f8 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -79,7 +79,7 @@ pub(crate) fn merge_bounds( !bounds.iter_mut().any(|b| { let trait_ref = match *b { clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, + clean::GenericBound::Outlives(..) | clean::GenericBound::Use(_) => return false, }; // If this QPath's trait `trait_did` is the same as, or a supertrait // of, the bound's trait `did` then we can keep going, otherwise diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fe01d17b08a8..a31adc9949a3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1244,6 +1244,8 @@ impl Eq for Attributes {} pub(crate) enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifier), Outlives(Lifetime), + /// `use<'a, T>` precise-capturing bound syntax + Use(Vec), } impl GenericBound { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4268fadd6c59..9b0b2571ec11 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -412,6 +412,20 @@ impl clean::GenericBound { })?; ty.print(cx).fmt(f) } + clean::GenericBound::Use(args) => { + if f.alternate() { + f.write_str("use<")?; + } else { + f.write_str("use<")?; + } + for (i, arg) in args.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + arg.fmt(f)?; + } + if f.alternate() { f.write_str(">") } else { f.write_str(">") } + } }) } } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index bc8bdffc3314..66d3f0fd8ce8 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1051,7 +1051,7 @@ fn simplify_fn_type<'tcx, 'a>( let mut ty_generics = Vec::new(); let mut ty_constraints = Vec::new(); if let Some(arg_generics) = arg.generic_args() { - for ty in arg_generics.into_iter().filter_map(|gen| match gen { + for ty in arg_generics.into_iter().filter_map(|param| match param { clean::GenericArg::Type(ty) => Some(ty), _ => None, }) { @@ -1172,8 +1172,8 @@ fn simplify_fn_constraint<'tcx, 'a>( ) { let mut ty_constraints = Vec::new(); let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name); - for gen in &constraint.assoc.args { - match gen { + for param in &constraint.assoc.args { + match param { clean::GenericArg::Type(arg) => simplify_fn_type( self_, generics, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5111e363c522..4ab0df367085 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -542,6 +542,7 @@ impl FromWithTcx for GenericBound { } } Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), + Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()), } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 89115d4d7d66..6fd23b60c8ad 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 31; +pub const FORMAT_VERSION: u32 = 32; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -538,6 +538,8 @@ pub enum GenericBound { modifier: TraitBoundModifier, }, Outlives(String), + /// `use<'a, T>` precise-capturing bound syntax + Use(Vec), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 09489b0d9b7d..6d79c7c83ad8 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -1,5 +1,3 @@ -use std::process::Command; - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum CiEnv { /// Not a CI environment. @@ -21,18 +19,6 @@ impl CiEnv { pub fn is_ci() -> bool { Self::current() != CiEnv::None } - - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(self, cmd: &mut Command) { - if self != CiEnv::None { - // Due to use of stamp/docker, the output stream of rustbuild is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - cmd.env("TERM", "xterm").args(&["--color", "always"]); - } - } } pub mod gha { diff --git a/src/tools/run-make-support/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs similarity index 71% rename from src/tools/run-make-support/src/drop_bomb/mod.rs rename to src/tools/build_helper/src/drop_bomb/mod.rs index 2fc84892c1bd..0a5bb04b55b3 100644 --- a/src/tools/run-make-support/src/drop_bomb/mod.rs +++ b/src/tools/build_helper/src/drop_bomb/mod.rs @@ -12,27 +12,31 @@ use std::panic; mod tests; #[derive(Debug)] -pub(crate) struct DropBomb { +pub struct DropBomb { command: OsString, defused: bool, - armed_line: u32, + armed_location: panic::Location<'static>, } impl DropBomb { /// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then /// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help - /// propagate the caller info from rmake.rs. + /// propagate the caller location. #[track_caller] - pub(crate) fn arm>(command: S) -> DropBomb { + pub fn arm>(command: S) -> DropBomb { DropBomb { command: command.as_ref().into(), defused: false, - armed_line: panic::Location::caller().line(), + armed_location: *panic::Location::caller(), } } + pub fn get_created_location(&self) -> panic::Location<'static> { + self.armed_location + } + /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped. - pub(crate) fn defuse(&mut self) { + pub fn defuse(&mut self) { self.defused = true; } } @@ -41,8 +45,8 @@ impl Drop for DropBomb { fn drop(&mut self) { if !self.defused && !std::thread::panicking() { panic!( - "command constructed but not executed at line {}: `{}`", - self.armed_line, + "command constructed at `{}` was dropped without being executed: `{}`", + self.armed_location, self.command.to_string_lossy() ) } diff --git a/src/tools/run-make-support/src/drop_bomb/tests.rs b/src/tools/build_helper/src/drop_bomb/tests.rs similarity index 100% rename from src/tools/run-make-support/src/drop_bomb/tests.rs rename to src/tools/build_helper/src/drop_bomb/tests.rs diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 15807d1c0d8f..4a4f0ca2a9d4 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,6 +1,7 @@ //! Types and functions shared across tools in this workspace. pub mod ci; +pub mod drop_bomb; pub mod git; pub mod metrics; pub mod stage0_parser; diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index 91c98b3a2560..f016a7700592 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -58,7 +58,7 @@ jobs: - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload base JSON uses: actions/upload-artifact@v4 @@ -86,7 +86,7 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload head JSON uses: actions/upload-artifact@v4 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 70ef2c793640..55281f3cbec0 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5236,6 +5236,7 @@ Released 2018-09-13 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata @@ -5253,6 +5254,7 @@ Released 2018-09-13 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes [`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts +[`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp @@ -5539,6 +5541,7 @@ Released 2018-09-13 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain +[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once @@ -5587,6 +5590,7 @@ Released 2018-09-13 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message [`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn +[`missing_const_for_thread_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_thread_local [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc @@ -5701,6 +5705,7 @@ Released 2018-09-13 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params +[`panicking_overflow_checks`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_overflow_checks [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl @@ -5797,6 +5802,7 @@ Released 2018-09-13 [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse +[`set_contains_or_insert`]: https://rust-lang.github.io/rust-clippy/master/index.html#set_contains_or_insert [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index cfd34c7d2a7d..ad29339a84ad 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -348,6 +348,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut) * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) @@ -454,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml index 62ed55beb1f3..319b72e8c5d5 100644 --- a/src/tools/clippy/clippy.toml +++ b/src/tools/clippy/clippy.toml @@ -1,5 +1,9 @@ avoid-breaking-exported-api = false +[[disallowed-methods]] +path = "rustc_lint::context::LintContext::lint" +reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" + [[disallowed-methods]] path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index dbab3b106a80..7f53aad67933 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -31,6 +31,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", + "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", @@ -262,7 +263,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index a5761d3270cd..fc56ac517968 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -25,8 +25,8 @@ msrv_aliases! { 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO } - 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } - 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN } + 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,56,0 { CONST_FN_UNION } 1,55,0 { SEEK_REWIND } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 2e56eb8ec15f..d762e30ef02e 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _: fmt::Result = writedoc!( lint_file_contents, r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 57a5cd8fba81..96e9c949b750 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -41,61 +40,80 @@ impl AlmostCompleteRange { } impl EarlyLintPass for AlmostCompleteRange { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind { - let ctxt = e.span.ctxt(); - let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) - && let Some(end) = walk_span_to_context(end.span, ctxt) - && self.msrv.meets(msrvs::RANGE_INCLUSIVE) - { - Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) - } else { - None - }; - check_range(cx, e.span, start, end, sugg); + if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), e.span) + { + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + e.span, + "almost complete ascii range", + |diag| { + let ctxt = e.span.ctxt(); + if let Some(start) = walk_span_to_context(start.span, ctxt) + && let Some(end) = walk_span_to_context(end.span, ctxt) + && self.msrv.meets(msrvs::RANGE_INCLUSIVE) + { + diag.span_suggestion( + trim_span(cx.sess().source_map(), start.between(end)), + "use an inclusive range", + "..=".to_owned(), + Applicability::MaybeIncorrect, + ); + } + }, + ); } } fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) { if let PatKind::Range(Some(start), Some(end), kind) = &p.kind && matches!(kind.node, RangeEnd::Excluded) + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), p.span) { - let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { - "..=" - } else { - "..." - }; - check_range(cx, p.span, start, end, Some((kind.span, sugg))); + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + p.span, + "almost complete ascii range", + |diag| { + diag.span_suggestion( + kind.span, + "use an inclusive range", + if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { + "..=".to_owned() + } else { + "...".to_owned() + }, + Applicability::MaybeIncorrect, + ); + }, + ); } } extract_msrv_attr!(EarlyContext); } -fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) { - if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind - && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind - && matches!( - ( - LitKind::from_token_lit(start_token_lit), - LitKind::from_token_lit(end_token_lit), - ), - ( - Ok(LitKind::Byte(b'a') | LitKind::Char('a')), - Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) | ( - Ok(LitKind::Byte(b'A') | LitKind::Char('A')), - Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) | ( - Ok(LitKind::Byte(b'0') | LitKind::Char('0')), - Ok(LitKind::Byte(b'9') | LitKind::Char('9')), +fn is_incomplete_range(start: &Expr, end: &Expr) -> bool { + match (&start.peel_parens().kind, &end.peel_parens().kind) { + (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => { + matches!( + (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),), + ( + Ok(LitKind::Byte(b'a') | LitKind::Char('a')), + Ok(LitKind::Byte(b'z') | LitKind::Char('z')) + ) | ( + Ok(LitKind::Byte(b'A') | LitKind::Char('A')), + Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), + ) | ( + Ok(LitKind::Byte(b'0') | LitKind::Char('0')), + Ok(LitKind::Byte(b'9') | LitKind::Char('9')), + ) ) - ) - && !in_external_macro(cx.sess(), span) - { - span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); - } - }); + }, + _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index 2003dd1fb0e2..ed4cdce8cb88 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,8 @@ -use clippy_utils::consts::{constant_with_source, Constant, ConstantSource}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_inside_always_const_context; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; -use rustc_hir::{Expr, Item, ItemKind, Node}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -42,17 +43,16 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return; }; - let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else { + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return; }; - if let ConstantSource::Constant = source - && let Node::Item(Item { - kind: ItemKind::Const(..), - .. - }) = cx.tcx.parent_hir_node(e.hir_id) - { - return; + + match condition.kind { + ExprKind::Path(..) | ExprKind::Lit(_) => {}, + _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return, + _ => {}, } + if val { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 406f38f411ec..0de0031ed24f 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -1,18 +1,16 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::HirNode; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -68,167 +66,84 @@ impl AssigningClones { impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { - fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { - // Do not fire the lint in macros - let ctxt = assign_expr.span().ctxt(); - let expn_data = ctxt.outer_expn_data(); - match expn_data.kind { - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return, - ExpnKind::Root => {}, - } - - let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else { - return; - }; - - let Some(call) = extract_call(cx, rhs) else { - return; - }; - - if is_ok_to_suggest(cx, lhs, &call, &self.msrv) { - suggest(cx, ctxt, assign_expr, lhs, &call); + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Assign(lhs, rhs, _) = e.kind + && let typeck = cx.typeck_results() + && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind { + ExprKind::Call(f, [arg]) + if let ExprKind::Path(fn_path) = &f.kind + && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() => + { + (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id)) + }, + ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => { + (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id)) + }, + _ => return, + } + && let ctxt = e.span.ctxt() + // Don't lint in macros. + && ctxt.is_root() + && let which_trait = match fn_name { + sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, + _ if fn_name.as_str() == "to_owned" + && is_diag_trait_item(cx, fn_id, sym::ToOwned) + && self.msrv.meets(msrvs::CLONE_INTO) => + { + CloneTrait::ToOwned + }, + _ => return, + } + && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args) + // TODO: This check currently bails if the local variable has no initializer. + // That is overly conservative - the lint should fire even if there was no initializer, + // but the variable has been initialized before `lhs` was evaluated. + && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs)) + && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id()) + // Derived forms don't implement `clone_from`/`clone_into`. + // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 + && !cx.tcx.is_builtin_derived(resolved_impl) + // Don't suggest calling a function we're implementing. + && resolved_impl.as_local().map_or(true, |block_id| { + cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id) + }) + && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl) + // Only suggest if `clone_from`/`clone_into` is explicitly implemented + && resolved_assoc_items.in_definition_order().any(|assoc| + match which_trait { + CloneTrait::Clone => assoc.name == sym::clone_from, + CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", + } + ) + && !clone_source_borrows_from_dest(cx, lhs, rhs.span) + { + span_lint_and_then( + cx, + ASSIGNING_CLONES, + e.span, + match which_trait { + CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", + CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", + }, + |diag| { + let mut app = Applicability::Unspecified; + diag.span_suggestion( + e.span, + match which_trait { + CloneTrait::Clone => "use `clone_from()`", + CloneTrait::ToOwned => "use `clone_into()`", + }, + build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app), + app, + ); + }, + ); } } extract_msrv_attr!(LateContext); } -// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`. -fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { - let fn_def_id = clippy_utils::fn_def_id(cx, expr)?; - - // Fast paths to only check method calls without arguments or function calls with a single argument - let (target, kind, resolved_method) = match expr.kind { - ExprKind::MethodCall(path, receiver, [], _span) => { - let args = cx.typeck_results().node_args(expr.hir_id); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else { - return None; - }; - if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { - (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method) - } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" { - (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method) - } else { - return None; - } - }, - ExprKind::Call(function, [arg]) => { - let kind = cx.typeck_results().node_type(function.hir_id).kind(); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args), - _ => Ok(None), - }) else { - return None; - }; - if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) { - ( - TargetTrait::ToOwned, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id) - && cx.tcx.is_diagnostic_item(sym::Clone, trait_did) - { - ( - TargetTrait::Clone, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else { - return None; - } - }, - _ => return None, - }; - - Some(CallCandidate { - span: expr.span, - target, - kind, - method_def_id: resolved_method.def_id(), - }) -} - -// Return true if we find that the called method has a custom implementation and isn't derived or -// provided by default by the corresponding trait. -fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { - // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. - // If the current MSRV is below that, don't suggest the lint. - if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) { - return false; - } - - // If the left-hand side is a local variable, it might be uninitialized at this point. - // In that case we do not want to suggest the lint. - if let Some(local) = path_to_local(lhs) { - // TODO: This check currently bails if the local variable has no initializer. - // That is overly conservative - the lint should fire even if there was no initializer, - // but the variable has been initialized before `lhs` was evaluated. - if !local_is_initialized(cx, local) { - return false; - } - } - - let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else { - return false; - }; - - // If the method implementation comes from #[derive(Clone)], then don't suggest the lint. - // Automatically generated Clone impls do not currently override `clone_from`. - // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details. - if cx.tcx.is_builtin_derived(impl_block) { - return false; - } - - // If the call expression is inside an impl block that contains the method invoked by the - // call expression, we bail out to avoid suggesting something that could result in endless - // recursion. - if let Some(local_block_id) = impl_block.as_local() - && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner() - { - let impl_block_owner = block.def_id(); - if cx - .tcx - .hir() - .parent_id_iter(lhs.hir_id) - .any(|parent| parent.owner == impl_block_owner) - { - return false; - } - } - - // Find the function for which we want to check that it is implemented. - let provided_fn = match call.target { - TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { - cx.tcx - .provided_trait_methods(clone) - .find(|item| item.name == sym::clone_from) - }), - TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| { - cx.tcx - .provided_trait_methods(to_owned) - .find(|item| item.name.as_str() == "clone_into") - }), - }; - let Some(provided_fn) = provided_fn else { - return false; - }; - - if clone_source_borrows_from_dest(cx, lhs, call.span) { - return false; - } - - // Now take a look if the impl block defines an implementation for the method that we're interested - // in. If not, then we're using a default implementation, which is not interesting, so we will - // not suggest the lint. - let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block); - implemented_fns.contains_key(&provided_fn.def_id) -} - /// Checks if the data being cloned borrows from the place that is being assigned to: /// /// ``` @@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC /// /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows. fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool { - /// If this basic block only exists to drop a local as part of an assignment, returns its - /// successor. Otherwise returns the basic block that was passed in. - fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock { - if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind { - target - } else { - bb - } - } - let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else { return false; }; @@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa // // bb2: // s = s_temp - for bb in mir.basic_blocks.iter() { - let terminator = bb.terminator(); - - // Look for the to_owned/clone call. - if terminator.source_info.span != call_span { - continue; + if let Some(terminator) = mir.basic_blocks.iter() + .map(mir::BasicBlockData::terminator) + .find(|term| term.source_info.span == call_span) + && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind + && let [source] = &**args + && let mir::Operand::Move(source) = &source.node + && let assign_bb = &mir.basic_blocks[assign_bb] + && let assign_bb = match assign_bb.terminator().kind { + // Skip the drop of the assignment's destination. + mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target], + _ => assign_bb, } - - if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind - && let [source] = &**args - && let mir::Operand::Move(source) = &source.node - && let assign_bb = skip_drop_block(mir, assign_bb) - // Skip any storage statements as they are just noise - && let Some(assignment) = mir.basic_blocks[assign_bb].statements - .iter() - .find(|stmt| { - !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) - }) - && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind - && let Some(borrowers) = borrow_map.get(&borrowed.local) - && borrowers.contains(source.local) - { - return true; - } - - return false; + // Skip any storage statements as they are just noise + && let Some(assignment) = assign_bb.statements + .iter() + .find(|stmt| { + !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) + }) + && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind + && let Some(borrowers) = borrow_map.get(&borrowed.local) + { + borrowers.contains(source.local) + } else { + false } - false } -fn suggest<'tcx>( - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - assign_expr: &Expr<'tcx>, - lhs: &Expr<'tcx>, - call: &CallCandidate<'tcx>, -) { - span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { - let mut applicability = Applicability::Unspecified; - - diag.span_suggestion( - assign_expr.span, - call.suggestion_msg(), - call.suggested_replacement(cx, ctxt, lhs, &mut applicability), - applicability, - ); - }); -} - -#[derive(Copy, Clone, Debug)] -enum CallKind<'tcx> { - MethodCall { receiver: &'tcx Expr<'tcx> }, - FunctionCall { self_arg: &'tcx Expr<'tcx> }, -} - -#[derive(Copy, Clone, Debug)] -enum TargetTrait { +#[derive(Clone, Copy)] +enum CloneTrait { Clone, ToOwned, } -#[derive(Debug)] -struct CallCandidate<'tcx> { - span: Span, - target: TargetTrait, - kind: CallKind<'tcx>, - // DefId of the called method from an impl block that implements the target trait - method_def_id: DefId, +#[derive(Copy, Clone)] +enum CallKind { + Ufcs, + Method, } -impl<'tcx> CallCandidate<'tcx> { - #[inline] - fn message(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", - TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", - } - } - - #[inline] - fn suggestion_msg(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "use `clone_from()`", - TargetTrait::ToOwned => "use `clone_into()`", - } - } - - fn suggested_replacement( - &self, - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - lhs: &Expr<'tcx>, - applicability: &mut Applicability, - ) -> String { - match self.target { - TargetTrait::Clone => { - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability) - } - .maybe_par(); - - // Determine whether we need to reference the argument to clone_from(). - let clone_receiver_type = cx.typeck_results().expr_ty(receiver); - let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver); - let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - if clone_receiver_type != clone_receiver_adj_type { - // The receiver may have been a value type, so we need to add an `&` to - // be sure the argument to clone_from will be a reference. - arg_sugg = arg_sugg.addr(); - }; - - format!("{receiver_sugg}.clone_from({arg_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr() - }; - // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. - let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - - format!("Clone::clone_from({self_sugg}, {rhs_sugg})") - }, - } - }, - TargetTrait::ToOwned => { - let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` - // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` - let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par(); - let inner_type = cx.typeck_results().expr_ty(ref_expr); - // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it - // deref to a mutable reference. - if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { - sugg +fn build_sugg<'tcx>( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + lhs: &'tcx Expr<'_>, + fn_arg: &'tcx Expr<'_>, + which_trait: CloneTrait, + call_kind: CallKind, + app: &mut Applicability, +) -> String { + match which_trait { + CloneTrait::Clone => { + match call_kind { + CallKind::Method => { + let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) } else { - sugg.mut_addr() + // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app) } - } else { - // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` - // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability) - .maybe_par() - .mut_addr() - }; + .maybe_par(); - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - format!("{receiver_sugg}.clone_into({rhs_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") - }, + // Determine whether we need to reference the argument to clone_from(). + let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg); + let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg); + let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + if clone_receiver_type != clone_receiver_adj_type { + // The receiver may have been a value type, so we need to add an `&` to + // be sure the argument to clone_from will be a reference. + arg_sugg = arg_sugg.addr(); + }; + + format!("{receiver_sugg}.clone_from({arg_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) + } else { + // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr() + }; + // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. + let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + + format!("Clone::clone_from({self_sugg}, {rhs_sugg})") + }, + } + }, + CloneTrait::ToOwned => { + let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` + // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` + let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par(); + let inner_type = cx.typeck_results().expr_ty(ref_expr); + // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it + // deref to a mutable reference. + if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { + sugg + } else { + sugg.mut_addr() } - }, - } + } else { + // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` + // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` + Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr() + }; + + match call_kind { + CallKind::Method => { + let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("{receiver_sugg}.clone_into({rhs_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") + }, + } + }, } } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index f25a474d9bbd..d4a1e2780d08 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -11,21 +11,25 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a non-async-aware MutexGuard. + /// Checks for calls to `await` while holding a non-async-aware + /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in std::sync and parking_lot - /// are not designed to operate in an async context across await points. + /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and + /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are + /// not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an async-aware Mutex - /// type. Many asynchronous foundation crates provide such a Mutex type. The - /// other solution is to ensure the mutex is unlocked before calling await, - /// either by introducing a scope or an explicit call to Drop::drop. + /// There are two potential solutions. One is to use an async-aware `Mutex` + /// type. Many asynchronous foundation crates provide such a `Mutex` type. + /// The other solution is to ensure the mutex is unlocked before calling + /// `await`, either by introducing a scope or an explicit call to + /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html). /// /// ### Known problems /// Will report false positive for explicitly dropped guards - /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is - /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A + /// workaround for this is to wrap the `.lock()` call in a block instead of + /// explicitly dropping the guard. /// /// ### Example /// ```no_run @@ -73,11 +77,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`. /// /// ### Why is this bad? /// `RefCell` refs only check for exclusive mutable access - /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point + /// at runtime. Holding a `RefCell` ref across an await suspension point /// risks panics from a mutable ref shared while other refs are outstanding. /// /// ### Known problems @@ -131,13 +135,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Allows users to configure types which should not be held across `await` + /// Allows users to configure types which should not be held across await /// suspension points. /// /// ### Why is this bad? - /// There are some types which are perfectly "safe" to be used concurrently - /// from a memory access perspective but will cause bugs at runtime if they - /// are held in such a way. + /// There are some types which are perfectly safe to use concurrently from + /// a memory access perspective, but that will cause bugs at runtime if + /// they are held in such a way. /// /// ### Example /// @@ -228,15 +232,15 @@ impl AwaitHolding { cx, AWAIT_HOLDING_LOCK, ty_cause.source_info.span, - "this `MutexGuard` is held across an `await` point", + "this `MutexGuard` is held across an await point", |diag| { diag.help( "consider using an async-aware `Mutex` type or ensuring the \ - `MutexGuard` is dropped before calling await", + `MutexGuard` is dropped before calling `await`", ); diag.span_note( await_points(), - "these are all the `await` points this lock is held through", + "these are all the await points this lock is held through", ); }, ); @@ -245,12 +249,12 @@ impl AwaitHolding { cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.source_info.span, - "this `RefCell` reference is held across an `await` point", + "this `RefCell` reference is held across an await point", |diag| { diag.help("ensure the reference is dropped before calling `await`"); diag.span_note( await_points(), - "these are all the `await` points this reference is held through", + "these are all the await points this reference is held through", ); }, ); @@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa AWAIT_HOLDING_INVALID_TYPE, span, format!( - "`{}` may not be held across an `await` point per `clippy.toml`", + "`{}` may not be held across an await point per `clippy.toml`", disallowed.path() ), |diag| { diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs index cfb76cab6dc2..561ca9bd9866 100644 --- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs +++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs @@ -1,13 +1,11 @@ -use clippy_utils::higher::If; -use rustc_ast::LitKind; -use rustc_hir::{Block, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; -use clippy_utils::{in_constant, is_else_clause, is_integer_literal}; +use clippy_utils::{in_constant, is_else_clause}; +use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -47,80 +45,64 @@ declare_clippy_lint! { declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { - check_if_else(cx, expr); + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::If(cond, then, Some(else_)) = expr.kind + && matches!(cond.kind, ExprKind::DropTemps(_)) + && let Some(then_lit) = as_int_bool_lit(then) + && let Some(else_lit) = as_int_bool_lit(else_) + && then_lit != else_lit + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { + let ty = cx.typeck_results().expr_ty(then); + let mut applicability = Applicability::MachineApplicable; + let snippet = { + let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + if !then_lit { + sugg = !sugg; + } + sugg + }; + let suggestion = { + let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); + // when used in else clause if statement should be wrapped in curly braces + if is_else_clause(cx.tcx, expr) { + s = s.blockify(); + } + s + }; + + let into_snippet = snippet.clone().maybe_par(); + let as_snippet = snippet.as_ty(ty); + + span_lint_and_then( + cx, + BOOL_TO_INT_WITH_IF, + expr.span, + "boolean to int conversion using if", + |diag| { + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); } } } -fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { - cond, - then, - r#else: Some(r#else), - }) = If::hir(expr) - && let Some(then_lit) = int_literal(then) - && let Some(else_lit) = int_literal(r#else) +fn as_int_bool_lit(e: &Expr<'_>) -> Option { + if let ExprKind::Block(b, _) = e.kind + && b.stmts.is_empty() + && let Some(e) = b.expr + && let ExprKind::Lit(lit) = e.kind + && let LitKind::Int(x, _) = lit.node { - let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) { - false - } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) { - true - } else { - // Expression isn't boolean, exit - return; - }; - let mut applicability = Applicability::MachineApplicable; - let snippet = { - let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - if inverted { - sugg = !sugg; - } - sugg - }; - - let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type - - let suggestion = { - let wrap_in_curly = is_else_clause(cx.tcx, expr); - let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); - if wrap_in_curly { - s = s.blockify(); - } - s - }; // when used in else clause if statement should be wrapped in curly braces - - let into_snippet = snippet.clone().maybe_par(); - let as_snippet = snippet.as_ty(ty); - - span_lint_and_then( - cx, - BOOL_TO_INT_WITH_IF, - expr.span, - "boolean to int conversion using if", - |diag| { - diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); - diag.note(format!( - "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" - )); - }, - ); - }; -} - -// If block contains only a int literal expression, return literal expression -fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { - if let ExprKind::Block(block, _) = expr.kind - && let Block { - stmts: [], // Shouldn't lint if statements with side effects - expr: Some(expr), - .. - } = block - && let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(_, _) = lit.node - { - Some(expr) + match x.get() { + 0 => Some(false), + 1 => Some(true), + _ => None, + } } else { None } diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs new file mode 100644 index 000000000000..a9fe190f1777 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs @@ -0,0 +1,80 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_ast::token::{Lit, LitKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for hard to read slices of byte characters, that could be more easily expressed as a + /// byte string. + /// + /// ### Why is this bad? + /// + /// Potentially makes the string harder to read. + /// + /// ### Example + /// ```ignore + /// &[b'H', b'e', b'l', b'l', b'o']; + /// ``` + /// Use instead: + /// ```ignore + /// b"Hello" + /// ``` + #[clippy::version = "1.68.0"] + pub BYTE_CHAR_SLICES, + style, + "hard to read byte char slice" +} +declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]); + +impl EarlyLintPass for ByteCharSlice { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let Some(slice) = is_byte_char_slices(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + BYTE_CHAR_SLICES, + expr.span, + "can be more succinctly written as a byte str", + "try", + format!("b\"{slice}\""), + Applicability::MaybeIncorrect, + ); + } + } +} + +fn is_byte_char_slices(expr: &Expr) -> Option { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind { + match &expr.kind { + ExprKind::Array(members) => { + if members.is_empty() { + return None; + } + + members + .iter() + .map(|member| match &member.kind { + ExprKind::Lit(Lit { + kind: LitKind::Byte, + symbol, + .. + }) => Some(symbol.as_str()), + _ => None, + }) + .map(|maybe_quote| match maybe_quote { + Some("\"") => Some("\\\""), + Some("\\'") => Some("'"), + other => other, + }) + .collect::>() + }, + _ => None, + } + } else { + None + } +} diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index e60c36ced75d..54f0c7c46871 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for casts from any numerical to a float type where + /// Checks for casts from any numeric type to a float type where /// the receiving type cannot store all values from the original type without /// rounding errors. This possible rounding is to be expected, so this lint is /// `Allow` by default. @@ -58,14 +58,14 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts from a signed to an unsigned numerical + /// Checks for casts from a signed to an unsigned numeric /// type. In this case, negative values wrap around to large positive values, - /// which can be quite surprising in practice. However, as the cast works as + /// which can be quite surprising in practice. However, since the cast works as /// defined, this lint is `Allow` by default. /// /// ### Why is this bad? /// Possibly surprising results. You can activate this lint - /// as a one-time check to see where numerical wrapping can arise. + /// as a one-time check to see where numeric wrapping can arise. /// /// ### Example /// ```no_run @@ -80,7 +80,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may + /// Checks for casts between numeric types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by /// default. It suggests user either explicitly ignore the lint, /// or use `try_from()` and handle the truncation, default, or panic explicitly. @@ -120,17 +120,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for casts from an unsigned type to a signed type of - /// the same size, or possibly smaller due to target dependent integers. - /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is - /// changed at the bit level, and the binary representation of the value is + /// the same size, or possibly smaller due to target-dependent integers. + /// Performing such a cast is a no-op for the compiler (that is, nothing is + /// changed at the bit level), and the binary representation of the value is /// reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// /// ### Why is this bad? /// While such a cast is not bad in itself, the results can - /// be surprising when this is not the intended behavior, as demonstrated by the - /// example below. + /// be surprising when this is not the intended behavior: /// /// ### Example /// ```no_run @@ -144,16 +143,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may - /// be replaced by safe conversion functions. + /// Checks for casts between numeric types that can be replaced by safe + /// conversion functions. /// /// ### Why is this bad? - /// Rust's `as` keyword will perform many kinds of - /// conversions, including silently lossy conversions. Conversion functions such - /// as `i32::from` will only perform lossless conversions. Using the conversion - /// functions prevents conversions from turning into silent lossy conversions if - /// the types of the input expressions ever change, and make it easier for - /// people reading the code to know that the conversion is lossless. + /// Rust's `as` keyword will perform many kinds of conversions, including + /// silently lossy conversions. Conversion functions such as `i32::from` + /// will only perform lossless conversions. Using the conversion functions + /// prevents conversions from becoming silently lossy if the input types + /// ever change, and makes it clear for people reading the code that the + /// conversion is lossless. /// /// ### Example /// ```no_run @@ -177,19 +176,21 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer types, casts of float - /// literals to float types and casts between raw pointers without changing type or constness. + /// Checks for casts to the same type, casts of int literals to integer + /// types, casts of float literals to float types, and casts between raw + /// pointers that don't change type or constness. /// /// ### Why is this bad? /// It's just unnecessary. /// /// ### Known problems - /// When the expression on the left is a function call, the lint considers the return type to be - /// a type alias if it's aliased through a `use` statement - /// (like `use std::io::Result as IoResult`). It will not lint such cases. + /// When the expression on the left is a function call, the lint considers + /// the return type to be a type alias if it's aliased through a `use` + /// statement (like `use std::io::Result as IoResult`). It will not lint + /// such cases. /// - /// This check is also rather primitive. It will only work on primitive types without any - /// intermediate references, raw pointers and trait objects may or may not work. + /// This check will only work on primitive types without any intermediate + /// references: raw pointers and trait objects may or may not work. /// /// ### Example /// ```no_run @@ -211,17 +212,17 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts, using `as` or `pointer::cast`, - /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer + /// Checks for casts, using `as` or `pointer::cast`, from a + /// less strictly aligned pointer to a more strictly aligned pointer. /// /// ### Why is this bad? - /// Dereferencing the resulting pointer may be undefined - /// behavior. + /// Dereferencing the resulting pointer may be undefined behavior. /// /// ### Known problems - /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like - /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or + /// similar on the resulting pointer is fine. Is over-zealous: casts with + /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be + /// fine. Miri is able to do a more in-depth analysis. /// /// ### Example /// ```no_run @@ -234,20 +235,21 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CAST_PTR_ALIGNMENT, pedantic, - "cast from a pointer to a more-strictly-aligned pointer" + "cast from a pointer to a more strictly aligned pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of function pointers to something other than usize + /// Checks for casts of function pointers to something other than `usize`. /// /// ### Why is this bad? - /// Casting a function pointer to anything other than usize/isize is not portable across - /// architectures, because you end up losing bits if the target type is too small or end up with a - /// bunch of extra bits that waste space and add more instructions to the final binary than - /// strictly necessary for the problem + /// Casting a function pointer to anything other than `usize`/`isize` is + /// not portable across architectures. If the target type is too small the + /// address would be truncated, and target types larger than `usize` are + /// unnecessary. /// - /// Casting to isize also doesn't make sense since there are no signed addresses. + /// Casting to `isize` also doesn't make sense, since addresses are never + /// signed. /// /// ### Example /// ```no_run @@ -263,17 +265,17 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, style, - "casting a function pointer to a numeric type other than usize" + "casting a function pointer to a numeric type other than `usize`" } declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to a numeric type not wide enough to - /// store address. + /// store an address. /// /// ### Why is this bad? /// Such a cast discards some bits of the function's address. If this is intended, it would be more - /// clearly expressed by casting to usize first, then casting the usize to the intended type (with + /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with /// a comment) to perform the truncation. /// /// ### Example @@ -306,7 +308,7 @@ declare_clippy_lint! { /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt-out of casting functions to integers in + /// low-level with function pointers then you can opt out of casting functions to integers in /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function /// pointer casts in your code. /// @@ -349,8 +351,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// In general, casting values to smaller types is /// error-prone and should be avoided where possible. In the particular case of - /// converting a character literal to u8, it is easy to avoid by just using a - /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter + /// converting a character literal to `u8`, it is easy to avoid by just using a + /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter /// than `'a' as u8`. /// /// ### Example @@ -371,12 +373,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers without changing its mutability, - /// namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// Checks for `as` casts between raw pointers that don't change their + /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because - /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + /// Though `as` casts between raw pointers are not terrible, + /// `pointer::cast` is safer because it cannot accidentally change the + /// pointer's mutability, nor cast the pointer to other types like `usize`. /// /// ### Example /// ```no_run @@ -395,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to + /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? @@ -423,12 +426,12 @@ declare_clippy_lint! { #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, pedantic, - "casting using `as` from and to raw pointers to change constness when specialized methods apply" + "casting using `as` on raw pointers to change constness when specialized methods apply" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// Checks for casts from an enum type to an integral type that will definitely truncate the /// value. /// /// ### Why is this bad? @@ -442,7 +445,7 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub CAST_ENUM_TRUNCATION, suspicious, - "casts from an enum type to an integral type which will truncate the value" + "casts from an enum type to an integral type that will truncate the value" } declare_clippy_lint! { @@ -621,7 +624,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer + /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. /// /// ### Why is this bad? /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 2c168405ee26..86c5f6b9f0ba 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { cx, PTR_AS_PTR, expr.span, - "`as` casting between raw pointers without changing its mutability", + "`as` casting between raw pointers without changing their constness", help, final_suggestion, app, diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs new file mode 100644 index 000000000000..b54f392bf2fa --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -0,0 +1,60 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::NestedMetaItem; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`) + /// + /// ### Why is this bad? + /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code. + /// Enabling this also guards against excessive mockery as well, which is an anti-pattern. + /// + /// ### Example + /// ```rust + /// # fn important_check() {} + /// #[cfg(not(test))] + /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage! + /// ``` + /// Use instead: + /// ```rust + /// # fn important_check() {} + /// important_check(); + /// ``` + #[clippy::version = "1.73.0"] + pub CFG_NOT_TEST, + restriction, + "enforce against excluding code from test builds" +} + +declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); + +impl EarlyLintPass for CfgNotTest { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { + if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } + } +} + +fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool { + list.is_some_and(|list| { + list.iter().any(|item| { + item.ident().is_some_and(|ident| match ident.name { + rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), + rustc_span::sym::test => not, + _ => contains_not_test(item.meta_item_list(), not), + }) + }) + }) +} diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 638de5e818c8..eabc67601a2f 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO, @@ -73,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO, crate::borrow_deref_ref::BORROW_DEREF_REF_INFO, crate::box_default::BOX_DEFAULT_INFO, + crate::byte_char_slices::BYTE_CHAR_SLICES_INFO, crate::cargo::CARGO_COMMON_METADATA_INFO, crate::cargo::LINT_GROUPS_PRIORITY_INFO, crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO, @@ -103,6 +102,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::casts::REF_AS_PTR_INFO, crate::casts::UNNECESSARY_CAST_INFO, crate::casts::ZERO_PTR_INFO, + crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, @@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, + crate::manual_rotate::MANUAL_ROTATE_INFO, crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, @@ -503,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO, crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO, crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO, + crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO, crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO, crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO, crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO, @@ -585,12 +587,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::VERBOSE_BIT_MASK_INFO, crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO, crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO, - crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO, crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO, crate::panic_unimplemented::PANIC_INFO, crate::panic_unimplemented::TODO_INFO, crate::panic_unimplemented::UNIMPLEMENTED_INFO, crate::panic_unimplemented::UNREACHABLE_INFO, + crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO, crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO, crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO, crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, @@ -644,6 +646,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO, crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO, crate::serde_api::SERDE_API_MISUSE_INFO, + crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO, crate::shadow::SHADOW_REUSE_INFO, crate::shadow::SHADOW_SAME_INFO, crate::shadow::SHADOW_UNRELATED_INFO, @@ -679,7 +682,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, - crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 2b3f4854255c..72fa05be3cc6 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // Avoid cases already linted by `field_reassign_with_default` && !self.reassigned_linted.contains(&expr.span) && let ExprKind::Call(path, ..) = expr.kind - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::default_fn, def_id) @@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding let stmts_head = match block.stmts { + [] | [_] => return, // Skip the last statement since there cannot possibly be any following statements that re-assign fields. - [head @ .., _] if !head.is_empty() => head, - _ => return, + [head @ .., _] => head, }; for (stmt_idx, stmt) in stmts_head.iter().enumerate() { // find all binding statements like `let mut _ = T::default()` where `T::default()` is the @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind // only take `let ...` statements && let Some(expr) = local.init - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && !expr.span.from_expansion() // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index ff631909bcb5..9af73db6849f 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { let hir = cx.tcx.hir(); + // NOTE: this is different from `clippy_utils::is_inside_always_const_context`. + // Inline const supports type inference. let is_parent_const = matches!( hir.body_const_context(hir.body_owner_def_id(body.id())), Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a115f8d06314..253f9959e13e 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, + expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, + ExprUseNode, }; use core::mem; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; @@ -175,6 +176,7 @@ struct StateData<'tcx> { adjusted_ty: Ty<'tcx>, } +#[derive(Debug)] struct DerefedBorrow { count: usize, msg: &'static str, @@ -182,6 +184,7 @@ struct DerefedBorrow { for_field_access: Option, } +#[derive(Debug)] enum State { // Any number of deref method calls. DerefMethod { @@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum TyCoercionStability { Deref, Reborrow, @@ -1042,16 +1045,28 @@ fn report<'tcx>( return; } - let (prefix, precedence) = if let Some(mutability) = mutability - && !typeck.expr_ty(expr).is_ref() + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, PREC_PREFIX) - } else { - ("", 0) + let (src, n_src_refs) = peel_middle_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, precedence) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, PREC_PREFIX) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0), + _ => ("", 0), }; span_lint_hir_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index 9de879604e2e..38fe687f7ccf 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -1,6 +1,6 @@ use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::Call(receiver, _) = parent.kind - && receiver.hir_id == expr.hir_id - { - None - } else { - path_def_id(cx, expr) + let (id, span) = match &expr.kind { + ExprKind::Path(path) + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = + cx.qpath_res(path, expr.hir_id) => + { + (id, expr.span) + }, + ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { + (id, name.ident.span) + }, + _ => return, }; - let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else { - return; - }; - let conf = match self.disallowed.get(&def_id) { - Some(&index) => &self.conf_disallowed[index], - None => return, - }; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&index) = self.disallowed.get(&id) { + let conf = &self.conf_disallowed[index]; + let msg = format!("use of a disallowed method `{}`", conf.path()); + span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { + if let Some(reason) = conf.reason() { + diag.note(reason); + } + }); + } } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 2afbf184117e..58809604c373 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Item, Pat, PatKind}; +use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -27,52 +27,30 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedNames { disallow: FxHashSet, - test_modules_deep: u32, } impl DisallowedNames { pub fn new(disallowed_names: &[String]) -> Self { Self { disallow: disallowed_names.iter().cloned().collect(), - test_modules_deep: 0, } } - - fn in_test_module(&self) -> bool { - self.test_modules_deep != 0 - } } impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { - fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } - } - fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - // Check whether we are under the `test` attribute. - if self.in_test_module() { - return; - } - - if let PatKind::Binding(.., ident, _) = pat.kind { - if self.disallow.contains(&ident.name.to_string()) { - span_lint( - cx, - DISALLOWED_NAMES, - ident.span, - format!("use of a disallowed/placeholder name `{}`", ident.name), - ); - } - } - } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); + if let PatKind::Binding(.., ident, _) = pat.kind + && self.disallow.contains(&ident.name.to_string()) + && !is_in_test(cx.tcx, pat.hir_id) + { + span_lint( + cx, + DISALLOWED_NAMES, + ident.span, + format!("use of a disallowed/placeholder name `{}`", ident.name), + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index a995f06fb73d..5ce11900adf8 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents { // Note: `symbol.as_str()` is an expensive operation, thus should not be called // more than once for a single symbol. let symbol_str = symbol.as_str(); - if symbol_str.is_ascii() { - continue; - } - for c in symbol_str.chars() { - // We want to iterate through all the scripts associated with this character - // and check whether at least of one scripts is in the whitelist. - let forbidden_script = c - .script_extension() - .iter() - .find(|script| !self.whitelist.contains(script)); - if let Some(script) = forbidden_script { - span_lint( - cx, - DISALLOWED_SCRIPT_IDENTS, - span, - format!( - "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", - script.full_name() - ), - ); - // We don't want to spawn warning multiple times over a single identifier. - break; - } + // Check if any character in the symbol is not part of any allowed script. + // Fast path for ascii-only idents. + if !symbol_str.is_ascii() + && let Some(script) = symbol_str.chars().find_map(|c| { + c.script_extension() + .iter() + .find(|script| !self.whitelist.contains(script)) + }) + { + span_lint( + cx, + DISALLOWED_SCRIPT_IDENTS, + span, + format!( + "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", + script.full_name() + ), + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs index 38bc58a55019..bd1cc46e1850 100644 --- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -22,6 +22,7 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], + line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -46,11 +47,35 @@ pub(super) fn check( .sum(); if ccount < blockquote_level || lcount < list_indentation { let msg = if ccount < blockquote_level { - "doc quote missing `>` marker" + "doc quote line without `>` marker" } else { - "doc list item missing indentation" + "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { + let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); + if snippet.chars().filter(|&c| c == '\n').count() > 1 + && let Some(doc_comment_start) = snippet.rfind('\n') + && let doc_comment = snippet[doc_comment_start..].trim() + && (doc_comment == "///" || doc_comment == "//!") + { + // suggest filling in a blank line + diag.span_suggestion_with_style( + line_break_span.shrink_to_lo(), + "if this should be its own paragraph, add a blank doc comment line", + format!("\n{doc_comment}"), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + if ccount > 0 || blockquote_level > 0 { + diag.help("if this not intended to be a quote at all, escape it with `\\>`"); + } else { + let indent = list_indentation - lcount; + diag.help(format!( + "if this is intended to be part of the list, indent {indent} spaces" + )); + } + return; + } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 3e210fd153bf..a2a1a51920f3 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -6,7 +6,8 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ - Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, + Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, + TaskListMarker, Text, }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; @@ -747,7 +748,8 @@ fn check_doc<'a, Events: Iterator, Range in_footnote_definition = true, End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, - Start(_) | End(_) => (), // We don't care about other tags + Start(_) | End(_) // We don't care about other tags + | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (), SoftBreak | HardBreak => { if !containers.is_empty() && let Some((next_event, next_range)) = events.peek() @@ -762,13 +764,24 @@ fn check_doc<'a, Events: Iterator, Range (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; - ticks_unbalanced |= text.contains('`') && !in_code; + let range_ = range.clone(); + ticks_unbalanced |= text.contains('`') + && !in_code + && doc[range.clone()].bytes().enumerate().any(|(i, c)| { + // scan the markdown source code bytes for backquotes that aren't preceded by backslashes + // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii) + // - relevant backquotes are within doc[range], but backslashes are not, because they're not + // actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes) + // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in + // usize, that would underflow and maybe panic + c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\')) + }); if Some(&text) == in_link.as_ref() || ticks_unbalanced { // Probably a link of the form `` // Which are represented as a link to "http://example.com" with diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index bb766e963387..99328e3e643f 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// /// ### Why restrict this? - /// To ensure use of big endian or the target’s endianness rather than little endian. + /// To ensure use of big-endian or the target’s endianness rather than little-endian. /// /// ### Example /// ```rust,ignore @@ -51,7 +51,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// /// ### Why restrict this? - /// To ensure use of little endian or the target’s endianness rather than big endian. + /// To ensure use of little-endian or the target’s endianness rather than big-endian. /// /// ### Example /// ```rust,ignore diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs index 6fb38a0d6dd8..cf85c74e688d 100644 --- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { if let FnKind::ItemFn(_, generics, _) = kind && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, hir_id) + && !is_in_test(cx.tcx, hir_id) { for param in generics.params { if param.is_impl_trait() { @@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { && of_trait.is_none() && let body = cx.tcx.hir().body(body_id) && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, impl_item.hir_id()) + && !is_in_test(cx.tcx, impl_item.hir_id()) { for param in impl_item.generics.params { if param.is_impl_trait() { @@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id()) // ^^ (Will always be a trait) && !item.vis_span.is_empty() // Is public - && !is_in_test_function(cx.tcx, trait_item.hir_id()) + && !is_in_test(cx.tcx, trait_item.hir_id()) { for param in trait_item.generics.params { if param.is_impl_trait() { diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 35b4481bfee7..5c63d48adaf0 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; @@ -88,7 +88,7 @@ impl IncompatibleMsrv { return; } let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) { + if self.msrv.meets(version) || is_in_test(cx.tcx, node) { return; } if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index 9aedf5ec7e85..ec6174bc0301 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S impl<'tcx> LateLintPass<'tcx> for InherentToString { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if impl_item.span.from_expansion() { - return; - } - // Check if item is a method called `to_string` and has a parameter 'self' if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // #11201 @@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { && decl.implicit_self.has_implicit_self() && decl.inputs.len() == 1 && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + && !impl_item.span.from_expansion() // Check if return type is String && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String) // Filters instances of to_string which are required by a trait diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index 1c8fd0a27f98..7f183bb601eb 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -1,13 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::SyntaxContext; use std::borrow::Cow; -use std::cmp::Reverse; -use std::collections::BinaryHeap; declare_clippy_lint! { /// ### What it does @@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); impl<'tcx> LateLintPass<'tcx> for NumberedFields { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Struct(path, fields, None) = e.kind { - if !fields.is_empty() - && !e.span.from_expansion() - && fields - .iter() - .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) - && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..)) - { - let expr_spans = fields - .iter() - .map(|f| (Reverse(f.ident.as_str().parse::().unwrap()), f.expr.span)) - .collect::>(); - let mut appl = Applicability::MachineApplicable; - let snippet = format!( - "{}({})", - snippet_with_applicability(cx, path.span(), "..", &mut appl), - expr_spans - .into_iter_sorted() - .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0) - .intersperse(Cow::Borrowed(", ")) - .collect::() - ); - span_lint_and_sugg( - cx, - INIT_NUMBERED_FIELDS, - e.span, - "used a field initializer for a tuple struct", - "try", - snippet, - appl, - ); - } + if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind + // If the first character of any field is a digit it has to be a tuple. + && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit) + // Type aliases can't be used as functions. + && !matches!( + cx.qpath_res(path, e.hir_id), + Res::Def(DefKind::TyAlias | DefKind::AssocTy, _) + ) + // This is the only syntax macros can use that works for all struct types. + && !e.span.from_expansion() + && let mut has_side_effects = false + && let Ok(mut expr_spans) = fields + .iter() + .map(|f| { + has_side_effects |= f.expr.can_have_side_effects(); + f.ident.as_str().parse::().map(|x| (x, f.expr.span)) + }) + .collect::, _>>() + // We can only reorder the expressions if there are no side effects. + && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx)) + { + span_lint_and_then( + cx, + INIT_NUMBERED_FIELDS, + e.span, + "used a field initializer for a tuple struct", + |diag| { + if !has_side_effects { + // We already checked the order if there are side effects. + expr_spans.sort_by_key(|&(idx, _)| idx); + } + let mut app = Applicability::MachineApplicable; + diag.span_suggestion( + e.span, + "use tuple initialization", + format!( + "{}({})", + snippet_with_applicability(cx, path.span(), "..", &mut app), + expr_spans + .into_iter() + .map( + |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0 + ) + .intersperse(Cow::Borrowed(", ")) + .collect::() + ), + app, + ); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 860258fd030e..5657c58bb0a4 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; -use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - check_attrs(cx, item.ident.name, attrs); + if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind + && let Some(attr) = cx + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .find(|a| a.has_name(sym::inline)) + { + span_lint_and_then( + cx, + INLINE_FN_WITHOUT_BODY, + attr.span, + format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), + |diag| { + diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); + }, + ); } } } - -fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { - for attr in attrs { - if !attr.has_name(sym::inline) { - continue; - } - - span_lint_and_then( - cx, - INLINE_FN_WITHOUT_BODY, - attr.span, - format!("use of `#[inline]` on trait method `{name}` which has no body"), - |diag| { - diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); - }, - ); - } -} diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 10b00f632bb0..5fe152d1e301 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction { lhs, rhs, ) = expr.kind + && let typeck = cx.typeck_results() + && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant) { + let rhs_ty = typeck.expr_ty(rhs); + if is_instant_now_call(cx, lhs) - && is_an_instant(cx, rhs) + && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant) && let Some(sugg) = Sugg::hir_opt(cx, rhs) { print_manual_instant_elapsed_sugg(cx, expr, sugg); - } else if !expr.span.from_expansion() + } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration) + && !expr.span.from_expansion() && self.msrv.meets(msrvs::TRY_FROM) - && is_an_instant(cx, lhs) - && is_a_duration(cx, rhs) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } @@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { } } -fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) -} - -fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration) -} - fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index 39223c20470b..a88d8e24fda8 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl LateLintPass<'_> for ItemsAfterStatements { fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { - if in_external_macro(cx.sess(), block.span) { - return; - } - - // skip initial items - let stmts = block - .stmts - .iter() - .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))); - - // lint on all further items - for stmt in stmts { - if let StmtKind::Item(item_id) = stmt.kind { - let item = cx.tcx.hir().item(item_id); - if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) { - return; - } - if let ItemKind::Macro(..) = item.kind { - // do not lint `macro_rules`, but continue processing further statements - continue; - } - span_lint_hir( - cx, - ITEMS_AFTER_STATEMENTS, - item.hir_id(), - item.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope", - ); - } + if block.stmts.len() > 1 { + let ctxt = block.span.ctxt(); + let mut in_external = None; + block + .stmts + .iter() + .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))) + .filter_map(|stmt| match stmt.kind { + StmtKind::Item(id) => Some(cx.tcx.hir().item(id)), + _ => None, + }) + // Ignore macros since they can only see previously defined locals. + .filter(|item| !matches!(item.kind, ItemKind::Macro(..))) + // Stop linting if macros define items. + .take_while(|item| item.span.ctxt() == ctxt) + // Don't use `next` due to the complex filter chain. + .for_each(|item| { + // Only do the macro check once, but delay it until it's needed. + if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) { + span_lint_hir( + cx, + ITEMS_AFTER_STATEMENTS, + item.hir_id(), + item.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope", + ); + } + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index 1b5f1b499475..ba0cd5d6eb35 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// ### What it does @@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") { - if let TraitItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + if let TraitItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) + { + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") + if let ImplItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) && !matches!( cx.tcx.parent_hir_node(item.hir_id()), Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some() ) { - if let ImplItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } } -fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { +fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) { if sig.decl.implicit_self.has_implicit_self() { let ret_ty = cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 6b03f2597b08..1e6404190d3c 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { - if !in_external_macro(cx.sess(), item.span) - && let ItemKind::Impl(imp) = item.kind + if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait && trait_ref .trait_def_id() .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && !in_external_macro(cx.sess(), item.span) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 7f8197c0cc01..b18ab625e609 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !item.span.from_expansion() - && let ItemKind::Const(_, generics, _) = &item.kind + if let ItemKind::Const(_, generics, _) = &item.kind // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. && generics.params.is_empty() && !generics.has_where_clause_predicates + && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index 0bf7389ef9cc..85daadcc5373 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if in_external_macro(cx.tcx.sess, item.span) { - return; - } - if let ItemKind::Enum(ref def, _) = item.kind { - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - let ty::Adt(adt, subst) = ty.kind() else { - panic!("already checked whether this is an enum") - }; - if adt.variants().len() <= 1 { - return; - } + if let ItemKind::Enum(ref def, _) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let ty::Adt(adt, subst) = ty.kind() + && adt.variants().len() > 1 + && !in_external_macro(cx.tcx.sess, item.span) + { let variants_size = AdtVariantInfo::new(cx, *adt, subst); let mut difference = variants_size[0].size - variants_size[1].size; diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 07488a512a37..602227e42490 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); impl<'tcx> LateLintPass<'tcx> for LargeFuture { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) { - return; - } - if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind { - if let ExprKind::Call(func, [expr, ..]) = expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind - && let ty = cx.typeck_results().expr_ty(expr) - && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) - && let size = layout.layout.size() - && size >= Size::from_bytes(self.future_size_threshold) - { - span_lint_and_sugg( - cx, - LARGE_FUTURES, - expr.span, - format!("large future with a size of {} bytes", size.bytes()), - "consider `Box::pin` on it", - format!("Box::pin({})", snippet(cx, expr.span, "..")), - Applicability::Unspecified, - ); - } + if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind + && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind + && !expr.span.from_expansion() + && let ty = cx.typeck_results().expr_ty(arg) + && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let size = layout.layout.size() + && size >= Size::from_bytes(self.future_size_threshold) + { + span_lint_and_sugg( + cx, + LARGE_FUTURES, + arg.span, + format!("large future with a size of {} bytes", size.bytes()), + "consider `Box::pin` on it", + format!("Box::pin({})", snippet(cx, arg.span, "..")), + Applicability::Unspecified, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 07efee159aab..2688283a6ce8 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(cx, expr) - && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id) - && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) - && let ExprKind::Lit(lit) = &expr.kind - { - let len = match &lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let len = match &lit.node { // include_bytes LitKind::ByteStr(bstr, _) => bstr.len(), // include_str LitKind::Str(sym, _) => sym.as_str().len(), _ => return, - }; - - if len as u64 <= self.max_file_size { - return; } - + && len as u64 > self.max_file_size + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) + || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + { span_lint_and_note( cx, LARGE_INCLUDE_FILE, diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index eadfeb6e3418..a08b40bef372 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) { - return; - } - // Integer modules are "TBD" deprecated, and the contents are too, // so lint on the `use` statement directly. if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), item.span) && let Some(def_id) = path.res[0].opt_def_id() { let module = if is_integer_module(cx, def_id) { @@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { - return; - } - let ExprKind::Path(qpath) = expr.kind else { + let ExprKind::Path(qpath) = &expr.kind else { return; }; @@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { ) // `::xxx_value` check } else if let QPath::TypeRelative(_, last_segment) = qpath - && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() - && is_integer_method(cx, def_id) + && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() && let Some(par_expr) = get_parent_expr(cx, expr) - && let ExprKind::Call(_, _) = par_expr.kind + && let ExprKind::Call(_, []) = par_expr.kind + && is_integer_method(cx, def_id) { let name = last_segment.ident.name.as_str(); @@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { return; }; - if is_from_proc_macro(cx, expr) { - return; + if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + diag.span_suggestion_with_style( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + }); } - - span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_with_style( - span, - "use the associated constant instead", - sugg, - Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, - ); - }); } extract_msrv_attr!(LateContext); diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 57e0a7aa2c7e..4c737371bd23 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.span.from_expansion() { - return; - } - - if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind { + if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind + && !item.span.from_expansion() + { check_trait_items(cx, item, trait_items); } } @@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Let(lt) = expr.kind - && has_is_empty(cx, lt.init) && match lt.pat.kind { PatKind::Slice([], None, []) => true, PatKind::Lit(lit) if is_empty_string(lit) => true, _ => false, } + && !expr.span.from_expansion() + && has_is_empty(cx, lt.init) { let mut applicability = Applicability::MachineApplicable; @@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } - if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind + && !expr.span.from_expansion() + { // expr.span might contains parenthesis, see issue #10529 let actual_span = span_without_enclosing_paren(cx, expr.span); match cmp { diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index a65cb3f4dfb4..0e488cee6b74 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]); impl<'tcx> LateLintPass<'tcx> for LetIfSeq { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let mut it = block.stmts.iter().peekable(); - while let Some(stmt) = it.next() { - if let Some(expr) = it.peek() - && let hir::StmtKind::Let(local) = stmt.kind + for [stmt, next] in block.stmts.array_windows::<2>() { + if let hir::StmtKind::Let(local) = stmt.kind && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind - && let hir::StmtKind::Expr(if_) = expr.kind + && let hir::StmtKind::Expr(if_) = next.kind && let hir::ExprKind::If( hir::Expr { kind: hir::ExprKind::DropTemps(cond), diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 9fd4f509aa47..8fa63f3e8fde 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if matches!(local.source, LocalSource::Normal) - && !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init + && !in_external_macro(cx.tcx.sess, local.span) { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index 593b29154b42..5a11702d7ce5 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet; +use clippy_utils::is_from_proc_macro; use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -25,19 +25,14 @@ declare_clippy_lint! { } declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); -impl LateLintPass<'_> for UnderscoreTyped { - fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { - if !in_external_macro(cx.tcx.sess, local.span) - && let Some(ty) = local.ty // Ensure that it has a type defined +impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { + if let Some(ty) = local.ty // Ensure that it has a type defined && let TyKind::Infer = &ty.kind // that type is '_' && local.span.eq_ctxt(ty.span) + && !in_external_macro(cx.tcx.sess, local.span) + && !is_from_proc_macro(cx, ty) { - // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, - // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` - if snippet(cx, ty.span, "_").trim() != "_" { - return; - } - span_lint_and_help( cx, LET_WITH_TYPE_UNDERSCORE, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 32fad0f02cea..c2dc26d6605b 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -4,7 +4,9 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(is_sorted)] #![feature(iter_intersperse)] +#![feature(iter_partition_in_place)] #![feature(let_chains)] #![cfg_attr(bootstrap, feature(lint_reasons))] #![feature(never_type)] @@ -90,8 +92,10 @@ mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; mod box_default; +mod byte_char_slices; mod cargo; mod casts; +mod cfg_not_test; mod checked_conversions; mod cognitive_complexity; mod collapsible_if; @@ -212,6 +216,7 @@ mod manual_non_exhaustive; mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; +mod manual_rotate; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; @@ -229,6 +234,7 @@ mod mismatching_type_param_order; mod missing_assert_message; mod missing_asserts_for_indexing; mod missing_const_for_fn; +mod missing_const_for_thread_local; mod missing_doc; mod missing_enforced_import_rename; mod missing_fields_in_debug; @@ -275,9 +281,9 @@ mod only_used_in_recursion; mod operators; mod option_env_unwrap; mod option_if_let_else; -mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; +mod panicking_overflow_checks; mod partial_pub_fields; mod partialeq_ne_impl; mod partialeq_to_none; @@ -318,6 +324,7 @@ mod self_named_constructors; mod semicolon_block; mod semicolon_if_nothing_returned; mod serde_api; +mod set_contains_or_insert; mod shadow; mod significant_drop_tightening; mod single_call_fn; @@ -339,7 +346,6 @@ mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; mod tests_outside_test_module; -mod thread_local_initializer_can_be_made_const; mod to_digit_is_some; mod to_string_trait_impl; mod trailing_empty_array; @@ -639,9 +645,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); - store.register_late_pass(|_| { - Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new()) - }); store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); store.register_late_pass(|_| { Box::::default() @@ -788,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone()))); store.register_late_pass(|_| Box::new(swap::Swap)); - store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); + store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names))); store.register_late_pass(move |_| { @@ -1024,6 +1027,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate)); store.register_late_pass(move |_| { Box::new(operators::Operators::new( verbose_bit_mask_threshold, @@ -1153,9 +1157,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { behavior: pub_underscore_fields_behavior, }) }); - store.register_late_pass(move |_| { - Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv())) - }); + store + .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv()))); store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); @@ -1171,6 +1174,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); + store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains)); + store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); + store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index d2a140a36a83..7481543941a6 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -233,11 +233,9 @@ impl_lint_pass!(LiteralDigitGrouping => [ impl EarlyLintPass for LiteralDigitGrouping { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } @@ -448,11 +446,9 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION] impl EarlyLintPass for DecimalLiteralRepresentation { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 24fc2b4faeac..d9f6be6dc2b5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]); impl<'tcx> LateLintPass<'tcx> for ManualBits { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::MANUAL_BITS) { - return; - } - if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind && let BinOpKind::Mul = &bin_op.node && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::MANUAL_BITS) && let ctxt = expr.span.ctxt() && left_expr.span.ctxt() == ctxt && right_expr.span.ctxt() == ctxt diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 89eea0b4456d..03416ba96de7 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -82,29 +82,26 @@ impl Variant { impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !in_external_macro(cx.sess(), expr.span) - && ( - matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().declared(sym!(const_float_classify)) - ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind + if let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind // Checking all possible scenarios using a function would be a hopeless task, as we have // 16 possible alignments of constants/operands. For now, let's use `partition`. - && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] - .into_iter() - .partition::>, _>(|i| path_to_local(i).is_some()) - && let [first, second] = &*operands - && let Some([const_1, const_2]) = constants - .into_iter() - .map(|i| constant(cx, cx.typeck_results(), i)) - .collect::>>() - .as_deref() + && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] + && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2 + && !in_external_macro(cx.sess(), expr.span) + && ( + matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) + || cx.tcx.features().declared(sym!(const_float_classify)) + ) + && let [first, second, const_1, const_2] = exprs + && let Some(const_1) = constant(cx, cx.typeck_results(), const_1) + && let Some(const_2) = constant(cx, cx.typeck_results(), const_2) && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s)) // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in // case somebody does that for some reason - && (is_infinity(const_1) && is_neg_infinity(const_2) - || is_neg_infinity(const_1) && is_infinity(const_2)) + && (is_infinity(&const_1) && is_neg_infinity(&const_2) + || is_neg_infinity(&const_1) && is_infinity(&const_2)) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 03e4d668dd8f..ebebdf679a86 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -49,16 +49,14 @@ declare_clippy_lint! { impl<'tcx> QuestionMark { pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { - if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { - return; - } - if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + && self.msrv.meets(msrvs::LET_ELSE) + && !in_external_macro(cx.sess(), stmt.span) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index 5732bdda7f2c..8e8cdc3fb076 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) - && let (target, _) = peel_hir_expr_refs(expr) - && is_trait_method(cx, target, sym::ToString) - && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + let (target, _) = peel_hir_expr_refs(expr); + if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && path.ident.name == sym::to_string && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && is_trait_method(cx, target, sym::ToString) + && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && ty.is_str() diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index d2ac0ad8363e..73a505fd73ff 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustiveStruct { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { - return; - } - - if let ast::ItemKind::Struct(variant_data, _) = &item.kind { - let (fields, delimiter) = match variant_data { + if let ast::ItemKind::Struct(variant_data, _) = &item.kind + && let (fields, delimiter) = match variant_data { ast::VariantData::Struct { fields, .. } => (&**fields, '{'), ast::VariantData::Tuple(fields, _) => (&**fields, '('), ast::VariantData::Unit(_) => return, - }; - if fields.len() <= 1 { - return; } + && fields.len() > 1 + && self.msrv.meets(msrvs::NON_EXHAUSTIVE) + { let mut iter = fields.iter().filter_map(|f| match f.vis.kind { VisibilityKind::Public => None, VisibilityKind::Inherited => Some(Ok(f)), diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index ec60de92c4ba..07d4abbf5cd1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -76,14 +76,11 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { - if in_external_macro(cx.sess(), pat.span) { - return; - } - // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives // or at least one range if let PatKind::Or(pats) = pat.kind && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); let mut max = Num::dummy(i128::MIN); diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index ab9bca170cf7..b518dc26937c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]); impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::REM_EUCLID) { - return; - } - - if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) { - return; - } - - if in_external_macro(cx.sess(), expr.span) { - return; - } - // (x % c + c) % c - if let ExprKind::Binary(op1, expr1, right) = expr.kind - && op1.node == BinOpKind::Rem + if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind + && rem_op.node == BinOpKind::Rem + && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind + && add_op.node == BinOpKind::Add && let ctxt = expr.span.ctxt() - && expr1.span.ctxt() == ctxt - && let Some(const1) = check_for_unsigned_int_constant(cx, right) - && let ExprKind::Binary(op2, left, right) = expr1.kind - && op2.node == BinOpKind::Add - && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right) - && expr2.span.ctxt() == ctxt - && let ExprKind::Binary(op3, expr3, right) = expr2.kind - && op3.node == BinOpKind::Rem - && let Some(const3) = check_for_unsigned_int_constant(cx, right) + && rem_lhs.span.ctxt() == ctxt + && rem_rhs.span.ctxt() == ctxt + && add_lhs.span.ctxt() == ctxt + && add_rhs.span.ctxt() == ctxt + && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::REM_EUCLID) + && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id)) + && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs) + && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs) + && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind + && rem2_op.node == BinOpKind::Rem + && const1 == const2 + && let Some(hir_id) = path_to_local(rem2_lhs) + && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs) // Also ensures the const is nonzero since zero can't be a divisor - && const1 == const2 && const2 == const3 - && let Some(hir_id) = path_to_local(expr3) - && let Node::Pat(_) = cx.tcx.hir_node(hir_id) + && const2 == const3 + && rem2_lhs.span.ctxt() == ctxt + && rem2_rhs.span.ctxt() == ctxt { // Apply only to params or locals with annotated types match cx.tcx.parent_hir_node(hir_id) { @@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { }; let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0; span_lint_and_sugg( cx, MANUAL_REM_EUCLID, diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 3ddb06a1e08a..8f7b8abd0c38 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]); impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Assign(left_expr, collect_expr, _) = &expr.kind - && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind + && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind && seg.args.is_none() - && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) { diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs new file mode 100644 index 000000000000..a517a4d50752 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs @@ -0,0 +1,117 @@ +use std::fmt::Display; + +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// It detects manual bit rotations that could be rewritten using standard + /// functions `rotate_left` or `rotate_right`. + /// + /// ### Why is this bad? + /// + /// Calling the function better conveys the intent. + /// + /// ### Known issues + /// + /// Currently, the lint only catches shifts by constant amount. + /// + /// ### Example + /// ```no_run + /// let x = 12345678_u32; + /// let _ = (x >> 8) | (x << 24); + /// ``` + /// Use instead: + /// ```no_run + /// let x = 12345678_u32; + /// let _ = x.rotate_right(8); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_ROTATE, + style, + "using bit shifts to rotate integers" +} + +declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ShiftDirection { + Left, + Right, +} + +impl Display for ShiftDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Left => "rotate_left", + Self::Right => "rotate_right", + }) + } +} + +fn parse_shift<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> { + if let ExprKind::Binary(op, l, r) = expr.kind { + let dir = match op.node { + BinOpKind::Shl => ShiftDirection::Left, + BinOpKind::Shr => ShiftDirection::Right, + _ => return None, + }; + let const_expr = constant(cx, cx.typeck_results(), r)?; + if let Constant::Int(shift) = const_expr { + return Some((dir, shift, l)); + } + } + None +} + +impl LateLintPass<'_> for ManualRotate { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Binary(op, l, r) = expr.kind + && let BinOpKind::Add | BinOpKind::BitOr = op.node + && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l) + && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r) + { + if l_shift_dir == r_shift_dir { + return; + } + if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) { + return; + } + let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() { + ty::Int(itype) => itype.bit_width(), + ty::Uint(itype) => itype.bit_width(), + _ => return, + }) else { + return; + }; + if l_amount + r_amount == u128::from(bit_width) { + let (shift_function, amount) = if l_amount < r_amount { + (l_shift_dir, l_amount) + } else { + (r_shift_dir, r_amount) + }; + let mut applicability = Applicability::MachineApplicable; + let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par(); + span_lint_and_sugg( + cx, + MANUAL_ROTATE, + expr.span, + "there is no need to manually implement bit rotation", + "this expression can be rewritten as", + format!("{expr_sugg}.{shift_function}({amount})"), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs index 1de686dbcb51..429ee2637c2f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs +++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs @@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION] impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Does not apply inside const because size_of_val is not cost in stable. - if !in_constant(cx, expr.hir_id) - && let ExprKind::Binary(ref op, left, right) = expr.kind + if let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node && !expr.span.from_expansion() + // Does not apply inside const because size_of_val is not cost in stable. + && !in_constant(cx, expr.hir_id) && let Some(receiver) = simplify(cx, left, right) { let ctxt = expr.span.ctxt(); diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 45af9f07718d..6a523ad15647 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -66,14 +66,11 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { - return; - } - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind - && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) && let ExprKind::Path(target_path) = &target_arg.kind + && self.msrv.meets(msrvs::STR_STRIP_PREFIX) + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { StripKind::Prefix diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs index 58b2ebebbf08..f1acc4b21748 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs @@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { - return; - } - // Call handle only if the expression is `if let` or `match` - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) { + if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { handle(cx, if_let_or_match, expr); } } diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 9db04b615be7..2db71b1f7a38 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -253,14 +253,11 @@ fn lint_map_unit_fn( impl<'tcx> LateLintPass<'tcx> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { - if stmt.span.from_expansion() { - return; - } - - if let hir::StmtKind::Semi(expr) = stmt.kind { - if let Some(arglists) = method_chain_args(expr, &["map"]) { - lint_map_unit_fn(cx, stmt, expr, arglists[0]); - } + if let hir::StmtKind::Semi(expr) = stmt.kind + && !stmt.span.from_expansion() + && let Some(arglists) = method_chain_args(expr, &["map"]) + { + lint_map_unit_fn(cx, stmt, expr, arglists[0]); } } } diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index bf7156cc53ec..22a299ae3d82 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [ ]); impl<'tcx> LateLintPass<'tcx> for Matches { + #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) { return; @@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { - significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); + significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source); } collapsible_match::check_match(cx, arms, &self.msrv); @@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); + significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { if self.msrv.meets(msrvs::MATCHES_MACRO) { @@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches { ); needless_match::check_if_let(cx, expr, &if_let); } - } else if !from_expansion { - redundant_pattern_match::check(cx, expr); + } else { + if let Some(while_let) = higher::WhileLet::hir(expr) { + significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then); + } + if !from_expansion { + redundant_pattern_match::check(cx, expr); + } } } diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 2f72e59834fa..9047c9627d9a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; -pub(super) fn check<'tcx>( +pub(super) fn check_match<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, scrutinee: &'tcx Expr<'_>, @@ -27,10 +27,89 @@ pub(super) fn check<'tcx>( return; } - let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source); + let scrutinee = match (source, &scrutinee.kind) { + (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, + _ => scrutinee, + }; + + let message = if source == MatchSource::Normal { + "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" + } else { + "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" + }; + + let arms = arms.iter().map(|arm| arm.body).collect::>(); + + check(cx, expr, scrutinee, &arms, message, Suggestion::Emit); +} + +pub(super) fn check_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + if_then: &'tcx Expr<'_>, + if_else: Option<&'tcx Expr<'_>>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + let message = + "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression"; + + if let Some(if_else) = if_else { + check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit); + } else { + check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit); + } +} + +pub(super) fn check_while_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + check( + cx, + expr, + scrutinee, + &[body], + "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression", + // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply + // moving it out. We need to change the `while` to a `loop` instead. + Suggestion::DontEmit, + ); +} + +#[derive(Copy, Clone, Debug)] +enum Suggestion { + Emit, + DontEmit, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + arms: &[&'tcx Expr<'_>], + message: &'static str, + sugg: Suggestion, +) { + let mut helper = SigDropHelper::new(cx); + let suggestions = helper.find_sig_drop(scrutinee); + for found in suggestions { span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { - set_diagnostic(diag, cx, expr, found); + match sugg { + Suggestion::Emit => set_suggestion(diag, cx, expr, found), + Suggestion::DontEmit => (), + } + let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); diag.span_label(s, "temporary lives until here"); for span in has_significant_drop_in_arms(cx, arms) { @@ -41,7 +120,7 @@ pub(super) fn check<'tcx>( } } -fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { +fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { let original = snippet(cx, found.found_span, ".."); let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); @@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: & ); } -/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that -/// may have a surprising lifetime. -fn has_significant_drop_in_scrutinee<'tcx>( - cx: &LateContext<'tcx>, - scrutinee: &'tcx Expr<'tcx>, - source: MatchSource, -) -> (Vec, &'static str) { - let mut helper = SigDropHelper::new(cx); - let scrutinee = match (source, &scrutinee.kind) { - (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, - _ => scrutinee, - }; - let message = if source == MatchSource::Normal { - "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" - } else { - "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" - }; - (helper.find_sig_drop(scrutinee), message) -} - struct SigDropChecker<'a, 'tcx> { seen_types: FxHashSet>, cx: &'a LateContext<'tcx>, @@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { } } -fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet { let mut helper = ArmSigDropHelper::new(cx); for arm in arms { - helper.visit_expr(arm.body); + helper.visit_expr(arm); } helper.found_sig_drop_spans } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index e3ce64c246a5..cac2e11f5916 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { edits.extend(addr_of_edits); } - edits.push(( - name_span, - String::from(match name { - "map" => "inspect", - "map_err" => "inspect_err", - _ => return, - }), - )); + let edit = match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }; + edits.push((name_span, edit.to_string())); edits.push(( final_expr .span @@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { Applicability::MachineApplicable }; - span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { - diag.multipart_suggestion("try", edits, app); - }); + span_lint_and_then( + cx, + MANUAL_INSPECT, + name_span, + format!("using `{name}` over `{edit}`"), + |diag| { + diag.multipart_suggestion("try", edits, app); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 1408f4548200..a846552cddfa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -628,12 +628,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or - /// `_.or_else(|x| Err(y))`. + /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` + /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// Readability, this can be written more concisely as - /// `_.map(|x| y)` or `_.map_err(|x| y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example /// ```no_run @@ -4121,7 +4120,7 @@ declare_clippy_lint! { /// ```no_run /// let x = Some(0).inspect(|x| println!("{x}")); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub MANUAL_INSPECT, complexity, "use of `map` returning the original item" diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index ae9aa83efd68..5d899415d772 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,13 +1,15 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, }; use clippy_utils::visitors::find_all_ret_expressions; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; +use clippy_utils::{ + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -52,6 +54,9 @@ pub fn check<'tcx>( if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { return; } + if check_string_from_utf8(cx, expr, receiver) { + return; + } check_other_call_arg(cx, expr, method_name, receiver); } } else { @@ -240,6 +245,65 @@ fn check_into_iter_call_arg( false } +/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`, +/// which can be written as just `std::str::from_utf8(bytes).unwrap()`. +fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool { + if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr) + && !arg.span.from_expansion() + && let ExprKind::Call(callee, _) = call.kind + && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8)) + && let Some(unwrap_call) = get_parent_expr(cx, call) + && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind + && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect) + && let Some(ref_string) = get_parent_expr(cx, unwrap_call) + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind + && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string) + // `&...` creates a `&String`, so only actually lint if this coerces to a `&str` + && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) + { + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + ref_string.span, + "allocating a new `String` only to create a temporary `&str` from it", + |diag| { + let arg_suggestion = format!( + "{borrow}{recv_snippet}", + recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."), + borrow = if cx.typeck_results().expr_ty(receiver).is_ref() { + "" + } else { + // If not already a reference, prefix with a borrow so that it can coerce to one + "&" + } + ); + + diag.multipart_suggestion( + "convert from `&[u8]` to `&str` directly", + vec![ + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^^^^ + (callee.span, "core::str::from_utf8".into()), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^ + ( + ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()), + String::new(), + ), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^ + (arg.span, arg_suggestion), + ], + Applicability::MachineApplicable, + ); + }, + ); + true + } else { + false + } +} + /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs index 516b8984ad79..5b0bd0f716ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; -use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; +use clippy_utils::{is_in_test, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; @@ -61,7 +61,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { + if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index fca626fa5c35..c3fbca1d560e 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; -use std::cmp::Ordering; +use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { /// ### What it does @@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]); impl<'tcx> LateLintPass<'tcx> for MinMaxPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) { - if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) { - if outer_max == inner_max { - return; - } - match ( - outer_max, - Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c), - ) { - (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), - _ => { - span_lint( - cx, - MIN_MAX, - expr.span, - "this `min`/`max` combination leads to constant result", - ); - }, - } - } + if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) + && let Some((inner_max, inner_c, ie)) = min_max(cx, oe) + && outer_max != inner_max + && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c) + && matches!( + (outer_max, ord), + (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less) + ) + { + span_lint( + cx, + MIN_MAX, + expr.span, + "this `min`/`max` combination leads to constant result", + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index f3f9bf11a61c..32c8731c5374 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats, - last_path_segment, SpanlessEq, + fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, + SpanlessEq, }; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || expr.span.desugaring_kind().is_some() - || any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + || in_automatically_derived(cx.tcx, expr.hir_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index fedcfd11fdcc..4cba13a05c24 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -364,8 +364,8 @@ declare_lint_pass!(MiscEarlyLints => [ ]); impl EarlyLintPass for MiscEarlyLints { - fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { - for param in &gen.params { + fn check_generics(&mut self, cx: &EarlyContext<'_>, generics: &Generics) { + for param in &generics.params { builtin_type_shadow::check(cx, param); } } diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index dd98352da860..935ed48dacc5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test; use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { }; // This lint would be very noisy in tests, so just ignore if we're in test context - if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) { + if is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index bb0d714a31fd..ed5f46ddc8d2 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -8,9 +8,11 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_target::spec::abi::Abi; declare_clippy_lint! { /// ### What it does @@ -115,7 +117,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { .iter() .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); - if already_const(header) || has_const_generic_params { + if already_const(header) + || has_const_generic_params + || !could_be_const_with_abi(cx, &self.msrv, header.abi) + { return; } }, @@ -127,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } + if fn_inputs_has_impl_trait_ty(cx, def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); // Const fns are not allowed as methods in a trait. @@ -171,3 +180,25 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } + +fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool { + match abi { + Abi::Rust => true, + // `const extern "C"` was stablized after 1.62.0 + Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN), + // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled. + _ => cx.tcx.features().const_extern_fn, + } +} + +/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of +/// its parameter types. +fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(); + inputs.iter().any(|input| { + matches!( + input.kind(), + ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() + ) + }) +} diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs similarity index 92% rename from src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs rename to src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs index 4af3ee74d0ea..ab1b4aa3dee6 100644 --- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs @@ -39,23 +39,23 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.77.0"] - pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + pub MISSING_CONST_FOR_THREAD_LOCAL, perf, "suggest using `const` in `thread_local!` macro" } -pub struct ThreadLocalInitializerCanBeMadeConst { +pub struct MissingConstForThreadLocal { msrv: Msrv, } -impl ThreadLocalInitializerCanBeMadeConst { +impl MissingConstForThreadLocal { #[must_use] pub fn new(msrv: Msrv) -> Self { Self { msrv } } } -impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]); +impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]); #[inline] fn is_thread_local_initializer( @@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id false } -impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { +impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { local_defid: rustc_span::def_id::LocalDefId, ) { let defid = local_defid.to_def_id(); - if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST) + if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT) && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) // Some implementations of `thread_local!` include an initializer fn. // In the case of a const initializer, the init fn is also const, @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { { span_lint_and_sugg( cx, - THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + MISSING_CONST_FOR_THREAD_LOCAL, unpeeled.span, "initializer for `thread_local` value can be made `const`", "replace with", diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 57ba0da53319..5ffd41d78e0c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Check if a `&mut` function argument is actually used mutably. /// /// Be careful if the function is publicly reexported as it would break compatibility with - /// users of this function. + /// users of this function, when the users pass this function as an argument. /// /// ### Why is this bad? /// Less `mut` means less fights with the borrow checker. It can also lead to more @@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { return; } + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { @@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { .iter() .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id)) { - let show_semver_warning = - self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id); - let mut is_cfged = None; for input in unused { // If the argument is never used mutably, we emit the warning. @@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),), Applicability::Unspecified, ); - if show_semver_warning { + if cx.effective_visibilities.is_exported(*fn_def_id) { diag.warn("changing this function will impact semver compatibility"); } if *is_cfged { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 87f886b1128d..0ecfa7baa72d 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; -use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks}; +use clippy_utils::{ + in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ @@ -185,7 +187,7 @@ impl NoEffect { && has_no_effect(cx, init) && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && ident.name.to_ident_string().starts_with('_') - && !any_parent_is_automatically_derived(cx.tcx, local.hir_id) + && !in_automatically_derived(cx.tcx, local.hir_id) { if let Some(l) = self.local_bindings.last_mut() { l.push(hir_id); @@ -258,13 +260,16 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind + && !in_external_macro(cx.sess(), stmt.span) && let ctxt = stmt.span.ctxt() && expr.span.ctxt() == ctxt && let Some(reduced) = reduce_expression(cx, expr) - && !in_external_macro(cx.sess(), stmt.span) && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { + if is_inside_always_const_context(cx.tcx, expr.hir_id) { + return; + } let snippet = if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { format!("assert!({}.len() > {});", &arr, &func) diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index faab79de9d3c..0e5b440c50f2 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>( Applicability::HasPlaceholders, // snippet ); } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); }); } } diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 48a442705b29..59834781a58a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -242,6 +242,13 @@ declare_clippy_lint! { /// # let x = 1; /// if (x | 1 > 3) { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x = 1; + /// if (x >= 2) { } + /// ``` #[clippy::version = "pre 1.29.0"] pub INEFFECTIVE_BIT_MASK, correctness, @@ -265,6 +272,13 @@ declare_clippy_lint! { /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x: i32 = 1; + /// if x.trailing_zeros() > 4 { } + /// ``` #[clippy::version = "pre 1.29.0"] pub VERBOSE_BIT_MASK, pedantic, @@ -560,74 +574,128 @@ declare_clippy_lint! { /// implement equality for a type involving floats). /// /// ### Why is this bad? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x = 1.2331f64; - /// let y = 1.2332f64; /// - /// if y == 1.23f64 { } - /// if y != x {} // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x = 1.2331f64; - /// # let y = 1.2332f64; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (y - 1.23f64).abs() < error_margin { } - /// if (y - x).abs() > error_margin { } + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP, pedantic, - "using `==` or `!=` on float values instead of comparing difference with an epsilon" + "using `==` or `!=` on float values instead of comparing difference with an allowed error" } declare_clippy_lint! { /// ### What it does - /// Checks for (in-)equality comparisons on floating-point - /// value and constant, except in functions called `*eq*` (which probably + /// Checks for (in-)equality comparisons on constant floating-point + /// values (apart from zero), except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// /// ### Why restrict this? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x: f64 = 1.0; - /// const ONE: f64 = 1.00; /// - /// if x == ONE { } // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == Y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x: f64 = 1.0; - /// # const ONE: f64 = 1.00; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (x - ONE).abs() < error_margin { } + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP_CONST, restriction, - "using `==` or `!=` on float constants instead of comparing difference with an epsilon" + "using `==` or `!=` on float constants instead of comparing difference with an allowed error" } declare_clippy_lint! { /// ### What it does - /// Checks for getting the remainder of a division by one or minus + /// Checks for getting the remainder of integer division by one or minus /// one. /// /// ### Why is this bad? @@ -646,7 +714,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub MODULO_ONE, correctness, - "taking a number modulo +/-1, which can either panic/overflow or always returns 0" + "taking an integer modulo +/-1, which can either panic/overflow or always returns 0" } declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs deleted file mode 100644 index de7898793310..000000000000 --- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::SpanlessEq; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Detects classic underflow/overflow checks. - /// - /// ### Why is this bad? - /// Most classic C underflow/overflow checks will fail in - /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. - /// - /// ### Example - /// ```no_run - /// # let a = 1; - /// # let b = 2; - /// a + b < a; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub OVERFLOW_CHECK_CONDITIONAL, - complexity, - "overflow checks inspired by C which are likely to panic" -} - -declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); - -const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; -const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; - -impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { - // a + b < a, a > a + b, a < a - b, a - b > a - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r); - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() - { - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } - } - - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() - { - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs new file mode 100644 index 000000000000..7f100a746d5e --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::eq_expr_value; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Detects C-style underflow/overflow checks. + /// + /// ### Why is this bad? + /// These checks will, by default, panic in debug builds rather than check + /// whether the operation caused an overflow. + /// + /// ### Example + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a + b < a { + /// // handle overflow + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.checked_add(b).is_none() { + /// // handle overflow + /// } + /// ``` + /// + /// Or: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.overflowing_add(b).1 { + /// // handle overflow + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub PANICKING_OVERFLOW_CHECKS, + correctness, + "overflow checks which will panic in debug mode" +} + +declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]); + +impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks { + // a + b < a, a > a + b, a < a - b, a - b > a + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Binary(op, lhs, rhs) = expr.kind + && let (lt, gt) = match op.node { + BinOpKind::Lt => (lhs, rhs), + BinOpKind::Gt => (rhs, lhs), + _ => return, + } + && let ctxt = expr.span.ctxt() + && let (op_lhs, op_rhs, other, commutative) = match (<.kind, >.kind) { + (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => { + (lhs, rhs, gt, true) + }, + (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => { + (lhs, rhs, lt, false) + }, + _ => return, + } + && let typeck = cx.typeck_results() + && let ty = typeck.expr_ty(op_lhs) + && matches!(ty.kind(), ty::Uint(_)) + && ty == typeck.expr_ty(op_rhs) + && ty == typeck.expr_ty(other) + && !in_external_macro(cx.tcx.sess, expr.span) + && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other))) + { + span_lint( + cx, + PANICKING_OVERFLOW_CHECKS, + expr.span, + "you are trying to use classic C overflow conditions that will fail in Rust", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 85979903b587..8e999f3e89af 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -26,12 +26,14 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"), ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"), ("clippy::option_unwrap_used", "clippy::unwrap_used"), + ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), ("clippy::ref_in_deref", "clippy::needless_borrow"), ("clippy::result_expect_used", "clippy::expect_used"), ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"), ("clippy::result_unwrap_used", "clippy::unwrap_used"), ("clippy::single_char_push_str", "clippy::single_char_add_str"), ("clippy::stutter", "clippy::module_name_repetitions"), + ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), ("clippy::zero_width_space", "clippy::invisible_characters"), diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index c11da3147ef4..8ced47b48a43 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -7,6 +7,7 @@ use clippy_utils::{ path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; +use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; @@ -14,13 +15,13 @@ use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, }; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{sym, BytePos, Pos, Span}; use std::borrow::Cow; use std::fmt::Display; @@ -80,6 +81,9 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_RETURN, + // This lint requires some special handling in `check_final_expr` for `#[expect]`. + // This handling needs to be updated if the group gets changed. This should also + // be caught by tests. style, "using a return statement like `return expr;` where an expression would suffice" } @@ -91,6 +95,9 @@ declare_clippy_lint! { /// ### Why is this bad? /// The `return` is unnecessary. /// + /// Returns may be used to add attributes to the return expression. Return + /// statements with attributes are therefore be accepted by this lint. + /// /// ### Example /// ```rust,ignore /// fn foo(x: usize) -> Result<(), Box> { @@ -377,13 +384,39 @@ fn check_final_expr<'tcx>( } }; - if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { - return; - } let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); if borrows { return; } + if ret_span.from_expansion() { + return; + } + + // Returns may be used to turn an expression into a statement in rustc's AST. + // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) + // `#[expect(clippy::needless_return)]` needs to be handled separatly to + // actually fullfil the expectation (clippy::#12998) + match cx.tcx.hir().attrs(expr.hir_id) { + [] => {}, + [attr] => { + if matches!(Level::from_attr(attr), Some(Level::Expect(_))) + && let metas = attr.meta_item_list() + && let Some(lst) = metas + && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice() + && let [tool, lint_name] = meta_item.path.segments.as_slice() + && tool.ident.name == sym::clippy + && matches!( + lint_name.ident.name.as_str(), + "needless_return" | "style" | "all" | "warnings" + ) + { + // This is an expectation of the `needless_return` lint + } else { + return; + } + }, + _ => return, + } emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); }, @@ -415,10 +448,6 @@ fn emit_return_lint( replacement: &RetReplacement<'_>, at: HirId, ) { - if ret_span.from_expansion() { - return; - } - span_lint_hir_and_then( cx, NEEDLESS_RETURN, diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 8fdd19c549f5..508f3ae6def0 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { /// ### What it does /// It lints if a struct has two methods with the same name: - /// one from a trait, another not from trait. + /// one from a trait, another not from a trait. /// /// ### Why restrict this? /// Confusing. diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs new file mode 100644 index 000000000000..5e65b9fa5171 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs @@ -0,0 +1,125 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Symbol; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `contains` to see if a value is not + /// present on `HashSet` followed by a `insert`. + /// + /// ### Why is this bad? + /// Using just `insert` and checking the returned `bool` is more efficient. + /// + /// ### Known problems + /// In case the value that wants to be inserted is borrowed and also expensive or impossible + /// to clone. In such a scenario, the developer might want to check with `contains` before inserting, + /// to avoid the clone. In this case, it will report a false positive. + /// + /// ### Example + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if !set.contains(&value) { + /// set.insert(value); + /// println!("inserted {value:?}"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if set.insert(&value) { + /// println!("inserted {value:?}"); + /// } + /// ``` + #[clippy::version = "1.80.0"] + pub SET_CONTAINS_OR_INSERT, + nursery, + "call to `HashSet::contains` followed by `HashSet::insert`" +} + +declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]); + +impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let Some(higher::If { + cond: cond_expr, + then: then_expr, + .. + }) = higher::If::hir(expr) + && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr) + && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr) + { + span_lint( + cx, + SET_CONTAINS_OR_INSERT, + vec![contains_expr.span, insert_expr.span], + "usage of `HashSet::insert` after `HashSet::contains`", + ); + } + } +} + +struct OpExpr<'tcx> { + receiver: &'tcx Expr<'tcx>, + value: &'tcx Expr<'tcx>, + span: Span, +} + +fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option> { + let expr = peel_hir_expr_while(expr, |e| { + if let ExprKind::Unary(UnOp::Not, e) = e.kind { + Some(e) + } else { + None + } + }); + + if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind { + let value = value.peel_borrows(); + let value = peel_hir_expr_while(value, |e| { + if let ExprKind::Unary(UnOp::Deref, e) = e.kind { + Some(e) + } else { + None + } + }); + let receiver = receiver.peel_borrows(); + let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); + if value.span.eq_ctxt(expr.span) + && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) + && path.ident.name == symbol + { + return Some(OpExpr { receiver, value, span }); + } + } + None +} + +fn find_insert_calls<'tcx>( + cx: &LateContext<'tcx>, + contains_expr: &OpExpr<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option> { + for_each_expr(cx, expr, |e| { + if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert)) + && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) + && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) + { + ControlFlow::Break(insert_expr) + } else { + ControlFlow::Continue(()) + } + }) +} diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index c05cd9ed5934..07390d6f4302 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -102,9 +102,9 @@ impl TraitBounds { impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { - fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { - self.check_type_repetition(cx, gen); - check_trait_bound_duplication(cx, gen); + fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { + self.check_type_repetition(cx, generics); + check_trait_bound_duplication(cx, generics); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { @@ -238,7 +238,7 @@ impl TraitBounds { } #[allow(clippy::mutable_key_type)] - fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { + fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, cx: &'cx LateContext<'tcx>, @@ -258,12 +258,12 @@ impl TraitBounds { } impl Eq for SpanlessTy<'_, '_> {} - if gen.span.from_expansion() { + if generics.span.from_expansion() { return; } let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; - for bound in gen.predicates { + for bound in generics.predicates { if let WherePredicate::BoundPredicate(ref p) = bound && p.origin != PredicateOrigin::ImplTrait && p.bounds.len() as u64 <= self.max_trait_bounds @@ -301,8 +301,8 @@ impl TraitBounds { } } -fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() { +fn check_trait_bound_duplication(cx: &LateContext<'_>, generics: &'_ Generics<'_>) { + if generics.span.from_expansion() { return; } @@ -313,7 +313,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // collects each of these where clauses into a set keyed by generic name and comparable trait // eg. (T, Clone) - let where_predicates = gen + let where_predicates = generics .predicates .iter() .filter_map(|pred| { @@ -342,7 +342,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // compare trait bounds keyed by generic name and comparable trait to collected where // predicates eg. (T, Clone) - for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) { + for predicate in generics.predicates.iter().filter(|pred| !pred.in_where_clause()) { if let WherePredicate::BoundPredicate(bound_predicate) = predicate && bound_predicate.origin != PredicateOrigin::ImplTrait && !bound_predicate.span.from_expansion() diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index 0aa50c99c169..b6e765d7c393 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { bound .bound_generic_params .iter() - .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) + .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) }); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index 877a77fd6d24..1d294c2944b2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,5 @@ pub mod almost_standard_lint_formulation; pub mod collapsible_calls; -pub mod compiler_lint_functions; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs deleted file mode 100644 index 9b6b68718186..000000000000 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ /dev/null @@ -1,73 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::match_type; -use clippy_utils::{is_lint_allowed, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*` - /// variant of the function. - /// - /// ### Why is this bad? - /// The `utils::*` variants also add a link to the Clippy documentation to the - /// warning/error messages. - /// - /// ### Example - /// ```rust,ignore - /// cx.span_lint(LINT_NAME, "message"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// utils::span_lint(cx, LINT_NAME, "message"); - /// ``` - pub COMPILER_LINT_FUNCTIONS, - internal, - "usage of the lint functions of the compiler instead of the utils::* variant" -} - -impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]); - -#[derive(Clone, Default)] -pub struct CompilerLintFunctions { - map: FxHashMap<&'static str, &'static str>, -} - -impl CompilerLintFunctions { - #[must_use] - pub fn new() -> Self { - let mut map = FxHashMap::default(); - map.insert("span_lint", "utils::span_lint"); - map.insert("lint", "utils::span_lint"); - map.insert("span_lint_note", "utils::span_lint_and_note"); - map.insert("span_lint_help", "utils::span_lint_and_help"); - Self { map } - } -} - -impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) { - return; - } - - if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind - && let fn_name = path.ident - && let Some(sugg) = self.map.get(fn_name.as_str()) - && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() - && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT)) - { - span_lint_and_help( - cx, - COMPILER_LINT_FUNCTIONS, - path.ident.span, - "usage of a compiler lint function", - None, - format!("please use the Clippy variant of this function: `{sugg}`"), - ); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 436f0cb79fb2..a0a60ca88758 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use clippy_utils::source::{snippet, snippet_with_applicability}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -100,7 +100,6 @@ declare_clippy_lint! { #[derive(Default)] pub struct WildcardImports { warn_on_all: bool, - test_modules_deep: u32, allowed_segments: FxHashSet, } @@ -108,7 +107,6 @@ impl WildcardImports { pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet) -> Self { Self { warn_on_all, - test_modules_deep: 0, allowed_segments: allowed_wildcard_imports, } } @@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports { return; } - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id); if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) { return; } if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind - && (self.warn_on_all || !self.check_exceptions(item, use_path.segments)) + && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments)) && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id) && !used_imports.is_empty() // Already handled by `unused_imports` && !used_imports.contains(&kw::Underscore) @@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports { span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability); } } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); - } - } } impl WildcardImports { - fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { + fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { item.span.from_expansion() || is_prelude_import(segments) - || (is_super_only_import(segments) && self.test_modules_deep > 0) || is_allowed_via_config(segments, &self.allowed_segments) + || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) } } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 652ce88bd951..96e53b7ef0ba 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .as_ref() .map_or(false, |crate_name| crate_name == "build_script_build"); - let allowed_in_tests = self.allow_print_in_tests - && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)); + let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 935a25d79319..bdb3b5e45c48 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -102,10 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, - ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, - ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, - PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -210,7 +211,10 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool { false } -/// Returns `true` if the given `NodeId` is inside a constant context +/// Returns `true` if the given `HirId` is inside a constant context. +/// +/// This is the same as `is_inside_always_const_context`, but also includes +/// `const fn`. /// /// # Example /// @@ -223,6 +227,24 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx.hir().is_inside_const_context(id) } +/// Returns `true` if the given `HirId` is inside an always constant context. +/// +/// This context includes: +/// * const/static items +/// * const blocks (or inline consts) +/// * associated constants +pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + use ConstContext::{Const, ConstFn, Static}; + let hir = tcx.hir(); + let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else { + return false; + }; + match ctx { + ConstFn => false, + Static(_) | Const { inline: _ } => true, + } +} + /// Checks if a `Res` refers to a constructor of a `LangItem` /// For example, use this to check whether a function call or a pattern is `Some(..)`. pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool { @@ -1904,8 +1926,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool false } -pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { - any_parent_has_attr(tcx, node, sym::automatically_derived) +/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived` +/// attribute. +pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.hir() + .parent_owner_iter(id) + .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_)))) + .any(|(id, _)| { + has_attr( + tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)), + sym::automatically_derived, + ) + }) } /// Matches a function call with the given path and returns the arguments. @@ -2472,6 +2504,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) } } +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { + let mut count = 0; + while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() { + ty = *dest_ty; + count += 1; + } + (ty, count) +} + /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { @@ -2594,16 +2637,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { .any(|attr| attr.has_name(sym::cfg)) } -/// Checks whether item either has `test` attribute applied, or -/// is a module with `test` in its name. -/// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function -pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { - is_in_test_function(tcx, item.hir_id()) - || matches!(item.kind, ItemKind::Mod(..)) - && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") -} - /// Walks up the HIR tree from the given expression in an attempt to find where the value is /// consumed. /// diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 3f66813801dc..d5a3d8b9e5a2 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern" pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; +pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index acaeb93f44a6..fc02b974ee12 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -96,11 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for (predicate, _span) in cx - .tcx - .explicit_item_super_predicates(def_id) - .iter_identity_copied() - { + for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. @@ -1332,19 +1328,13 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { - cx.tcx - .inherent_impls(ty_did) - .into_iter() - .flatten() - .map(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .filter(|item| item.kind == AssocKind::Fn) - }) - .next() - .flatten() + cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .filter(|item| item.kind == AssocKind::Fn) + }) } else { None } diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml index ae9e77b8eed0..3c86dfe324f4 100644 --- a/src/tools/clippy/lintcheck/Cargo.toml +++ b/src/tools/clippy/lintcheck/Cargo.toml @@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive", "env"] } crossbeam-channel = "0.5.6" diff = "0.1.13" flate2 = "1.0" +itertools = "0.12" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.85" diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md index 2d6039caeef0..47a96e0a03c9 100644 --- a/src/tools/clippy/lintcheck/README.md +++ b/src/tools/clippy/lintcheck/README.md @@ -7,13 +7,13 @@ repo. We can then check the diff and spot new or disappearing warnings. From the repo root, run: ``` -cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml +cargo lintcheck ``` or ``` -cargo lintcheck +cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml ``` By default, the logs will be saved into @@ -33,6 +33,8 @@ the 200 recently most downloaded crates: cargo lintcheck popular -n 200 custom.toml ``` +> Note: Lintcheck isn't sandboxed. Only use it to check crates that you trust or +> sandbox it manually. ### Configuring the Crate Sources @@ -65,17 +67,11 @@ sources. #### Command Line Options (optional) ```toml -bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']} +clap = {name = "clap", versions = ['4.5.8'], options = ['-Fderive']} ``` It is possible to specify command line options for each crate. This makes it -possible to only check a crate for certain lint groups. If no options are -specified, the lint groups `clippy::all`, `clippy::pedantic`, and -`clippy::cargo` are checked. If an empty array is specified only `clippy::all` -is checked. - -**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all` -is explicitly specified in the options. +possible to enable or disable features. ### Fix mode You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and diff --git a/src/tools/clippy/lintcheck/lintcheck_crates.toml b/src/tools/clippy/lintcheck/lintcheck_crates.toml index 52f7fee47b61..ff608e6f9359 100644 --- a/src/tools/clippy/lintcheck/lintcheck_crates.toml +++ b/src/tools/clippy/lintcheck/lintcheck_crates.toml @@ -1,38 +1,38 @@ [crates] # some of these are from cargotest -cargo = {name = "cargo", versions = ['0.64.0']} -iron = {name = "iron", versions = ['0.6.1']} -ripgrep = {name = "ripgrep", versions = ['12.1.1']} -xsv = {name = "xsv", versions = ['0.13.0']} +cargo = {name = "cargo", version = '0.64.0'} +iron = {name = "iron", version = '0.6.1'} +ripgrep = {name = "ripgrep", version = '12.1.1'} +xsv = {name = "xsv", version = '0.13.0'} # commented out because of 173K clippy::match_same_arms msgs in language_type.rs -#tokei = { name = "tokei", versions = ['12.0.4']} -rayon = {name = "rayon", versions = ['1.5.0']} -serde = {name = "serde", versions = ['1.0.118']} +#tokei = { name = "tokei", version = '12.0.4'} +rayon = {name = "rayon", version = '1.5.0'} +serde = {name = "serde", version = '1.0.118'} # top 10 crates.io dls -bitflags = {name = "bitflags", versions = ['1.2.1']} +bitflags = {name = "bitflags", version = '1.2.1'} # crash = {name = "clippy_crash", path = "/tmp/clippy_crash"} -libc = {name = "libc", versions = ['0.2.81']} -log = {name = "log", versions = ['0.4.11']} -proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} -quote = {name = "quote", versions = ['1.0.7']} -rand = {name = "rand", versions = ['0.7.3']} -rand_core = {name = "rand_core", versions = ['0.6.0']} -regex = {name = "regex", versions = ['1.3.2']} -syn = {name = "syn", versions = ['1.0.54']} -unicode-xid = {name = "unicode-xid", versions = ['0.2.1']} +libc = {name = "libc", version = '0.2.81'} +log = {name = "log", version = '0.4.11'} +proc-macro2 = {name = "proc-macro2", version = '1.0.24'} +quote = {name = "quote", version = '1.0.7'} +rand = {name = "rand", version = '0.7.3'} +rand_core = {name = "rand_core", version = '0.6.0'} +regex = {name = "regex", version = '1.3.2'} +syn = {name = "syn", version = '1.0.54'} +unicode-xid = {name = "unicode-xid", version = '0.2.1'} # some more of dtolnays crates -anyhow = {name = "anyhow", versions = ['1.0.38']} -async-trait = {name = "async-trait", versions = ['0.1.42']} -cxx = {name = "cxx", versions = ['1.0.32']} -ryu = {name = "ryu", versions = ['1.0.5']} -serde_yaml = {name = "serde_yaml", versions = ['0.8.17']} -thiserror = {name = "thiserror", versions = ['1.0.24']} +anyhow = {name = "anyhow", version = '1.0.38'} +async-trait = {name = "async-trait", version = '0.1.42'} +cxx = {name = "cxx", version = '1.0.32'} +ryu = {name = "ryu", version = '1.0.5'} +serde_yaml = {name = "serde_yaml", version = '0.8.17'} +thiserror = {name = "thiserror", version = '1.0.24'} # some embark crates, there are other interesting crates but # unfortunately adding them increases lintcheck runtime drastically -cfg-expr = {name = "cfg-expr", versions = ['0.7.1']} +cfg-expr = {name = "cfg-expr", version = '0.7.1'} puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} -rpmalloc = {name = "rpmalloc", versions = ['0.2.0']} -tame-oidc = {name = "tame-oidc", versions = ['0.1.0']} +rpmalloc = {name = "rpmalloc", version = '0.2.0'} +tame-oidc = {name = "tame-oidc", version = '0.1.0'} [recursive] ignore = [ diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs index e6cd7c9fdc2b..b35a62eed440 100644 --- a/src/tools/clippy/lintcheck/src/config.rs +++ b/src/tools/clippy/lintcheck/src/config.rs @@ -36,6 +36,10 @@ pub(crate) struct LintcheckConfig { /// Apply a filter to only collect specified lints, this also overrides `allow` attributes #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)] pub lint_filter: Vec, + /// Set all lints to the "warn" lint level, even resitriction ones. Usually, + /// it's better to use `--filter` instead + #[clap(long, conflicts_with("lint_filter"))] + pub warn_all: bool, /// Set the output format of the log file #[clap(long, short, default_value = "text")] pub format: OutputFormat, diff --git a/src/tools/clippy/lintcheck/src/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs index 47724a2fedb0..041be5081f28 100644 --- a/src/tools/clippy/lintcheck/src/driver.rs +++ b/src/tools/clippy/lintcheck/src/driver.rs @@ -11,8 +11,6 @@ use std::{env, mem}; fn run_clippy(addr: &str) -> Option { let driver_info = DriverInfo { package_name: env::var("CARGO_PKG_NAME").ok()?, - crate_name: env::var("CARGO_CRATE_NAME").ok()?, - version: env::var("CARGO_PKG_VERSION").ok()?, }; let mut stream = BufReader::new(TcpStream::connect(addr).unwrap()); diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs new file mode 100644 index 000000000000..3d034391c280 --- /dev/null +++ b/src/tools/clippy/lintcheck/src/input.rs @@ -0,0 +1,288 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::{self}; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::Duration; + +use serde::Deserialize; +use walkdir::{DirEntry, WalkDir}; + +use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES}; + +/// List of sources to check, loaded from a .toml file +#[derive(Debug, Deserialize)] +pub struct SourceList { + crates: HashMap, + #[serde(default)] + recursive: RecursiveOptions, +} + +#[derive(Debug, Deserialize, Default)] +pub struct RecursiveOptions { + pub ignore: HashSet, +} + +/// A crate source stored inside the .toml +/// will be translated into on one of the `CrateSource` variants +#[derive(Debug, Deserialize)] +struct TomlCrate { + name: String, + version: Option, + git_url: Option, + git_hash: Option, + path: Option, + options: Option>, +} + +/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder +/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub enum CrateSource { + CratesIo { + name: String, + version: String, + options: Option>, + }, + Git { + name: String, + url: String, + commit: String, + options: Option>, + }, + Path { + name: String, + path: PathBuf, + options: Option>, + }, +} + +/// Read a `lintcheck_crates.toml` file +pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { + let toml_content: String = + fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); + let crate_list: SourceList = + toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); + // parse the hashmap of the toml file into a list of crates + let tomlcrates: Vec = crate_list.crates.into_values().collect(); + + // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => + // multiple Cratesources) + let mut crate_sources = Vec::new(); + for tk in tomlcrates { + if let Some(ref path) = tk.path { + crate_sources.push(CrateSource::Path { + name: tk.name.clone(), + path: PathBuf::from(path), + options: tk.options.clone(), + }); + } else if let Some(ref version) = tk.version { + crate_sources.push(CrateSource::CratesIo { + name: tk.name.clone(), + version: version.to_string(), + options: tk.options.clone(), + }); + } else if tk.git_url.is_some() && tk.git_hash.is_some() { + // otherwise, we should have a git source + crate_sources.push(CrateSource::Git { + name: tk.name.clone(), + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), + options: tk.options.clone(), + }); + } else { + panic!("Invalid crate source: {tk:?}"); + } + + // if we have a version as well as a git data OR only one git data, something is funky + if tk.version.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) + || tk.git_hash.is_some() != tk.git_url.is_some() + { + eprintln!("tomlkrate: {tk:?}"); + assert_eq!( + tk.git_hash.is_some(), + tk.git_url.is_some(), + "Error: Encountered TomlCrate with only one of git_hash and git_url!" + ); + assert!( + tk.path.is_none() || (tk.git_hash.is_none() && tk.version.is_none()), + "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" + ); + unreachable!("Failed to translate TomlCrate into CrateSource!"); + } + } + // sort the crates + crate_sources.sort(); + + (crate_sources, crate_list.recursive) +} + +impl CrateSource { + /// Makes the sources available on the disk for clippy to check. + /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or + /// copies a local folder + #[expect(clippy::too_many_lines)] + pub fn download_and_extract(&self) -> Crate { + #[allow(clippy::result_large_err)] + fn get(path: &str) -> Result { + const MAX_RETRIES: u8 = 4; + let mut retries = 0; + loop { + match ureq::get(path).call() { + Ok(res) => return Ok(res), + Err(e) if retries >= MAX_RETRIES => return Err(e), + Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), + Err(e) => return Err(e), + } + eprintln!("retrying in {retries} seconds..."); + std::thread::sleep(Duration::from_secs(u64::from(retries))); + retries += 1; + } + } + match self { + CrateSource::CratesIo { name, version, options } => { + let extract_dir = PathBuf::from(LINTCHECK_SOURCES); + let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); + + // url to download the crate from crates.io + let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); + println!("Downloading and extracting {name} {version} from {url}"); + create_dirs(&krate_download_dir, &extract_dir); + + let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); + // don't download/extract if we already have done so + if !krate_file_path.is_file() { + // create a file path to download and write the crate data into + let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); + let mut krate_req = get(&url).unwrap().into_reader(); + // copy the crate into the file + io::copy(&mut krate_req, &mut krate_dest).unwrap(); + + // unzip the tarball + let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); + // extract the tar archive + let mut archive = tar::Archive::new(ungz_tar); + archive.unpack(&extract_dir).expect("Failed to extract!"); + } + // crate is extracted, return a new Krate object which contains the path to the extracted + // sources that clippy can check + Crate { + version: version.clone(), + name: name.clone(), + path: extract_dir.join(format!("{name}-{version}/")), + options: options.clone(), + } + }, + CrateSource::Git { + name, + url, + commit, + options, + } => { + let repo_path = { + let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); + // add a -git suffix in case we have the same crate from crates.io and a git repo + repo_path.push(format!("{name}-git")); + repo_path + }; + // clone the repo if we have not done so + if !repo_path.is_dir() { + println!("Cloning {url} and checking out {commit}"); + if !Command::new("git") + .arg("clone") + .arg(url) + .arg(&repo_path) + .status() + .expect("Failed to clone git repo!") + .success() + { + eprintln!("Failed to clone {url} into {}", repo_path.display()); + } + } + // check out the commit/branch/whatever + if !Command::new("git") + .args(["-c", "advice.detachedHead=false"]) + .arg("checkout") + .arg(commit) + .current_dir(&repo_path) + .status() + .expect("Failed to check out commit") + .success() + { + eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); + } + + Crate { + version: commit.clone(), + name: name.clone(), + path: repo_path, + options: options.clone(), + } + }, + CrateSource::Path { name, path, options } => { + fn is_cache_dir(entry: &DirEntry) -> bool { + fs::read(entry.path().join("CACHEDIR.TAG")) + .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) + .unwrap_or(false) + } + + // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. + // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory + // as a result of this filter. + let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); + if dest_crate_root.exists() { + println!("Deleting existing directory at {dest_crate_root:?}"); + fs::remove_dir_all(&dest_crate_root).unwrap(); + } + + println!("Copying {path:?} to {dest_crate_root:?}"); + + for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { + let entry = entry.unwrap(); + let entry_path = entry.path(); + let relative_entry_path = entry_path.strip_prefix(path).unwrap(); + let dest_path = dest_crate_root.join(relative_entry_path); + let metadata = entry_path.symlink_metadata().unwrap(); + + if metadata.is_dir() { + fs::create_dir(dest_path).unwrap(); + } else if metadata.is_file() { + fs::copy(entry_path, dest_path).unwrap(); + } + } + + Crate { + version: String::from("local"), + name: name.clone(), + path: dest_crate_root, + options: options.clone(), + } + }, + } + } +} + +/// Create necessary directories to run the lintcheck tool. +/// +/// # Panics +/// +/// This function panics if creating one of the dirs fails. +fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { + fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create lintcheck target dir" + ); + }); + fs::create_dir(krate_download_dir).unwrap_or_else(|err| { + assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); + }); + fs::create_dir(extract_dir).unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create crate extraction dir" + ); + }); +} diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs index 43d0413c7cee..1a652927988e 100644 --- a/src/tools/clippy/lintcheck/src/json.rs +++ b/src/tools/clippy/lintcheck/src/json.rs @@ -1,37 +1,50 @@ -use std::collections::HashMap; -use std::fmt::Write; use std::fs; -use std::hash::Hash; use std::path::Path; +use itertools::EitherOrBoth; +use serde::{Deserialize, Serialize}; + use crate::ClippyWarning; -/// Creates the log file output for [`crate::config::OutputFormat::Json`] -pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String { - serde_json::to_string(&clippy_warnings).unwrap() +#[derive(Deserialize, Serialize)] +struct LintJson { + lint: String, + file_name: String, + byte_pos: (u32, u32), + rendered: String, } -fn load_warnings(path: &Path) -> Vec { +impl LintJson { + fn key(&self) -> impl Ord + '_ { + (self.file_name.as_str(), self.byte_pos, self.lint.as_str()) + } +} + +/// Creates the log file output for [`crate::config::OutputFormat::Json`] +pub(crate) fn output(clippy_warnings: Vec) -> String { + let mut lints: Vec = clippy_warnings + .into_iter() + .map(|warning| { + let span = warning.span(); + LintJson { + file_name: span.file_name.clone(), + byte_pos: (span.byte_start, span.byte_end), + lint: warning.lint, + rendered: warning.diag.rendered.unwrap(), + } + }) + .collect(); + lints.sort_by(|a, b| a.key().cmp(&b.key())); + serde_json::to_string(&lints).unwrap() +} + +fn load_warnings(path: &Path) -> Vec { let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display())); serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display())) } -/// Group warnings by their primary span location + lint name -fn create_map(warnings: &[ClippyWarning]) -> HashMap> { - let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len()); - - for warning in warnings { - let span = warning.span(); - let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end); - - map.entry(key).or_default().push(warning); - } - - map -} - -fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { +fn print_warnings(title: &str, warnings: &[LintJson]) { if warnings.is_empty() { return; } @@ -39,31 +52,20 @@ fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { println!("### {title}"); println!("```"); for warning in warnings { - print!("{}", warning.diag); + print!("{}", warning.rendered); } println!("```"); } -fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) { - fn render(warnings: &[&ClippyWarning]) -> String { - let mut rendered = String::new(); - for warning in warnings { - write!(&mut rendered, "{}", warning.diag).unwrap(); - } - rendered - } - +fn print_changed_diff(changed: &[(LintJson, LintJson)]) { if changed.is_empty() { return; } println!("### Changed"); println!("```diff"); - for &(old, new) in changed { - let old_rendered = render(old); - let new_rendered = render(new); - - for change in diff::lines(&old_rendered, &new_rendered) { + for (old, new) in changed { + for change in diff::lines(&old.rendered, &new.rendered) { use diff::Result::{Both, Left, Right}; match change { @@ -86,26 +88,19 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) { let old_warnings = load_warnings(old_path); let new_warnings = load_warnings(new_path); - let old_map = create_map(&old_warnings); - let new_map = create_map(&new_warnings); - let mut added = Vec::new(); let mut removed = Vec::new(); let mut changed = Vec::new(); - for (key, new) in &new_map { - if let Some(old) = old_map.get(key) { - if old != new { - changed.push((old.as_slice(), new.as_slice())); - } - } else { - added.extend(new); - } - } - - for (key, old) in &old_map { - if !new_map.contains_key(key) { - removed.extend(old); + for change in itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) { + match change { + EitherOrBoth::Both(old, new) => { + if old.rendered != new.rendered { + changed.push((old, new)); + } + }, + EitherOrBoth::Left(old) => removed.push(old), + EitherOrBoth::Right(new) => added.push(new), } } diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index ec72e0eb5dcb..e37ffab13ac8 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -5,6 +5,7 @@ // When a new lint is introduced, we can search the results for new warnings and check for false // positives. +#![feature(iter_collect_into)] #![warn( trivial_casts, trivial_numeric_casts, @@ -12,84 +13,38 @@ unused_lifetimes, unused_qualifications )] -#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)] +#![allow( + clippy::collapsible_else_if, + clippy::needless_borrows_for_generic_args, + clippy::module_name_repetitions +)] mod config; mod driver; +mod input; mod json; +mod output; mod popular_crates; mod recursive; use crate::config::{Commands, LintcheckConfig, OutputFormat}; use crate::recursive::LintcheckServer; -use std::collections::{HashMap, HashSet}; use std::env::consts::EXE_SUFFIX; -use std::fmt::{self, Display, Write as _}; -use std::hash::Hash; -use std::io::{self, ErrorKind}; +use std::io::{self}; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus, Stdio}; +use std::process::{Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::time::Duration; -use std::{env, fs, thread}; +use std::{env, fs}; -use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; +use input::{read_crates, CrateSource}; +use output::{ClippyCheckOutput, ClippyWarning, RustcIce}; use rayon::prelude::*; -use serde::{Deserialize, Serialize}; -use walkdir::{DirEntry, WalkDir}; const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; -/// List of sources to check, loaded from a .toml file -#[derive(Debug, Deserialize)] -struct SourceList { - crates: HashMap, - #[serde(default)] - recursive: RecursiveOptions, -} - -#[derive(Debug, Deserialize, Default)] -struct RecursiveOptions { - ignore: HashSet, -} - -/// A crate source stored inside the .toml -/// will be translated into on one of the `CrateSource` variants -#[derive(Debug, Deserialize)] -struct TomlCrate { - name: String, - versions: Option>, - git_url: Option, - git_hash: Option, - path: Option, - options: Option>, -} - -/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder -/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` -#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] -enum CrateSource { - CratesIo { - name: String, - version: String, - options: Option>, - }, - Git { - name: String, - url: String, - commit: String, - options: Option>, - }, - Path { - name: String, - path: PathBuf, - options: Option>, - }, -} - /// Represents the actual source code of a crate that we ran "cargo clippy" on #[derive(Debug)] struct Crate { @@ -100,248 +55,6 @@ struct Crate { options: Option>, } -/// A single emitted output from clippy being executed on a crate. It may either be a -/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many -/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). -#[derive(Debug)] -enum ClippyCheckOutput { - ClippyWarning(ClippyWarning), - RustcIce(RustcIce), -} - -#[derive(Debug)] -struct RustcIce { - pub crate_name: String, - pub ice_content: String, -} - -impl Display for RustcIce { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}:\n{}\n========================================\n", - self.crate_name, self.ice_content - ) - } -} - -impl RustcIce { - pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { - if status.code().unwrap_or(0) == 101 - /* ice exit status */ - { - Some(Self { - crate_name: crate_name.to_owned(), - ice_content: stderr.to_owned(), - }) - } else { - None - } - } -} - -/// A single warning that clippy issued while checking a `Crate` -#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -struct ClippyWarning { - crate_name: String, - crate_version: String, - lint_type: String, - diag: Diagnostic, -} - -#[allow(unused)] -impl ClippyWarning { - fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { - let lint_type = diag.code.clone()?.code; - if !(lint_type.contains("clippy") || diag.message.contains("clippy")) - || diag.message.contains("could not read cargo metadata") - { - return None; - } - - // --recursive bypasses cargo so we have to strip the rendered output ourselves - let rendered = diag.rendered.as_mut().unwrap(); - *rendered = strip_ansi_escapes::strip_str(&rendered); - - Some(Self { - crate_name: crate_name.to_owned(), - crate_version: crate_version.to_owned(), - lint_type, - diag, - }) - } - - fn span(&self) -> &DiagnosticSpan { - self.diag.spans.iter().find(|span| span.is_primary).unwrap() - } - - fn to_output(&self, format: OutputFormat) -> String { - let span = self.span(); - let mut file = span.file_name.clone(); - let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); - match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message), - OutputFormat::Markdown => { - if file.starts_with("target") { - file.insert_str(0, "../"); - } - - let mut output = String::from("| "); - write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap(); - output.push('\n'); - output - }, - OutputFormat::Json => unreachable!("JSON output is handled via serde"), - } - } -} - -#[allow(clippy::result_large_err)] -fn get(path: &str) -> Result { - const MAX_RETRIES: u8 = 4; - let mut retries = 0; - loop { - match ureq::get(path).call() { - Ok(res) => return Ok(res), - Err(e) if retries >= MAX_RETRIES => return Err(e), - Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), - Err(e) => return Err(e), - } - eprintln!("retrying in {retries} seconds..."); - thread::sleep(Duration::from_secs(u64::from(retries))); - retries += 1; - } -} - -impl CrateSource { - /// Makes the sources available on the disk for clippy to check. - /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or - /// copies a local folder - fn download_and_extract(&self) -> Crate { - match self { - CrateSource::CratesIo { name, version, options } => { - let extract_dir = PathBuf::from(LINTCHECK_SOURCES); - let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); - - // url to download the crate from crates.io - let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); - println!("Downloading and extracting {name} {version} from {url}"); - create_dirs(&krate_download_dir, &extract_dir); - - let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); - // don't download/extract if we already have done so - if !krate_file_path.is_file() { - // create a file path to download and write the crate data into - let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); - let mut krate_req = get(&url).unwrap().into_reader(); - // copy the crate into the file - io::copy(&mut krate_req, &mut krate_dest).unwrap(); - - // unzip the tarball - let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); - // extract the tar archive - let mut archive = tar::Archive::new(ungz_tar); - archive.unpack(&extract_dir).expect("Failed to extract!"); - } - // crate is extracted, return a new Krate object which contains the path to the extracted - // sources that clippy can check - Crate { - version: version.clone(), - name: name.clone(), - path: extract_dir.join(format!("{name}-{version}/")), - options: options.clone(), - } - }, - CrateSource::Git { - name, - url, - commit, - options, - } => { - let repo_path = { - let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); - // add a -git suffix in case we have the same crate from crates.io and a git repo - repo_path.push(format!("{name}-git")); - repo_path - }; - // clone the repo if we have not done so - if !repo_path.is_dir() { - println!("Cloning {url} and checking out {commit}"); - if !Command::new("git") - .arg("clone") - .arg(url) - .arg(&repo_path) - .status() - .expect("Failed to clone git repo!") - .success() - { - eprintln!("Failed to clone {url} into {}", repo_path.display()); - } - } - // check out the commit/branch/whatever - if !Command::new("git") - .args(["-c", "advice.detachedHead=false"]) - .arg("checkout") - .arg(commit) - .current_dir(&repo_path) - .status() - .expect("Failed to check out commit") - .success() - { - eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); - } - - Crate { - version: commit.clone(), - name: name.clone(), - path: repo_path, - options: options.clone(), - } - }, - CrateSource::Path { name, path, options } => { - fn is_cache_dir(entry: &DirEntry) -> bool { - fs::read(entry.path().join("CACHEDIR.TAG")) - .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) - .unwrap_or(false) - } - - // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. - // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory - // as a result of this filter. - let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); - if dest_crate_root.exists() { - println!("Deleting existing directory at {dest_crate_root:?}"); - fs::remove_dir_all(&dest_crate_root).unwrap(); - } - - println!("Copying {path:?} to {dest_crate_root:?}"); - - for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { - let entry = entry.unwrap(); - let entry_path = entry.path(); - let relative_entry_path = entry_path.strip_prefix(path).unwrap(); - let dest_path = dest_crate_root.join(relative_entry_path); - let metadata = entry_path.symlink_metadata().unwrap(); - - if metadata.is_dir() { - fs::create_dir(dest_path).unwrap(); - } else if metadata.is_file() { - fs::copy(entry_path, dest_path).unwrap(); - } - } - - Crate { - version: String::from("local"), - name: name.clone(), - path: dest_crate_root, - options: options.clone(), - } - }, - } - } -} - impl Crate { /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy /// issued @@ -352,7 +65,7 @@ impl Crate { target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, - lint_filter: &[String], + lint_levels_args: &[String], server: &Option, ) -> Vec { // advance the atomic index by one @@ -398,16 +111,9 @@ impl Crate { for opt in options { clippy_args.push(opt); } - } else { - clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]); } - if lint_filter.is_empty() { - clippy_args.push("--cap-lints=warn"); - } else { - clippy_args.push("--cap-lints=allow"); - clippy_args.extend(lint_filter.iter().map(String::as_str)); - } + clippy_args.extend(lint_levels_args.iter().map(String::as_str)); let mut cmd = Command::new("cargo"); cmd.arg(if config.fix { "fix" } else { "check" }) @@ -479,7 +185,7 @@ impl Crate { // get all clippy warnings and ICEs let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { - Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), + Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message), _ => None, }) .map(ClippyCheckOutput::ClippyWarning) @@ -509,96 +215,6 @@ fn build_clippy() -> String { String::from_utf8_lossy(&output.stdout).into_owned() } -/// Read a `lintcheck_crates.toml` file -fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { - let toml_content: String = - fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); - let crate_list: SourceList = - toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); - // parse the hashmap of the toml file into a list of crates - let tomlcrates: Vec = crate_list.crates.into_values().collect(); - - // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => - // multiple Cratesources) - let mut crate_sources = Vec::new(); - for tk in tomlcrates { - if let Some(ref path) = tk.path { - crate_sources.push(CrateSource::Path { - name: tk.name.clone(), - path: PathBuf::from(path), - options: tk.options.clone(), - }); - } else if let Some(ref versions) = tk.versions { - // if we have multiple versions, save each one - for ver in versions { - crate_sources.push(CrateSource::CratesIo { - name: tk.name.clone(), - version: ver.to_string(), - options: tk.options.clone(), - }); - } - } else if tk.git_url.is_some() && tk.git_hash.is_some() { - // otherwise, we should have a git source - crate_sources.push(CrateSource::Git { - name: tk.name.clone(), - url: tk.git_url.clone().unwrap(), - commit: tk.git_hash.clone().unwrap(), - options: tk.options.clone(), - }); - } else { - panic!("Invalid crate source: {tk:?}"); - } - - // if we have a version as well as a git data OR only one git data, something is funky - if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) - || tk.git_hash.is_some() != tk.git_url.is_some() - { - eprintln!("tomlkrate: {tk:?}"); - assert_eq!( - tk.git_hash.is_some(), - tk.git_url.is_some(), - "Error: Encountered TomlCrate with only one of git_hash and git_url!" - ); - assert!( - tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()), - "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" - ); - unreachable!("Failed to translate TomlCrate into CrateSource!"); - } - } - // sort the crates - crate_sources.sort(); - - (crate_sources, crate_list.recursive) -} - -/// Generate a short list of occurring lints-types and their count -fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { - // count lint type occurrences - let mut counter: HashMap<&String, usize> = HashMap::new(); - warnings - .iter() - .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); - - // collect into a tupled list for sorting - let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); - // sort by "000{count} {clippy::lintname}" - // to not have a lint with 200 and 2 warnings take the same spot - stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); - - let mut header = String::from("| lint | count |\n"); - header.push_str("| -------------------------------------------------- | ----- |\n"); - let stats_string = stats - .iter() - .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) - .fold(header, |mut table, line| { - table.push_str(&line); - table - }); - - (stats_string, counter) -} - fn main() { // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` if let Ok(addr) = env::var("LINTCHECK_SERVER") { @@ -638,15 +254,39 @@ fn lintcheck(config: LintcheckConfig) { let (crates, recursive_options) = read_crates(&config.sources_toml_path); let counter = AtomicUsize::new(1); - let lint_filter: Vec = config - .lint_filter - .iter() - .map(|filter| { - let mut filter = filter.clone(); - filter.insert_str(0, "--force-warn="); - filter - }) - .collect(); + let mut lint_level_args: Vec = vec![]; + if config.lint_filter.is_empty() { + lint_level_args.push("--cap-lints=warn".to_string()); + + // Set allow-by-default to warn + if config.warn_all { + [ + "clippy::cargo", + "clippy::nursery", + "clippy::pedantic", + "clippy::restriction", + ] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } else { + ["clippy::cargo", "clippy::pedantic"] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } + } else { + lint_level_args.push("--cap-lints=allow".to_string()); + config + .lint_filter + .iter() + .map(|filter| { + let mut filter = filter.clone(); + filter.insert_str(0, "--force-warn="); + filter + }) + .collect_into(&mut lint_level_args); + }; let crates: Vec = crates .into_iter() @@ -698,7 +338,7 @@ fn lintcheck(config: LintcheckConfig) { &counter, crates.len(), &config, - &lint_filter, + &lint_level_args, &server, ) }) @@ -727,7 +367,9 @@ fn lintcheck(config: LintcheckConfig) { } let text = match config.format { - OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config), + OutputFormat::Text | OutputFormat::Markdown => { + output::summarize_and_print_changes(&warnings, &raw_ices, clippy_ver, &config) + }, OutputFormat::Json => { if !raw_ices.is_empty() { for ice in raw_ices { @@ -736,7 +378,7 @@ fn lintcheck(config: LintcheckConfig) { panic!("Some crates ICEd"); } - json::output(&warnings) + json::output(warnings) }, }; @@ -745,135 +387,6 @@ fn lintcheck(config: LintcheckConfig) { fs::write(&config.lintcheck_results_path, text).unwrap(); } -/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] -fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String { - // generate some stats - let (stats_formatted, new_stats) = gather_stats(warnings); - let old_stats = read_stats_from_file(&config.lintcheck_results_path); - - let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); - all_msgs.sort(); - all_msgs.push("\n\n### Stats:\n\n".into()); - all_msgs.push(stats_formatted); - - let mut text = clippy_ver; // clippy version number on top - text.push_str("\n### Reports\n\n"); - if config.format == OutputFormat::Markdown { - text.push_str("| file | lint | message |\n"); - text.push_str("| --- | --- | --- |\n"); - } - write!(text, "{}", all_msgs.join("")).unwrap(); - text.push_str("\n\n### ICEs:\n"); - for ice in ices { - writeln!(text, "{ice}").unwrap(); - } - - print_stats(old_stats, new_stats, &config.lint_filter); - - text -} - -/// read the previous stats from the lintcheck-log file -fn read_stats_from_file(file_path: &Path) -> HashMap { - let file_content: String = match fs::read_to_string(file_path).ok() { - Some(content) => content, - None => { - return HashMap::new(); - }, - }; - - let lines: Vec = file_content.lines().map(ToString::to_string).collect(); - - lines - .iter() - .skip_while(|line| line.as_str() != "### Stats:") - // Skipping the table header and the `Stats:` label - .skip(4) - .take_while(|line| line.starts_with("| ")) - .filter_map(|line| { - let mut spl = line.split('|'); - // Skip the first `|` symbol - spl.next(); - if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { - Some((lint.trim().to_string(), count.trim().parse::().unwrap())) - } else { - None - } - }) - .collect::>() -} - -/// print how lint counts changed between runs -fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { - let same_in_both_hashmaps = old_stats - .iter() - .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) - .map(|(k, v)| (k.to_string(), *v)) - .collect::>(); - - let mut old_stats_deduped = old_stats; - let mut new_stats_deduped = new_stats; - - // remove duplicates from both hashmaps - for (k, v) in &same_in_both_hashmaps { - assert!(old_stats_deduped.remove(k) == Some(*v)); - assert!(new_stats_deduped.remove(k) == Some(*v)); - } - - println!("\nStats:"); - - // list all new counts (key is in new stats but not in old stats) - new_stats_deduped - .iter() - .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_value)| { - println!("{new_key} 0 => {new_value}"); - }); - - // list all changed counts (key is in both maps but value differs) - new_stats_deduped - .iter() - .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_val)| { - let old_val = old_stats_deduped.get::(new_key).unwrap(); - println!("{new_key} {old_val} => {new_val}"); - }); - - // list all gone counts (key is in old status but not in new stats) - old_stats_deduped - .iter() - .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) - .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) - .for_each(|(old_key, old_value)| { - println!("{old_key} {old_value} => 0"); - }); -} - -/// Create necessary directories to run the lintcheck tool. -/// -/// # Panics -/// -/// This function panics if creating one of the dirs fails. -fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { - fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create lintcheck target dir" - ); - }); - fs::create_dir(krate_download_dir).unwrap_or_else(|err| { - assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); - }); - fs::create_dir(extract_dir).unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create crate extraction dir" - ); - }); -} - /// Returns the path to the Clippy project directory #[must_use] fn clippy_project_root() -> &'static Path { diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs new file mode 100644 index 000000000000..4bfc554ef9e6 --- /dev/null +++ b/src/tools/clippy/lintcheck/src/output.rs @@ -0,0 +1,235 @@ +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt::{self, Write as _}; +use std::fs; +use std::path::Path; +use std::process::ExitStatus; + +use crate::config::{LintcheckConfig, OutputFormat}; + +/// A single emitted output from clippy being executed on a crate. It may either be a +/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many +/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). +#[derive(Debug)] +pub enum ClippyCheckOutput { + ClippyWarning(ClippyWarning), + RustcIce(RustcIce), +} + +#[derive(Debug)] +pub struct RustcIce { + pub crate_name: String, + pub ice_content: String, +} + +impl fmt::Display for RustcIce { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}:\n{}\n========================================\n", + self.crate_name, self.ice_content + ) + } +} + +impl RustcIce { + pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { + if status.code().unwrap_or(0) == 101 + /* ice exit status */ + { + Some(Self { + crate_name: crate_name.to_owned(), + ice_content: stderr.to_owned(), + }) + } else { + None + } + } +} + +/// A single warning that clippy issued while checking a `Crate` +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ClippyWarning { + pub lint: String, + pub diag: Diagnostic, +} + +#[allow(unused)] +impl ClippyWarning { + pub fn new(mut diag: Diagnostic) -> Option { + let lint = diag.code.clone()?.code; + if !(lint.contains("clippy") || diag.message.contains("clippy")) + || diag.message.contains("could not read cargo metadata") + { + return None; + } + + // --recursive bypasses cargo so we have to strip the rendered output ourselves + let rendered = diag.rendered.as_mut().unwrap(); + *rendered = strip_ansi_escapes::strip_str(&rendered); + + Some(Self { lint, diag }) + } + + pub fn span(&self) -> &DiagnosticSpan { + self.diag.spans.iter().find(|span| span.is_primary).unwrap() + } + + pub fn to_output(&self, format: OutputFormat) -> String { + let span = self.span(); + let mut file = span.file_name.clone(); + let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); + match format { + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), + OutputFormat::Markdown => { + if file.starts_with("target") { + file.insert_str(0, "../"); + } + + let mut output = String::from("| "); + write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); + output.push('\n'); + output + }, + OutputFormat::Json => unreachable!("JSON output is handled via serde"), + } + } +} + +/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] +pub fn summarize_and_print_changes( + warnings: &[ClippyWarning], + ices: &[RustcIce], + clippy_ver: String, + config: &LintcheckConfig, +) -> String { + // generate some stats + let (stats_formatted, new_stats) = gather_stats(warnings); + let old_stats = read_stats_from_file(&config.lintcheck_results_path); + + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); + all_msgs.sort(); + all_msgs.push("\n\n### Stats:\n\n".into()); + all_msgs.push(stats_formatted); + + let mut text = clippy_ver; // clippy version number on top + text.push_str("\n### Reports\n\n"); + if config.format == OutputFormat::Markdown { + text.push_str("| file | lint | message |\n"); + text.push_str("| --- | --- | --- |\n"); + } + write!(text, "{}", all_msgs.join("")).unwrap(); + text.push_str("\n\n### ICEs:\n"); + for ice in ices { + writeln!(text, "{ice}").unwrap(); + } + + print_stats(old_stats, new_stats, &config.lint_filter); + + text +} + +/// Generate a short list of occurring lints-types and their count +fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { + // count lint type occurrences + let mut counter: HashMap<&String, usize> = HashMap::new(); + warnings + .iter() + .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); + + // collect into a tupled list for sorting + let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); + // sort by "000{count} {clippy::lintname}" + // to not have a lint with 200 and 2 warnings take the same spot + stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); + + let mut header = String::from("| lint | count |\n"); + header.push_str("| -------------------------------------------------- | ----- |\n"); + let stats_string = stats + .iter() + .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) + .fold(header, |mut table, line| { + table.push_str(&line); + table + }); + + (stats_string, counter) +} + +/// read the previous stats from the lintcheck-log file +fn read_stats_from_file(file_path: &Path) -> HashMap { + let file_content: String = match fs::read_to_string(file_path).ok() { + Some(content) => content, + None => { + return HashMap::new(); + }, + }; + + let lines: Vec = file_content.lines().map(ToString::to_string).collect(); + + lines + .iter() + .skip_while(|line| line.as_str() != "### Stats:") + // Skipping the table header and the `Stats:` label + .skip(4) + .take_while(|line| line.starts_with("| ")) + .filter_map(|line| { + let mut spl = line.split('|'); + // Skip the first `|` symbol + spl.next(); + if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { + Some((lint.trim().to_string(), count.trim().parse::().unwrap())) + } else { + None + } + }) + .collect::>() +} + +/// print how lint counts changed between runs +fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { + let same_in_both_hashmaps = old_stats + .iter() + .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) + .map(|(k, v)| (k.to_string(), *v)) + .collect::>(); + + let mut old_stats_deduped = old_stats; + let mut new_stats_deduped = new_stats; + + // remove duplicates from both hashmaps + for (k, v) in &same_in_both_hashmaps { + assert!(old_stats_deduped.remove(k) == Some(*v)); + assert!(new_stats_deduped.remove(k) == Some(*v)); + } + + println!("\nStats:"); + + // list all new counts (key is in new stats but not in old stats) + new_stats_deduped + .iter() + .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_value)| { + println!("{new_key} 0 => {new_value}"); + }); + + // list all changed counts (key is in both maps but value differs) + new_stats_deduped + .iter() + .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_val)| { + let old_val = old_stats_deduped.get::(new_key).unwrap(); + println!("{new_key} {old_val} => {new_val}"); + }); + + // list all gone counts (key is in old status but not in new stats) + old_stats_deduped + .iter() + .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) + .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) + .for_each(|(old_key, old_value)| { + println!("{old_key} {old_value} => 0"); + }); +} diff --git a/src/tools/clippy/lintcheck/src/popular_crates.rs b/src/tools/clippy/lintcheck/src/popular_crates.rs index 880a8bd81f08..ad8fc440c424 100644 --- a/src/tools/clippy/lintcheck/src/popular_crates.rs +++ b/src/tools/clippy/lintcheck/src/popular_crates.rs @@ -44,7 +44,7 @@ pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box let mut out = "[crates]\n".to_string(); for Crate { name, max_version } in crates { - writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap(); + writeln!(out, "{name} = {{ name = '{name}', version = '{max_version}' }}").unwrap(); } fs::write(output, out)?; diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs index 994fa3c3b239..373ca6f99184 100644 --- a/src/tools/clippy/lintcheck/src/recursive.rs +++ b/src/tools/clippy/lintcheck/src/recursive.rs @@ -3,7 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::{ClippyWarning, RecursiveOptions}; +use crate::input::RecursiveOptions; +use crate::ClippyWarning; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; @@ -19,8 +20,6 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)] pub(crate) struct DriverInfo { pub package_name: String, - pub crate_name: String, - pub version: String, } pub(crate) fn serialize_line(value: &T, writer: &mut W) @@ -65,7 +64,7 @@ fn process_stream( let messages = stderr .lines() .filter_map(|json_msg| serde_json::from_str::(json_msg).ok()) - .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version)); + .filter_map(ClippyWarning::new); for message in messages { sender.send(message).unwrap(); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 72b50d59f7e9..a61c22c59f98 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,4 @@ [toolchain] -channel = "nightly-2024-06-27" +channel = "nightly-2024-07-11" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] +profile = "minimal" diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr index 1be4b665bcba..66eda44f7455 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr @@ -1,22 +1,18 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> tests/ui-internal/disallow_span_lint.rs:14:5 + --> tests/ui-internal/disallow_span_lint.rs:14:8 | -LL | / cx.span_lint(lint, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +LL | cx.span_lint(lint, span, |lint| { + | ^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml) = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:20:5 + --> tests/ui-internal/disallow_span_lint.rs:20:9 | -LL | / tcx.node_span_lint(lint, hir_id, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +LL | tcx.node_span_lint(lint, hir_id, span, |lint| { + | ^^^^^^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml) diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index a74d8757e4a5..016ee502c242 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -1,4 +1,4 @@ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 | LL | let _x = String::from("hello"); @@ -8,13 +8,13 @@ LL | let _x = String::from("hello"); = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` -error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` +error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13 | LL | let _x = String::from("hi!"); diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml new file mode 100644 index 000000000000..cda8d17eed44 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed new file mode 100644 index 000000000000..40556ca5410f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs new file mode 100644 index 000000000000..bbc63ceb15a3 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr new file mode 100644 index 000000000000..c10607bf4bab --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr @@ -0,0 +1,12 @@ +error: this argument is a mutable reference, but not used mutably + --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19 + | +LL | pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | + = warning: changing this function will impact semver compatibility + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 4afbbf5f8079..f661e76cc746 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -2,36 +2,36 @@ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8 | LL | re.is_match("abc"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: no matching allowed (from clippy.toml) error: use of a disallowed method `std::iter::Iterator::sum` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14 | LL | a.iter().sum::(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7 | LL | a.sort_unstable(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61 @@ -55,37 +55,37 @@ error: use of a disallowed method `futures::stream::select_all` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 | LL | local_fn(); - | ^^^^^^^^^^ + | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5 | LL | local_mod::f(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7 | LL | s.method(); - | ^^^^^^^^^^ + | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7 | LL | s.provided_method(); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7 | LL | s.implemented_method(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs index 1309ae45d0ae..957154e60dec 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.rs +++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs @@ -1,4 +1,4 @@ -#![allow(non_fmt_panics, clippy::needless_bool)] +#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)] macro_rules! assert_const { ($len:expr) => { @@ -49,7 +49,16 @@ fn main() { const _: () = assert!(true); //~^ ERROR: `assert!(true)` will be optimized out by the compiler + assert!(8 == (7 + 1)); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler + // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; const _: () = assert!(N.is_power_of_two()); } + +const _: () = { + assert!(true); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler + assert!(8 == (7 + 1)); +}; diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr index 00f117c94920..e164a999c43e 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr @@ -80,5 +80,21 @@ LL | const _: () = assert!(true); | = help: remove it -error: aborting due to 10 previous errors +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:52:5 + | +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove it + +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:61:5 + | +LL | assert!(true); + | ^^^^^^^^^^^^^ + | + = help: remove it + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs index 8e5510e6cd01..cecf00c934fe 100644 --- a/src/tools/clippy/tests/ui/await_holding_lock.rs +++ b/src/tools/clippy/tests/ui/await_holding_lock.rs @@ -8,7 +8,7 @@ mod std_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -24,13 +24,13 @@ mod std_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -52,7 +52,7 @@ mod std_mutex { let first = baz().await; let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -66,7 +66,7 @@ mod std_mutex { let second = { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -79,7 +79,7 @@ mod std_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -92,7 +92,7 @@ mod parking_lot_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -108,13 +108,13 @@ mod parking_lot_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -136,7 +136,7 @@ mod parking_lot_mutex { let first = baz().await; let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -150,7 +150,7 @@ mod parking_lot_mutex { let second = { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -163,7 +163,7 @@ mod parking_lot_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex) { // `*guard += 1` is removed it is picked up. async fn dropped_before_await(x: std::sync::Mutex) { let mut guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point *guard += 1; drop(guard); baz().await; diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr index 0af48a36acca..af61d8939483 100644 --- a/src/tools/clippy/tests/ui/await_holding_lock.stderr +++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr @@ -1,11 +1,11 @@ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:10:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:12:15 | LL | baz().await @@ -13,40 +13,40 @@ LL | baz().await = note: `-D clippy::await-holding-lock` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:26:13 | LL | let guard = x.read().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:28:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:32:13 | LL | let mut guard = x.write().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:34:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:54:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:57:28 | LL | let second = baz().await; @@ -55,79 +55,79 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:68:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:70:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:81:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:83:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:94:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:96:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:110:13 | LL | let guard = x.read(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:112:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:116:13 | LL | let mut guard = x.write(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:118:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:138:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:141:28 | LL | let second = baz().await; @@ -136,40 +136,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:152:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:154:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:165:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:167:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:186:9 | LL | let mut guard = x.lock().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:190:11 | LL | baz().await; diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs index 5bd26c628362..b0c92d8c1f6e 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs @@ -4,13 +4,13 @@ use std::cell::RefCell; async fn bad(x: &RefCell) -> u32 { let b = x.borrow(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } async fn bad_mut(x: &RefCell) -> u32 { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } @@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -61,7 +61,7 @@ async fn not_good(x: &RefCell) -> u32 { let second = { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await }; @@ -74,7 +74,7 @@ async fn not_good(x: &RefCell) -> u32 { fn block_bad(x: &RefCell) -> impl std::future::Future + '_ { async move { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } } diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr index 6b474c27ddc1..6c7209c9ff9e 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr @@ -1,11 +1,11 @@ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:8:11 | LL | baz().await @@ -13,27 +13,27 @@ LL | baz().await = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:12:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:14:11 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:34:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:37:24 | LL | let second = baz().await; @@ -42,40 +42,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:47:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:50:24 | LL | let second = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:63:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:65:15 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:76:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:78:15 | LL | baz().await diff --git a/src/tools/clippy/tests/ui/byte_char_slices.fixed b/src/tools/clippy/tests/ui/byte_char_slices.fixed new file mode 100644 index 000000000000..d1db58f9363e --- /dev/null +++ b/src/tools/clippy/tests/ui/byte_char_slices.fixed @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = b"abc"; + let quotes = b"\"Hi"; + let quotes = b"'Sup"; + let escapes = b"\x42Esc"; + + let good = &[b'a', 0x42]; + let good = [b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/src/tools/clippy/tests/ui/byte_char_slices.rs b/src/tools/clippy/tests/ui/byte_char_slices.rs new file mode 100644 index 000000000000..18648fffceb4 --- /dev/null +++ b/src/tools/clippy/tests/ui/byte_char_slices.rs @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = &[b'a', b'b', b'c']; + let quotes = &[b'"', b'H', b'i']; + let quotes = &[b'\'', b'S', b'u', b'p']; + let escapes = &[b'\x42', b'E', b's', b'c']; + + let good = &[b'a', 0x42]; + let good = vec![b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/src/tools/clippy/tests/ui/byte_char_slices.stderr b/src/tools/clippy/tests/ui/byte_char_slices.stderr new file mode 100644 index 000000000000..4e2b5d8a7329 --- /dev/null +++ b/src/tools/clippy/tests/ui/byte_char_slices.stderr @@ -0,0 +1,38 @@ +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:5:15 + | +LL | let bad = &[b'a', b'b', b'c']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"` + | + = note: `-D clippy::byte-char-slices` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:6:18 + | +LL | let quotes = &[b'"', b'H', b'i']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:7:18 + | +LL | let quotes = &[b'\'', b'S', b'u', b'p']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:8:19 + | +LL | let escapes = &[b'\x42', b'E', b's', b'c']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` + +error: useless use of `vec!` + --> tests/ui/byte_char_slices.rs:11:16 + | +LL | let good = vec![b'a', b'a']; + | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/cfg_not_test.rs b/src/tools/clippy/tests/ui/cfg_not_test.rs new file mode 100644 index 000000000000..da3e29d28966 --- /dev/null +++ b/src/tools/clippy/tests/ui/cfg_not_test.rs @@ -0,0 +1,32 @@ +#![allow(unused)] +#![warn(clippy::cfg_not_test)] + +fn important_check() {} + +fn main() { + // Statement + #[cfg(not(test))] + let answer = 42; + + // Expression + #[cfg(not(test))] + important_check(); + + // Make sure only not(test) are checked, not other attributes + #[cfg(not(foo))] + important_check(); +} + +#[cfg(not(not(test)))] +struct CfgNotTest; + +// Deeply nested `not(test)` +#[cfg(not(test))] +fn foo() {} +#[cfg(all(debug_assertions, not(test)))] +fn bar() {} +#[cfg(not(any(not(debug_assertions), test)))] +fn baz() {} + +#[cfg(test)] +mod tests {} diff --git a/src/tools/clippy/tests/ui/cfg_not_test.stderr b/src/tools/clippy/tests/ui/cfg_not_test.stderr new file mode 100644 index 000000000000..c1bf626887af --- /dev/null +++ b/src/tools/clippy/tests/ui/cfg_not_test.stderr @@ -0,0 +1,45 @@ +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:8:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + = note: this could increase code coverage despite not actually being tested + = note: `-D clippy::cfg-not-test` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]` + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:12:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:24:1 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:26:1 + | +LL | #[cfg(all(debug_assertions, not(test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:28:1 + | +LL | #[cfg(not(any(not(debug_assertions), test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr index c7cf5cf5483f..a84a945a429f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/crashes/ice-12616.rs:6:5 | LL | s() as *const (); diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 13c883409bf6..96531bf8d88c 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs @@ -60,6 +60,7 @@ fn issue_1647_ref_mut() { //~^ ERROR: use of a disallowed/placeholder name `quux` } +#[cfg(test)] mod tests { fn issue_7305() { // `disallowed_names` lint should not be triggered inside of the test code. diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed new file mode 100644 index 000000000000..1aaa26afe7f2 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed @@ -0,0 +1,47 @@ +// https://github.com/rust-lang/rust-clippy/issues/12917 +#![warn(clippy::doc_lazy_continuation)] + +/// This is a constant. +/// +/// The meaning of which should not be explained. +pub const A: i32 = 42; + +/// This is another constant, no longer used. +/// +/// This block of documentation has a long +/// explanation and derivation to explain +/// why it is what it is, and how it's used. +/// +/// It is left here for historical reasons, and +/// for reference. +/// +/// Reasons it's great: +/// - First reason +/// - Second reason +/// +//pub const B: i32 = 1337; + +/// This is yet another constant. +/// +/// This has a similar fate as `B`. +/// +/// Reasons it's useful: +/// 1. First reason +/// 2. Second reason +/// +//pub const C: i32 = 8008; + +/// This is still in use. +pub const D: i32 = 20; + +/// > blockquote code path +/// + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +/// +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs new file mode 100644 index 000000000000..e1ab8fc83892 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs @@ -0,0 +1,43 @@ +// https://github.com/rust-lang/rust-clippy/issues/12917 +#![warn(clippy::doc_lazy_continuation)] + +/// This is a constant. +/// +/// The meaning of which should not be explained. +pub const A: i32 = 42; + +/// This is another constant, no longer used. +/// +/// This block of documentation has a long +/// explanation and derivation to explain +/// why it is what it is, and how it's used. +/// +/// It is left here for historical reasons, and +/// for reference. +/// +/// Reasons it's great: +/// - First reason +/// - Second reason +//pub const B: i32 = 1337; + +/// This is yet another constant. +/// +/// This has a similar fate as `B`. +/// +/// Reasons it's useful: +/// 1. First reason +/// 2. Second reason +//pub const C: i32 = 8008; + +/// This is still in use. +pub const D: i32 = 20; + +/// > blockquote code path + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr new file mode 100644 index 000000000000..854906a74741 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr @@ -0,0 +1,56 @@ +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 + | +LL | /// This is yet another constant. + | ^ + | + = help: if this is intended to be part of the list, indent 3 spaces + = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// - Second reason +LL + /// + | + +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 + | +LL | /// This is still in use. + | ^ + | + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// 2. Second reason +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed index 9877991f183a..9d6e8637608f 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed @@ -2,7 +2,7 @@ /// > blockquote with /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// > lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs index 587b2fdd533c..0323a1b44e7c 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs @@ -2,7 +2,7 @@ /// > blockquote with /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr index 975184a01c3f..d3390efdff37 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr @@ -1,4 +1,4 @@ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: add markers to start of line LL | /// > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:20:5 | LL | /// > lazy continuation @@ -24,7 +24,7 @@ help: add markers to start of line LL | /// > > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:27:5 | LL | /// lazy continuation @@ -36,7 +36,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:32:5 | LL | /// lazy continuation @@ -48,7 +48,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:37:5 | LL | /// lazy continuation @@ -60,7 +60,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:45:5 | LL | /// lazy continuation (this results in strange indentation, but still works) diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed index 409e6b0bc227..ea59ae4c01c9 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed @@ -2,38 +2,41 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation -/// and so should this -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// and so should this +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +57,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +76,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs index 30ab448a1130..3cc18e35780a 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs @@ -2,38 +2,38 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// and so should this -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +54,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +73,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr index ddfdc49340c4..52aa74df8948 100644 --- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr @@ -1,4 +1,4 @@ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: indent this line LL | /// lazy continuation | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:9:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -24,19 +24,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:11:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 3 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 | LL | /// lazy continuation @@ -48,7 +49,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:21:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -60,19 +61,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:23:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 | LL | /// lazy continuation @@ -84,7 +86,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:33:5 | LL | /// this will warn on the lazy continuation @@ -96,19 +98,20 @@ help: indent this line LL | /// this will warn on the lazy continuation | ++++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:35:5 | LL | /// and so should this | ^^^^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 2 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// this will warn on the lazy continuation +LL + /// | -LL | /// and so should this - | ++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 | LL | /// 'protocol_descriptors': [ @@ -120,7 +123,7 @@ help: indent this line LL | /// 'protocol_descriptors': [ | + -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:75:5 | LL | /// ] diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs index 6f7bab72040c..04446787b6c2 100644 --- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs +++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs @@ -49,3 +49,20 @@ fn other_markdown() {} /// pub struct Struct; /// ``` fn issue_7421() {} + +/// ` +//~^ ERROR: backticks are unbalanced +fn escape_0() {} + +/// Escaped \` backticks don't count. +fn escape_1() {} + +/// Escaped \` \` backticks don't count. +fn escape_2() {} + +/// Escaped \` ` backticks don't count, but unescaped backticks do. +//~^ ERROR: backticks are unbalanced +fn escape_3() {} + +/// Backslashes ` \` within code blocks don't count. +fn escape_4() {} diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr index 56ef29136231..50324010e97f 100644 --- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr +++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr @@ -78,5 +78,21 @@ help: try LL | /// - This item needs `backticks_here` | ~~~~~~~~~~~~~~~~ -error: aborting due to 8 previous errors +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:53:5 + | +LL | /// ` + | ^ + | + = help: a backtick may be missing a pair + +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:63:5 + | +LL | /// Escaped \` ` backticks don't count, but unescaped backticks do. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: a backtick may be missing a pair + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed index e6ca4bb66ccd..255b2c5a220d 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed @@ -345,3 +345,39 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs index 7531e1f87b71..99906999f01d 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs @@ -345,3 +345,39 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&*wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr index 56a183de3487..53784934f638 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr @@ -271,5 +271,11 @@ error: deref which would be done by auto-deref LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` -error: aborting due to 45 previous errors +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:367:13 + | +LL | foo(&*wrapped_bar); + | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` + +error: aborting due to 46 previous errors diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs index 1923ad7c677e..78dd2c6c01c3 100644 --- a/src/tools/clippy/tests/ui/float_cmp.rs +++ b/src/tools/clippy/tests/ui/float_cmp.rs @@ -71,19 +71,16 @@ fn main() { twice(ONE) != ONE; ONE as f64 != 2.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE as f64 != 0.0; // no error, comparison with zero is ok let x: f64 = 1.0; x == 1.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x != 0f64; // no error, comparison with zero is ok twice(x) != twice(ONE as f64); //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x < 0.0; // no errors, lower or greater comparisons need no fuzzyness x > 0.0; @@ -105,17 +102,14 @@ fn main() { ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let a1: [f32; 1] = [0.0]; let a2: [f32; 1] = [1.1]; a1 == a2; //~^ ERROR: strict comparison of `f32` or `f64` arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` a1[0] == a2[0]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors - comparing signums is ok let x32 = 3.21f32; diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr index c8a0bde6e63a..d10da8a99a9d 100644 --- a/src/tools/clippy/tests/ui/float_cmp.stderr +++ b/src/tools/clippy/tests/ui/float_cmp.stderr @@ -4,49 +4,38 @@ error: strict comparison of `f32` or `f64` LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:79:5 + --> tests/ui/float_cmp.rs:78:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:84:5 + --> tests/ui/float_cmp.rs:82:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:106:5 + --> tests/ui/float_cmp.rs:103:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> tests/ui/float_cmp.rs:113:5 + --> tests/ui/float_cmp.rs:109:5 | LL | a1 == a2; | ^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:116:5 + --> tests/ui/float_cmp.rs:111:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs index 47ea0e19c68b..081805564373 100644 --- a/src/tools/clippy/tests/ui/float_cmp_const.rs +++ b/src/tools/clippy/tests/ui/float_cmp_const.rs @@ -15,28 +15,21 @@ fn main() { // has errors 1f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE + ONE == TWO; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let x = 1; x as f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let v = 0.9; v == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` v != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors, lower than or greater than comparisons v < ONE; @@ -70,5 +63,4 @@ fn main() { // has errors NON_ZERO_ARRAY == NON_ZERO_ARRAY2; //~^ ERROR: strict comparison of `f32` or `f64` constant arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` } diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr index bffd2acc2e04..4f88746e958e 100644 --- a/src/tools/clippy/tests/ui/float_cmp_const.stderr +++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr @@ -4,65 +4,50 @@ error: strict comparison of `f32` or `f64` constant LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:19:5 + --> tests/ui/float_cmp_const.rs:18:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` + +error: strict comparison of `f32` or `f64` constant + --> tests/ui/float_cmp_const.rs:20:5 | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | TWO != ONE; + | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:22:5 | -LL | TWO != ONE; - | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | ONE + ONE == TWO; + | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:25:5 | -LL | ONE + ONE == TWO; - | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | x as f32 == ONE; + | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:29:5 | -LL | x as f32 == ONE; - | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` - -error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:34:5 - | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:37:5 + --> tests/ui/float_cmp_const.rs:31:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant arrays - --> tests/ui/float_cmp_const.rs:71:5 + --> tests/ui/float_cmp_const.rs:64:5 | LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/init_numbered_fields.fixed similarity index 82% rename from src/tools/clippy/tests/ui/numbered_fields.fixed rename to src/tools/clippy/tests/ui/init_numbered_fields.fixed index 108520eed38d..dca4e8da4d2f 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.fixed +++ b/src/tools/clippy/tests/ui/init_numbered_fields.fixed @@ -39,4 +39,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec(vec![0, 1, 2, 3]); + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/init_numbered_fields.rs similarity index 84% rename from src/tools/clippy/tests/ui/numbered_fields.rs rename to src/tools/clippy/tests/ui/init_numbered_fields.rs index c718661a6826..8cb34705b4f6 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.rs +++ b/src/tools/clippy/tests/ui/init_numbered_fields.rs @@ -47,4 +47,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/init_numbered_fields.stderr similarity index 63% rename from src/tools/clippy/tests/ui/numbered_fields.stderr rename to src/tools/clippy/tests/ui/init_numbered_fields.stderr index 9d3f59cd3769..f176e0c2ff30 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.stderr +++ b/src/tools/clippy/tests/ui/init_numbered_fields.stderr @@ -1,5 +1,5 @@ error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:17:13 + --> tests/ui/init_numbered_fields.rs:17:13 | LL | let _ = TupleStruct { | _____________^ @@ -7,13 +7,13 @@ LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:24:13 + --> tests/ui/init_numbered_fields.rs:24:13 | LL | let _ = TupleStruct { | _____________^ @@ -21,13 +21,13 @@ LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:49:13 + --> tests/ui/init_numbered_fields.rs:49:13 | LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs index c8b9076041a3..109259d6975c 100644 --- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs +++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs @@ -185,3 +185,42 @@ pub mod issue11635 { } } } + +pub mod issue12964 { + pub struct MyIter<'a, T: 'a> { + iter: std::slice::Iter<'a, T>, + } + + impl<'a, T> Iterator for MyIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + } + + pub struct MyContainer { + inner: Vec, + } + + impl MyContainer {} + + impl MyContainer { + #[must_use] + pub fn iter(&self) -> MyIter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + } + + impl<'a, T> IntoIterator for &'a MyContainer { + type Item = &'a T; + + type IntoIter = MyIter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter { + iter: self.inner.as_slice().iter(), + } + } + } +} diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs index 548b799de44e..d425f4da0e81 100644 --- a/src/tools/clippy/tests/ui/iter_next_loop.rs +++ b/src/tools/clippy/tests/ui/iter_next_loop.rs @@ -3,7 +3,7 @@ fn main() { let x = [1, 2, 3, 4]; - for _ in vec.iter().next() {} + for _ in x.iter().next() {} struct Unrelated(&'static [u8]); impl Unrelated { diff --git a/src/tools/clippy/tests/ui/iter_next_loop.stderr b/src/tools/clippy/tests/ui/iter_next_loop.stderr index 85c23f4e7094..acc55031c3b2 100644 --- a/src/tools/clippy/tests/ui/iter_next_loop.stderr +++ b/src/tools/clippy/tests/ui/iter_next_loop.stderr @@ -1,9 +1,11 @@ -error[E0423]: expected value, found macro `vec` +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want --> tests/ui/iter_next_loop.rs:6:14 | -LL | for _ in vec.iter().next() {} - | ^^^ not a value +LL | for _ in x.iter().next() {} + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::iter-next-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0423`. diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr index 8548c0cd2942..0559b3bd6611 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.stderr +++ b/src/tools/clippy/tests/ui/manual_inspect.stderr @@ -1,4 +1,4 @@ -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:5:21 | LL | let _ = Some(0).map(|x| { @@ -12,7 +12,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:10:21 | LL | let _ = Some(0).map(|x| { @@ -24,7 +24,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{x}"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:15:21 | LL | let _ = Some(0).map(|x| { @@ -36,7 +36,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x * 5 + 1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:20:21 | LL | let _ = Some(0).map(|x| { @@ -50,7 +50,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:27:21 | LL | let _ = Some(0).map(|x| { @@ -65,7 +65,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:78:41 | LL | let _ = Some((String::new(), 0u32)).map(|x| { @@ -80,7 +80,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:104:33 | LL | let _ = Some(String::new()).map(|x| { @@ -98,7 +98,7 @@ LL | } LL ~ println!("test"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:115:21 | LL | let _ = Some(0).map(|x| { @@ -113,7 +113,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:130:46 | LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { @@ -125,7 +125,7 @@ LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { LL ~ x.0.set(1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:146:34 | LL | let _: Result<_, ()> = Ok(0).map(|x| { @@ -137,7 +137,7 @@ LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map_err` over `inspect_err` --> tests/ui/manual_inspect.rs:151:35 | LL | let _: Result<(), _> = Err(0).map_err(|x| { @@ -166,7 +166,7 @@ LL | | .count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:158:10 | LL | .map(|x| { diff --git a/src/tools/clippy/tests/ui/manual_rotate.fixed b/src/tools/clippy/tests/ui/manual_rotate.fixed new file mode 100644 index 000000000000..5d33838a3187 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rotate.fixed @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = x_u8.rotate_right(3); + let y_u16 = x_u16.rotate_right(7); + let y_u32 = x_u32.rotate_right(8); + let y_u64 = x_u64.rotate_right(9); + let y_i8 = x_i8.rotate_right(3); + let y_i16 = x_i16.rotate_right(7); + let y_i32 = x_i32.rotate_right(8); + let y_i64 = x_i64.rotate_right(9); + // Plus also works instead of | + let y_u32_plus = x_u32.rotate_right(8); + // Complex expression + let y_u32_complex = (x_u32 | 3256).rotate_right(8); + let y_u64_as = (x_u32 as u64).rotate_right(8); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/src/tools/clippy/tests/ui/manual_rotate.rs b/src/tools/clippy/tests/ui/manual_rotate.rs new file mode 100644 index 000000000000..5377491fb1a3 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rotate.rs @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + // Plus also works instead of | + let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + // Complex expression + let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/src/tools/clippy/tests/ui/manual_rotate.stderr b/src/tools/clippy/tests/ui/manual_rotate.stderr new file mode 100644 index 000000000000..52da0861f700 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rotate.stderr @@ -0,0 +1,71 @@ +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:8:16 + | +LL | let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)` + | + = note: `-D clippy::manual-rotate` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:9:17 + | +LL | let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:10:17 + | +LL | let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:11:17 + | +LL | let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:12:16 + | +LL | let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:13:17 + | +LL | let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:14:17 + | +LL | let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:15:17 + | +LL | let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:17:22 + | +LL | let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:19:25 + | +LL | let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:20:20 + | +LL | let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)` + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index 2750e0cdf3f7..2c6e1e92da02 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -7,6 +7,7 @@ #![warn(clippy::missing_const_for_fn)] #![feature(start)] +#![feature(type_alias_impl_trait)] extern crate helper; extern crate proc_macros; @@ -180,4 +181,21 @@ mod msrv { unsafe { *self.1 as usize } } } + + #[clippy::msrv = "1.61"] + extern "C" fn c() {} +} + +mod with_extern { + extern "C-unwind" fn c_unwind() {} + extern "system" fn system() {} + extern "system-unwind" fn system_unwind() {} +} + +mod with_ty_alias { + type Foo = impl std::fmt::Debug; + + fn foo(_: Foo) { + let _: Foo = 1; + } } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed index f8fc935f3679..dbd739eee138 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -143,6 +143,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + const extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + const extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { @@ -174,3 +189,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 5e4e2c58e5a4..4ac56f4c8034 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -143,6 +143,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { @@ -174,3 +189,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 8302b074127e..fb4db7031031 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -211,7 +211,29 @@ LL | const fn union_access_can_be_const() { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9 + | +LL | extern "C" fn c() {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "C" fn c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9 + | +LL | extern fn implicit_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern fn implicit_c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -224,7 +246,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -237,7 +259,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -250,5 +272,16 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 18 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5 + | +LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | +++++ + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed new file mode 100644 index 000000000000..c103db536ab5 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +const extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +const extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +const extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs new file mode 100644 index 000000000000..0f7020ae559a --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr new file mode 100644 index 000000000000..036094a367b2 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr @@ -0,0 +1,59 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1 + | +LL | extern "C-unwind" fn c_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const extern "C-unwind" fn c_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1 + | +LL | extern "system" fn system() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system" fn system() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1 + | +LL | extern "system-unwind" fn system_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system-unwind" fn system_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1 + | +LL | pub extern "stdcall" fn std_call() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall" fn std_call() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1 + | +LL | pub extern "stdcall-unwind" fn std_call_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} + | +++++ + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed similarity index 97% rename from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed rename to src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed index 4c9bd0bd8634..90b31b9b5d21 100644 --- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs similarity index 97% rename from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs rename to src/tools/clippy/tests/ui/missing_const_for_thread_local.rs index eb336f0dd191..f97e4848fd7a 100644 --- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr similarity index 72% rename from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr rename to src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr index b4f8bd822b0d..c143a37454f5 100644 --- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr @@ -1,38 +1,38 @@ error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:8:41 + --> tests/ui/missing_const_for_thread_local.rs:8:41 | LL | static BUF_1: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` | - = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]` + = note: `-D clippy::missing-const-for-thread-local` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_thread_local)]` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:18:29 + --> tests/ui/missing_const_for_thread_local.rs:18:29 | LL | static SIMPLE:i32 = 1; | ^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:24:59 + --> tests/ui/missing_const_for_thread_local.rs:24:59 | LL | static BUF_3_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:26:59 + --> tests/ui/missing_const_for_thread_local.rs:26:59 | LL | static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31 + --> tests/ui/missing_const_for_thread_local.rs:32:31 | LL | static PEEL_ME: i32 = { 1 }; | ^^^^^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36 + --> tests/ui/missing_const_for_thread_local.rs:34:36 | LL | static PEEL_ME_MANY: i32 = { let x = 1; x * x }; | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index eee62122fdfd..162ec82aeded 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec) { } fn non_mut(n: &str) {} //Should warn -pub async fn call_in_closure1(n: &mut str) { +async fn call_in_closure1(n: &mut str) { (|| non_mut(n))() } fn str_mut(str: &mut String) -> bool { str.pop().is_some() } //Should not warn -pub async fn call_in_closure2(str: &mut String) { +async fn call_in_closure2(str: &mut String) { (|| str_mut(str))(); } // Should not warn. -pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { +async fn closure(n: &mut usize) -> impl '_ + FnMut() { || { *n += 1; } } // Should warn. -pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { +fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { //~^ ERROR: this argument is a mutable reference, but not used mutably || *n + 1 } // Should not warn. -pub async fn closure3(n: &mut usize) { +async fn closure3(n: &mut usize) { (|| *n += 1)(); } // Should warn. -pub async fn closure4(n: &mut usize) { +async fn closure4(n: &mut usize) { //~^ ERROR: this argument is a mutable reference, but not used mutably (|| { let _x = *n + 1; })(); } +// Should not warn: pub +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + *x += *b + s.len() as u32; +} + // Should not warn. async fn _f(v: &mut Vec<()>) { let x = || v.pop(); @@ -365,4 +370,5 @@ fn main() { used_as_path; let _: fn(&mut u32) = passed_as_local; let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 }; + pub_foo(&mut v, &0, &mut u); } diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 51e3ba37dede..f462fa9099ed 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -108,109 +108,103 @@ LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:235:34 + --> tests/ui/needless_pass_by_ref_mut.rs:235:30 | -LL | pub async fn call_in_closure1(n: &mut str) { - | ^^^^^^^^ help: consider changing to: `&str` - | - = warning: changing this function will impact semver compatibility +LL | async fn call_in_closure1(n: &mut str) { + | ^^^^^^^^ help: consider changing to: `&str` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:254:20 + --> tests/ui/needless_pass_by_ref_mut.rs:254:16 | -LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { + | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:265:26 + --> tests/ui/needless_pass_by_ref_mut.rs:265:22 | -LL | pub async fn closure4(n: &mut usize) { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +LL | async fn closure4(n: &mut usize) { + | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:314:12 + --> tests/ui/needless_pass_by_ref_mut.rs:319:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:18 + --> tests/ui/needless_pass_by_ref_mut.rs:321:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:45 + --> tests/ui/needless_pass_by_ref_mut.rs:321:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:324:46 + --> tests/ui/needless_pass_by_ref_mut.rs:329:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:340:18 + --> tests/ui/needless_pass_by_ref_mut.rs:345:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:341:19 + --> tests/ui/needless_pass_by_ref_mut.rs:346:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:342:18 + --> tests/ui/needless_pass_by_ref_mut.rs:347:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:343:11 + --> tests/ui/needless_pass_by_ref_mut.rs:348:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:345:23 + --> tests/ui/needless_pass_by_ref_mut.rs:350:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:346:20 + --> tests/ui/needless_pass_by_ref_mut.rs:351:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:347:18 + --> tests/ui/needless_pass_by_ref_mut.rs:352:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:348:25 + --> tests/ui/needless_pass_by_ref_mut.rs:353:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:349:20 + --> tests/ui/needless_pass_by_ref_mut.rs:354:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:350:20 + --> tests/ui/needless_pass_by_ref_mut.rs:355:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed index 3c2576213cd7..f26b39ea6a16 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &i32, y: &mut u32) { +async fn inner_async3(x: &i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &u32) { +async fn inner_async4(u: &mut i32, v: &u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs index 34b0b564deb8..4220215b1fe9 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &mut i32, y: &mut u32) { +async fn inner_async3(x: &mut i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &mut i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &mut u32) { +async fn inner_async4(u: &mut i32, v: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr index c87536032256..1c0136cf5d59 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr @@ -1,20 +1,17 @@ error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:8:30 + --> tests/ui/needless_pass_by_ref_mut2.rs:8:26 | -LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` +LL | async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` | - = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:16:43 + --> tests/ui/needless_pass_by_ref_mut2.rs:16:39 | -LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` - | - = warning: changing this function will impact semver compatibility +LL | async fn inner_async4(u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index 853f685f04c7..fc4129e1db84 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -228,12 +228,41 @@ fn needless_return_macro() -> String { format!("Hello {}", "world!") } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index e9c1e0e8ae8e..61c7a02008f0 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -236,12 +236,41 @@ fn needless_return_macro() -> String { return format!("Hello {}", "world!"); } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 6c891fe7ad3f..ea9c230eafd2 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:248:9 + --> tests/ui/needless_return.rs:277:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:250:9 + --> tests/ui/needless_return.rs:279:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:257:13 + --> tests/ui/needless_return.rs:286:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:260:13 + --> tests/ui/needless_return.rs:289:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:268:9 + --> tests/ui/needless_return.rs:297:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:275:13 + --> tests/ui/needless_return.rs:304:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:277:13 + --> tests/ui/needless_return.rs:306:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:284:20 + --> tests/ui/needless_return.rs:313:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:291:20 + --> tests/ui/needless_return.rs:320:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:303:9 + --> tests/ui/needless_return.rs:332:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:305:9 + --> tests/ui/needless_return.rs:334:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:311:9 + --> tests/ui/needless_return.rs:340:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:315:9 + --> tests/ui/needless_return.rs:344:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:336:5 + --> tests/ui/needless_return.rs:365:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.rs b/src/tools/clippy/tests/ui/overflow_check_conditional.rs deleted file mode 100644 index a70bb3bc47bf..000000000000 --- a/src/tools/clippy/tests/ui/overflow_check_conditional.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![warn(clippy::overflow_check_conditional)] -#![allow(clippy::needless_if)] - -fn test(a: u32, b: u32, c: u32) { - if a + b < a {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - //~| NOTE: `-D clippy::overflow-check-conditional` implied by `-D warnings` - if a > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if a + b < b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if b > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if a - b > b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if b < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a - b > a {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a + b < c {} - if c > a + b {} - if a - b < c {} - if c > a - b {} - let i = 1.1; - let j = 2.2; - if i + j < i {} - if i - j < i {} - if i > i + j {} - if i - j < i {} -} - -fn main() { - test(1, 2, 3) -} diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr deleted file mode 100644 index c14532bad5ab..000000000000 --- a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:5:8 - | -LL | if a + b < a {} - | ^^^^^^^^^ - | - = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]` - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:8:8 - | -LL | if a > a + b {} - | ^^^^^^^^^ - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:10:8 - | -LL | if a + b < b {} - | ^^^^^^^^^ - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:12:8 - | -LL | if b > a + b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:14:8 - | -LL | if a - b > b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:16:8 - | -LL | if b < a - b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:18:8 - | -LL | if a - b > a {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:20:8 - | -LL | if a < a - b {} - | ^^^^^^^^^ - -error: aborting due to 8 previous errors - diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs new file mode 100644 index 000000000000..dc2ddeada1e9 --- /dev/null +++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs @@ -0,0 +1,27 @@ +#![warn(clippy::panicking_overflow_checks)] +#![allow(clippy::needless_if)] + +fn test(a: u32, b: u32, c: u32) { + if a + b < a {} //~ panicking_overflow_checks + if a > a + b {} //~ panicking_overflow_checks + if a + b < b {} //~ panicking_overflow_checks + if b > a + b {} //~ panicking_overflow_checks + if a - b > b {} + if b < a - b {} + if a - b > a {} //~ panicking_overflow_checks + if a < a - b {} //~ panicking_overflow_checks + if a + b < c {} + if c > a + b {} + if a - b < c {} + if c > a - b {} + let i = 1.1; + let j = 2.2; + if i + j < i {} + if i - j < i {} + if i > i + j {} + if i - j < i {} +} + +fn main() { + test(1, 2, 3) +} diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr new file mode 100644 index 000000000000..1fae04578899 --- /dev/null +++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr @@ -0,0 +1,41 @@ +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:5:8 + | +LL | if a + b < a {} + | ^^^^^^^^^ + | + = note: `-D clippy::panicking-overflow-checks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]` + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:6:8 + | +LL | if a > a + b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:7:8 + | +LL | if a + b < b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:8:8 + | +LL | if b > a + b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:11:8 + | +LL | if a - b > a {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:12:8 + | +LL | if a < a - b {} + | ^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index e162f35baf55..18462620b0a3 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } @@ -7,37 +7,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); @@ -45,157 +45,157 @@ LL | let _ = inline!($ptr as *const i32); | = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 24d0f7975428..d70c9f8d06c0 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -24,9 +24,11 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -77,12 +79,14 @@ #![warn(clippy::map_unwrap_or)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::unwrap_used)] +#![warn(clippy::panicking_overflow_checks)] #![warn(clippy::needless_borrow)] #![warn(clippy::expect_used)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::unwrap_used)] #![warn(clippy::single_char_add_str)] #![warn(clippy::module_name_repetitions)] +#![warn(clippy::missing_const_for_thread_local)] #![warn(clippy::recursive_format_impl)] #![warn(clippy::unwrap_or_default)] #![warn(clippy::invisible_characters)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index be8da2fa1a38..8d0ac3c8f955 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -24,9 +24,11 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -77,12 +79,14 @@ #![warn(clippy::option_map_unwrap_or)] #![warn(clippy::option_map_unwrap_or_else)] #![warn(clippy::option_unwrap_used)] +#![warn(clippy::overflow_check_conditional)] #![warn(clippy::ref_in_deref)] #![warn(clippy::result_expect_used)] #![warn(clippy::result_map_unwrap_or_else)] #![warn(clippy::result_unwrap_used)] #![warn(clippy::single_char_push_str)] #![warn(clippy::stutter)] +#![warn(clippy::thread_local_initializer_can_be_made_const)] #![warn(clippy::to_string_in_display)] #![warn(clippy::unwrap_or_else_default)] #![warn(clippy::zero_width_space)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 777ac20153da..d6637324a030 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> tests/ui/rename.rs:56:9 + --> tests/ui/rename.rs:58:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,346 +8,358 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:57:9 + --> tests/ui/rename.rs:59:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:58:9 + --> tests/ui/rename.rs:60:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:59:9 + --> tests/ui/rename.rs:61:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:60:9 + --> tests/ui/rename.rs:62:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:61:9 + --> tests/ui/rename.rs:63:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> tests/ui/rename.rs:62:9 + --> tests/ui/rename.rs:64:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:63:9 + --> tests/ui/rename.rs:65:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:64:9 + --> tests/ui/rename.rs:66:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:65:9 + --> tests/ui/rename.rs:67:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:73:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:74:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:75:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:76:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:78:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:79:9 + --> tests/ui/rename.rs:81:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` + --> tests/ui/rename.rs:82:9 + | +LL | #![warn(clippy::overflow_check_conditional)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` + error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:83:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:85:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` +error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` + --> tests/ui/rename.rs:89:9 + | +LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` + error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:97:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:101:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:102:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:105:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 58 previous errors +error: aborting due to 60 previous errors diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs new file mode 100644 index 000000000000..8465007402ab --- /dev/null +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs @@ -0,0 +1,83 @@ +#![allow(unused)] +#![allow(clippy::nonminimal_bool)] +#![allow(clippy::needless_borrow)] +#![warn(clippy::set_contains_or_insert)] + +use std::collections::HashSet; + +fn main() { + should_warn_cases(); + + should_not_warn_cases(); +} + +fn should_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + + if !set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if !set.contains(&value) { + set.insert(value); + } + + if !!set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if (&set).contains(&value) { + set.insert(value); + } + + let borrow_value = &6; + if !set.contains(borrow_value) { + set.insert(*borrow_value); + } + + let borrow_set = &mut set; + if !borrow_set.contains(&value) { + borrow_set.insert(value); + } +} + +fn should_not_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + let another_value = 6; + + if !set.contains(&value) { + set.insert(another_value); + } + + if !set.contains(&value) { + println!("Just a comment"); + } + + if simply_true() { + set.insert(value); + } + + if !set.contains(&value) { + set.replace(value); //it is not insert + println!("Just a comment"); + } + + if set.contains(&value) { + println!("value is already in set"); + } else { + set.insert(value); + } +} + +fn simply_true() -> bool { + true +} diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr new file mode 100644 index 000000000000..507e20964fc2 --- /dev/null +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr @@ -0,0 +1,61 @@ +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:18:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::set-contains-or-insert` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]` + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:23:12 + | +LL | if set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:28:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:32:14 + | +LL | if !!set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:37:15 + | +LL | if (&set).contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:42:13 + | +LL | if !set.contains(borrow_value) { + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | set.insert(*borrow_value); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:47:20 + | +LL | if !borrow_set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | borrow_set.insert(value); + | ^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 8ee15440ccf0..0db6fbfb7be9 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -801,4 +801,30 @@ fn should_not_trigger_lint_with_explicit_drop() { } } +fn should_trigger_lint_in_if_let() { + let mutex = Mutex::new(vec![1]); + + if let Some(val) = mutex.lock().unwrap().first().copied() { + //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } + + // Should not trigger lint without the final `copied()`, because we actually hold a reference + // (i.e., the `val`) to the locked data. + if let Some(val) = mutex.lock().unwrap().first() { + println!("{}", val); + }; +} + +fn should_trigger_lint_in_while_let() { + let mutex = Mutex::new(vec![1]); + + while let Some(val) = mutex.lock().unwrap().pop() { + //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 4a483e79d8ad..c0c93cd10c02 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -541,5 +541,32 @@ LL ~ let value = mutex.lock().unwrap()[0]; LL ~ for val in [value, 2] { | -error: aborting due to 27 previous errors +error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:807:24 + | +LL | if let Some(val) = mutex.lock().unwrap().first().copied() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().first().copied(); +LL ~ if let Some(val) = value { + | + +error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:823:27 + | +LL | while let Some(val) = mutex.lock().unwrap().pop() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior + +error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index 11761c6c90e3..006f123cbcdf 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -113,4 +113,16 @@ fn main() { 'label: { break 'label }; + let () = const { + [42, 55][get_usize()]; + }; +} + +const _: () = { + [42, 55][get_usize()]; +}; + +const fn foo() { + assert!([42, 55].len() > get_usize()); + //~^ ERROR: unnecessary operation } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index de0081289ac3..b4067c740741 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -117,4 +117,16 @@ fn main() { 'label: { break 'label }; + let () = const { + [42, 55][get_usize()]; + }; +} + +const _: () = { + [42, 55][get_usize()]; +}; + +const fn foo() { + [42, 55][get_usize()]; + //~^ ERROR: unnecessary operation } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index 27be5e6f4b92..036a9a44bbad 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -119,5 +119,11 @@ LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` -error: aborting due to 19 previous errors +error: unnecessary operation + --> tests/ui/unnecessary_operation.rs:130:5 + | +LL | [42, 55][get_usize()]; + | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` + +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index 1afa5ab54c46..fdcac8fb08dc 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x")); require_str(&String::from("x")); require_slice(&[String::from("x")]); + + let slice = [0u8; 1024]; + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs index aa88dde43bf6..10a9727a9a79 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x").to_path_buf()); require_str(&String::from("x").to_string()); require_slice(&[String::from("x")].to_owned()); + + let slice = [0u8; 1024]; + let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr index 2829f3cd6e98..511b4ae119f8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr @@ -477,8 +477,44 @@ error: unnecessary use of `to_owned` LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:162:26 + | +LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); +LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:163:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:164:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + | + error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:202:14 + --> tests/ui/unnecessary_to_owned.rs:221:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,64 +530,64 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:225:14 + --> tests/ui/unnecessary_to_owned.rs:244:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:230:14 + --> tests/ui/unnecessary_to_owned.rs:249:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:278:24 + --> tests/ui/unnecessary_to_owned.rs:297:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:387:12 + --> tests/ui/unnecessary_to_owned.rs:406:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:530:37 + --> tests/ui/unnecessary_to_owned.rs:549:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:540:18 + --> tests/ui/unnecessary_to_owned.rs:559:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:544:14 + --> tests/ui/unnecessary_to_owned.rs:563:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:545:14 + --> tests/ui/unnecessary_to_owned.rs:564:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:550:14 + --> tests/ui/unnecessary_to_owned.rs:569:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:551:14 + --> tests/ui/unnecessary_to_owned.rs:570:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 85 previous errors +error: aborting due to 88 previous errors diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 6fdd728b9b72..46890ee9213f 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -204,6 +204,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -212,6 +213,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -219,6 +221,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs index 20e06d4b3664..1a5586cbb88d 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports.rs @@ -205,6 +205,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -213,6 +214,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -220,6 +222,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index 0c69d5262c26..8e88f216394d 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:236:17 + --> tests/ui/wildcard_imports.rs:239:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:244:13 + --> tests/ui/wildcard_imports.rs:247:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:253:17 + --> tests/ui/wildcard_imports.rs:256:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:262:13 + --> tests/ui/wildcard_imports.rs:265:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:270:13 + --> tests/ui/wildcard_imports.rs:273:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs index 18ebc0f51274..606ff080e774 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs @@ -199,6 +199,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -207,6 +208,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -214,6 +216,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7479be90797e..7f5d4f4b4169 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -991,13 +991,19 @@ impl Config { } fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> { - if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match { - let (regex, replacement) = parse_normalize_rule(line) - .unwrap_or_else(|| panic!("couldn't parse custom normalization rule: `{line}`")); - Some((regex, replacement)) - } else { - None + let parsed = parse_cfg_name_directive(self, line, prefix); + if parsed.outcome != MatchOutcome::Match { + return None; } + let name = parsed.name.expect("successful match always has a name"); + + let Some((regex, replacement)) = parse_normalize_rule(line) else { + panic!( + "couldn't parse custom normalization rule: `{line}`\n\ + help: expected syntax is: `{prefix}-{name}: \"REGEX\" -> \"REPLACEMENT\"`" + ); + }; + Some((regex, replacement)) } fn parse_name_directive(&self, line: &str, directive: &str) -> bool { diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index cd011dce7844..ea1e573384b8 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -298,6 +298,7 @@ impl<'a> Validator<'a> { generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } GenericBound::Outlives(_) => {} + GenericBound::Use(_) => {} } } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index f246d71d499b..9eaa234bfaf3 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -37,7 +37,7 @@ impl<'a> LintExtractor<'a> { .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; let new_contents = contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?); - // Delete the output because rustbuild uses hard links in its copies. + // Delete the output because bootstrap uses hard links in its copies. let _ = fs::remove_file(&groups_path); fs::write(&groups_path, new_contents) .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 72d6a495e7e7..48e2dd098769 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -532,7 +532,7 @@ impl<'a> LintExtractor<'a> { } add_rename_redirect(level, &mut result); let out_path = self.out_path.join("listing").join(level.doc_filename()); - // Delete the output because rustbuild uses hard links in its copies. + // Delete the output because bootstrap uses hard links in its copies. let _ = fs::remove_file(&out_path); fs::write(&out_path, result) .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 8d48b9c8ad14..3743446e2764 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -104,9 +104,17 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { miri_for_host() ) }); - let host = &rustc_version.host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(host); + let mut targets = get_arg_flag_values("--target").collect::>(); + // If `targets` is empty, we need to add a `--target $HOST` flag ourselves, and also ensure + // that the host target is indeed setup. + let target_flag = if targets.is_empty() { + let host = &rustc_version.host; + targets.push(host.clone()); + Some(host) + } else { + // We don't need to add a `--target` flag, we just forward the user's flags. + None + }; // If cleaning the target directory & sysroot cache, // delete them then exit. There is no reason to setup a new @@ -118,8 +126,11 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { return; } - // We always setup. - let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose, quiet); + for target in &targets { + // We always setup. + setup(&subcommand, target.as_str(), &rustc_version, verbose, quiet); + } + let miri_sysroot = get_sysroot_dir(); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -155,10 +166,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // No target given. Explicitly pick the host. + if let Some(target_flag) = target_flag { cmd.arg("--target"); - cmd.arg(host); + cmd.arg(target_flag); } // Set ourselves as runner for al binaries invoked by cargo. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 67985f9b7d6e..5e75638f4670 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -41,9 +41,11 @@ function run_tests { if [ -n "${TEST_TARGET-}" ]; then begingroup "Testing foreign architecture $TEST_TARGET" TARGET_FLAG="--target $TEST_TARGET" + MULTI_TARGET_FLAG="" else begingroup "Testing host architecture" TARGET_FLAG="" + MULTI_TARGET_FLAG="--multi-target" fi ## ui test suite @@ -93,7 +95,7 @@ function run_tests { echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml fi # Run the actual test - time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG + time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG $MULTI_TARGET_FLAG # Clean up unset RUSTC MIRI rm -rf .cargo diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5a35166769e8..e90d3732ca57 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -66b4f0021bfb11a8c20d084c99a40f4a78ce1d38 +99b7134389e9766462601a2fc4013840b9d31745 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9d8e44ce409e..9f3fa075f38f 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -592,6 +592,9 @@ fn main() { let num_cpus = param .parse::() .unwrap_or_else(|err| show_error!("-Zmiri-num-cpus requires a `u32`: {}", err)); + if !(1..=miri::MAX_CPUS).contains(&usize::try_from(num_cpus).unwrap()) { + show_error!("-Zmiri-num-cpus must be in the range 1..={}", miri::MAX_CPUS); + } miri_config.num_cpus = num_cpus; } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") { let page_size = param.parse::().unwrap_or_else(|err| { diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index f65f49a75ddd..774b36919fe3 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -136,8 +136,16 @@ impl StackCache { impl PartialEq for Stack { fn eq(&self, other: &Self) -> bool { - // All the semantics of Stack are in self.borrows, everything else is caching - self.borrows == other.borrows + let Stack { + borrows, + unknown_bottom, + // The cache is ignored for comparison. + #[cfg(feature = "stack-cache")] + cache: _, + #[cfg(feature = "stack-cache")] + unique_range: _, + } = self; + *borrows == other.borrows && *unknown_bottom == other.unknown_bottom } } diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs new file mode 100644 index 000000000000..8df26d718bf6 --- /dev/null +++ b/src/tools/miri/src/concurrency/cpu_affinity.rs @@ -0,0 +1,90 @@ +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::Endian; + +use crate::*; + +/// The maximum number of CPUs supported by miri. +/// +/// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number +/// of CPUs that a `cpu_set_t` can contain. +/// +/// Real machines can have more CPUs than this number, and there exist APIs to set their affinity, +/// but this is not currently supported by miri. +pub const MAX_CPUS: usize = 1024; + +/// A thread's CPU affinity mask determines the set of CPUs on which it is eligible to run. +// the actual representation depends on the target's endianness and pointer width. +// See CpuAffinityMask::set for details +#[derive(Clone)] +pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]); + +impl CpuAffinityMask { + pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8; + + pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self { + let mut this = Self([0; Self::CPU_MASK_BYTES]); + + // the default affinity mask includes only the available CPUs + for i in 0..cpu_count as usize { + this.set(cx, i); + } + + this + } + + pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 { + // The actual representation of the CpuAffinityMask is [c_ulong; _]. + let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]); + ulong.size.bytes() + } + + fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) { + // we silently ignore CPUs that are out of bounds. This matches the behavior of + // `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs. + if cpu >= MAX_CPUS { + return; + } + + // The actual representation of the CpuAffinityMask is [c_ulong; _]. + // Within the array elements, we need to use the endianness of the target. + let target = &cx.tcx().sess.target; + match Self::chunk_size(cx) { + 4 => { + let start = cpu / 32 * 4; // first byte of the correct u32 + let chunk = self.0[start..].first_chunk_mut::<4>().unwrap(); + let offset = cpu % 32; + *chunk = match target.options.endian { + Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), + Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + }; + } + 8 => { + let start = cpu / 64 * 8; // first byte of the correct u64 + let chunk = self.0[start..].first_chunk_mut::<8>().unwrap(); + let offset = cpu % 64; + *chunk = match target.options.endian { + Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), + Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + }; + } + other => bug!("chunk size not supported: {other}"), + }; + } + + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + pub fn from_array<'tcx>( + cx: &impl LayoutOf<'tcx>, + cpu_count: u32, + bytes: [u8; Self::CPU_MASK_BYTES], + ) -> Option { + // mask by what CPUs are actually available + let default = Self::new(cx, cpu_count); + let masked = std::array::from_fn(|i| bytes[i] & default.0[i]); + + // at least one thread must be set for the input to be valid + masked.iter().any(|b| *b != 0).then_some(Self(masked)) + } +} diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 822d173ac06a..17789fe9f87f 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,3 +1,4 @@ +pub mod cpu_affinity; pub mod data_race; pub mod init_once; mod range_object_map; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 91865a2192cf..d0c9a4600e85 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -269,7 +269,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); if this.mutex_is_locked(mutex) { assert_ne!(this.mutex_get_owner(mutex), this.active_thread()); - this.mutex_enqueue_and_block(mutex, retval, dest); + this.mutex_enqueue_and_block(mutex, Some((retval, dest))); } else { // We can have it right now! this.mutex_lock(mutex); @@ -390,9 +390,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Put the thread into the queue waiting for the mutex. - /// Once the Mutex becomes available, `retval` will be written to `dest`. + /// + /// Once the Mutex becomes available and if it exists, `retval_dest.0` will + /// be written to `retval_dest.1`. #[inline] - fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) { + fn mutex_enqueue_and_block( + &mut self, + id: MutexId, + retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, + ) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); let thread = this.active_thread(); @@ -403,13 +409,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: MutexId, - retval: Scalar, - dest: MPlaceTy<'tcx>, + retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, } @unblock = |this| { assert!(!this.mutex_is_locked(id)); this.mutex_lock(id); - this.write_scalar(retval, &dest)?; + + if let Some((retval, dest)) = retval_dest { + this.write_scalar(retval, &dest)?; + } + Ok(()) } ), diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 718daf93ea00..a53dd7eac1e9 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -936,6 +936,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // After this all accesses will be treated as occurring in the new thread. let old_thread_id = this.machine.threads.set_active_thread_id(new_thread_id); + // The child inherits its parent's cpu affinity. + if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&old_thread_id).cloned() { + this.machine.thread_cpu_affinity.insert(new_thread_id, cpuset); + } + // Perform the function pointer load in the new thread frame. let instance = this.get_ptr_fn(start_routine)?.as_instance()?; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 9142b8b5fdbc..2184a4426c8d 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>( })?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS); + let sentinel = + helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS); if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) { tcx.dcx().fatal( "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \ diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 590e8984e990..ba094c988e5a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -18,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::mir; +use rustc_middle::ty::layout::MaybeResult; use rustc_middle::ty::{ self, layout::{LayoutOf, TyAndLayout}, @@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) None } +/// Gets an instance for a path; fails gracefully if the path does not exist. +pub fn try_resolve_path<'tcx>( + tcx: TyCtxt<'tcx>, + path: &[&str], + namespace: Namespace, +) -> Option> { + let did = try_resolve_did(tcx, path, Some(namespace))?; + Some(ty::Instance::mono(tcx, did)) +} + +/// Gets an instance for a path. +#[track_caller] +pub fn resolve_path<'tcx>( + tcx: TyCtxt<'tcx>, + path: &[&str], + namespace: Namespace, +) -> ty::Instance<'tcx> { + try_resolve_path(tcx, path, namespace) + .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}")) +} + +/// Gets the layout of a type at a path. +#[track_caller] +pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> { + let ty = + resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all()); + cx.layout_of(ty).to_result().ok().unwrap() +} + /// Call `f` for each exported symbol. pub fn iter_exported_symbols<'tcx>( tcx: TyCtxt<'tcx>, @@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some() } - /// Gets an instance for a path; fails gracefully if the path does not exist. - fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option> { - let tcx = self.eval_context_ref().tcx.tcx; - let did = try_resolve_did(tcx, path, Some(namespace))?; - Some(ty::Instance::mono(tcx, did)) - } - - /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> { - self.try_resolve_path(path, namespace) - .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}")) - } - /// Evaluates the scalar at the specified path. fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> { let this = self.eval_context_ref(); - let instance = this.resolve_path(path, Namespace::ValueNS); + let instance = resolve_path(*this.tcx, path, Namespace::ValueNS); // We don't give a span -- this isn't actually used directly by the program anyway. let const_val = this.eval_global(instance).unwrap_or_else(|err| { panic!("failed to evaluate required Rust item: {path:?}\n{err:?}") @@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "`libc` crate is not reliably available on Windows targets; Miri should not use it there" ); } - let ty = this - .resolve_path(&["libc", name], Namespace::TypeNS) - .ty(*this.tcx, ty::ParamEnv::reveal_all()); - this.layout_of(ty).unwrap() + path_ty_layout(this, &["libc", name]) } /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> { let this = self.eval_context_ref(); - let ty = this - .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS) - .ty(*this.tcx, ty::ParamEnv::reveal_all()); - this.layout_of(ty).unwrap() + path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name]) } /// Project to the given *named* field (which must be a struct or union type). diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 313eac363372..9cd776c93710 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -392,10 +392,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { bug!("float_finite: non-float input type {}", x.layout.ty) }; Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(), FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(), FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => x.to_scalar().to_f128()?.is_finite(), }) }; match (float_finite(&a)?, float_finite(&b)?) { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 8da00861f905..7fb68d782f11 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -129,6 +129,7 @@ pub use crate::borrow_tracker::{ }; pub use crate::clock::{Clock, Instant}; pub use crate::concurrency::{ + cpu_affinity::MAX_CPUS, data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _}, init_once::{EvalContextExt as _, InitOnceId}, sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects}, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 714d97823f4f..adb845935616 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -30,6 +30,7 @@ use rustc_target::spec::abi::Abi; use crate::{ concurrency::{ + cpu_affinity::{self, CpuAffinityMask}, data_race::{self, NaReadType, NaWriteType}, weak_memory, }, @@ -471,6 +472,12 @@ pub struct MiriMachine<'tcx> { /// The set of threads. pub(crate) threads: ThreadManager<'tcx>, + + /// Stores which thread is eligible to run on which CPUs. + /// This has no effect at all, it is just tracked to produce the correct result + /// in `sched_getaffinity` + pub(crate) thread_cpu_affinity: FxHashMap, + /// The state of the primitive synchronization objects. pub(crate) sync: SynchronizationObjects, @@ -627,6 +634,18 @@ impl<'tcx> MiriMachine<'tcx> { let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 }; let stack_size = if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 }; + assert!( + usize::try_from(config.num_cpus).unwrap() <= cpu_affinity::MAX_CPUS, + "miri only supports up to {} CPUs, but {} were configured", + cpu_affinity::MAX_CPUS, + config.num_cpus + ); + let threads = ThreadManager::default(); + let mut thread_cpu_affinity = FxHashMap::default(); + if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") { + thread_cpu_affinity + .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus)); + } MiriMachine { tcx, borrow_tracker, @@ -644,7 +663,8 @@ impl<'tcx> MiriMachine<'tcx> { fds: shims::FdTable::new(config.mute_stdout_stderr), dirs: Default::default(), layouts, - threads: ThreadManager::default(), + threads, + thread_cpu_affinity, sync: SynchronizationObjects::default(), static_roots: Vec::new(), profiler, @@ -765,6 +785,7 @@ impl VisitProvenance for MiriMachine<'_> { #[rustfmt::skip] let MiriMachine { threads, + thread_cpu_affinity: _, sync: _, tls, env_vars, diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index af980ca48197..8edd80744ddc 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -30,6 +30,17 @@ impl VisitProvenance for Option { } } +impl VisitProvenance for (A, B) +where + A: VisitProvenance, + B: VisitProvenance, +{ + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + self.0.visit_provenance(visit); + self.1.visit_provenance(visit); + } +} + impl VisitProvenance for std::cell::RefCell { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { self.borrow().visit_provenance(visit) diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index c91386fa877f..870744687895 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -36,9 +36,9 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single per thread destructor of the thread local storage (that's how - /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap, Scalar)>, + /// On macOS, each thread holds a list of destructor functions with their + /// respective data arguments. + macos_thread_dtors: BTreeMap, Scalar)>>, } impl<'tcx> Default for TlsData<'tcx> { @@ -119,26 +119,15 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set the thread wide destructor of the thread local storage for the given - /// thread. This function is used to implement `_tlv_atexit` shim on MacOS. - /// - /// Thread wide dtors are available only on MacOS. There is one destructor - /// per thread as can be guessed from the following comment in the - /// [`_tlv_atexit` - /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): - /// - /// NOTE: this does not need locks because it only operates on current thread data - pub fn set_macos_thread_dtor( + /// Add a thread local storage destructor for the given thread. This function + /// is used to implement the `_tlv_atexit` shim on MacOS. + pub fn add_macos_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar, ) -> InterpResult<'tcx> { - if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!( - "setting more than one thread local storage destructor for the same thread is not supported" - ); - } + self.macos_thread_dtors.entry(thread).or_default().push((dtor, data)); Ok(()) } @@ -202,6 +191,10 @@ impl<'tcx> TlsData<'tcx> { for TlsEntry { data, .. } in self.keys.values_mut() { data.remove(&thread_id); } + + if let Some(dtors) = self.macos_thread_dtors.remove(&thread_id) { + assert!(dtors.is_empty(), "the destructors should have already been run"); + } } } @@ -212,7 +205,7 @@ impl VisitProvenance for TlsData<'_> { for scalar in keys.values().flat_map(|v| v.data.values()) { scalar.visit_provenance(visit); } - for (_, scalar) in macos_thread_dtors.values() { + for (_, scalar) in macos_thread_dtors.values().flatten() { scalar.visit_provenance(visit); } } @@ -225,6 +218,7 @@ pub struct TlsDtorsState<'tcx>(TlsDtorsStatePriv<'tcx>); enum TlsDtorsStatePriv<'tcx> { #[default] Init, + MacOsDtors, PthreadDtors(RunningDtorState), /// For Windows Dtors, we store the list of functions that we still have to call. /// These are functions from the magic `.CRT$XLB` linker section. @@ -243,11 +237,10 @@ impl<'tcx> TlsDtorsState<'tcx> { Init => { match this.tcx.sess.target.os.as_ref() { "macos" => { - // The macOS thread wide destructor runs "before any TLS slots get - // freed", so do that first. - this.schedule_macos_tls_dtor()?; - // When that destructor is done, go on with the pthread dtors. - break 'new_state PthreadDtors(Default::default()); + // macOS has a _tlv_atexit function that allows + // registering destructors without associated keys. + // These are run first. + break 'new_state MacOsDtors; } _ if this.target_os_is_unix() => { // All other Unixes directly jump to running the pthread dtors. @@ -266,6 +259,14 @@ impl<'tcx> TlsDtorsState<'tcx> { } } } + MacOsDtors => { + match this.schedule_macos_tls_dtor()? { + Poll::Pending => return Ok(Poll::Pending), + // After all macOS destructors are run, the system switches + // to destroying the pthread destructors. + Poll::Ready(()) => break 'new_state PthreadDtors(Default::default()), + } + } PthreadDtors(state) => { match this.schedule_next_pthread_tls_dtor(state)? { Poll::Pending => return Ok(Poll::Pending), // just keep going @@ -328,12 +329,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - /// Schedule the MacOS thread destructor of the thread local storage to be - /// executed. - fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { + /// Schedule the macOS thread local storage destructors to be executed. + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); let thread_id = this.active_thread(); - if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { + // macOS keeps track of TLS destructors in a stack. If a destructor + // registers another destructor, it will be run next. + // See https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/DyldRuntimeState.cpp#L2277 + let dtor = this.machine.tls.macos_thread_dtors.get_mut(&thread_id).and_then(Vec::pop); + if let Some((instance, data)) = dtor { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); this.call_function( @@ -343,8 +347,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None, StackPopCleanup::Root { cleanup: true }, )?; + + return Ok(Poll::Pending); } - Ok(()) + + Ok(Poll::Ready(())) } /// Schedule a pthread TLS destructor. Returns `true` if found diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 7f6a09781035..8fb046b5e64c 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -419,7 +419,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match result { Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.write_bytes_ptr(buf, bytes)?; + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + this.write_bytes_ptr( + buf, + bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(), + )?; Ok(read_bytes) } Err(e) => { diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 2421f9244f36..3a18d6220333 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -3,8 +3,10 @@ use std::str; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use crate::concurrency::cpu_affinity::CpuAffinityMask; use crate::shims::alloc::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -571,6 +573,99 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "sched_getaffinity" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { + throw_unsup_format!( + "`sched_getaffinity` is not supported on {}", + this.tcx.sess.target.os + ); + } + + let [pid, cpusetsize, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let pid = this.read_scalar(pid)?.to_u32()?; + let cpusetsize = this.read_target_usize(cpusetsize)?; + let mask = this.read_pointer(mask)?; + + // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid + let thread_id = match pid { + 0 => this.active_thread(), + _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"), + }; + + // The mask is stored in chunks, and the size must be a whole number of chunks. + let chunk_size = CpuAffinityMask::chunk_size(this); + + if this.ptr_is_null(mask)? { + let einval = this.eval_libc("EFAULT"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 { + // we only copy whole chunks of size_of::() + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { + let cpuset = cpuset.clone(); + // we only copy whole chunks of size_of::() + let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap()); + this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?; + this.write_scalar(Scalar::from_i32(0), dest)?; + } else { + // The thread whose ID is pid could not be found + let einval = this.eval_libc("ESRCH"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } + } + "sched_setaffinity" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { + throw_unsup_format!( + "`sched_setaffinity` is not supported on {}", + this.tcx.sess.target.os + ); + } + + let [pid, cpusetsize, mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let pid = this.read_scalar(pid)?.to_u32()?; + let cpusetsize = this.read_target_usize(cpusetsize)?; + let mask = this.read_pointer(mask)?; + + // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid + let thread_id = match pid { + 0 => this.active_thread(), + _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"), + }; + + if this.ptr_is_null(mask)? { + let einval = this.eval_libc("EFAULT"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } else { + // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. + // Any unspecified bytes are treated as zero here (none of the CPUs are configured). + // This is not exactly documented, so we assume that this is the behavior in practice. + let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; + // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES` + let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] = + std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0)); + match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) { + Some(cpuset) => { + this.machine.thread_cpu_affinity.insert(thread_id, cpuset); + this.write_scalar(Scalar::from_i32(0), dest)?; + } + None => { + // The intersection between the mask and the available CPUs was empty. + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + } + } + } + } // Miscellaneous "isatty" => { diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e31d43d9190a..95bee38cd783 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -178,19 +178,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?; } - "sched_getaffinity" => { - // This shim isn't useful, aside from the fact that it makes `num_cpus` - // fall back to `sysconf` where it will successfully determine the number of CPUs. - let [pid, cpusetsize, mask] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(pid)?.to_i32()?; - this.read_target_usize(cpusetsize)?; - this.deref_pointer_as(mask, this.libc_ty_layout("cpu_set_t"))?; - // FIXME: we just return an error. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; - } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 25002f0a611c..47b887dec947 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -1,6 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use super::sync::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -132,7 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; let active_thread = this.active_thread(); - this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; + this.machine.tls.add_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information @@ -174,6 +175,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + "os_unfair_lock_lock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_lock(lock_op)?; + } + "os_unfair_lock_trylock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_trylock(lock_op, dest)?; + } + "os_unfair_lock_unlock" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_unlock(lock_op)?; + } + "os_unfair_lock_assert_owner" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_assert_owner(lock_op)?; + } + "os_unfair_lock_assert_not_owner" => { + let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.os_unfair_lock_assert_not_owner(lock_op)?; + } + _ => return Ok(EmulateItemResult::NotSupported), }; diff --git a/src/tools/miri/src/shims/unix/macos/mod.rs b/src/tools/miri/src/shims/unix/macos/mod.rs index 09c6507b24f8..50fb2b9d3287 100644 --- a/src/tools/miri/src/shims/unix/macos/mod.rs +++ b/src/tools/miri/src/shims/unix/macos/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod sync; diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs new file mode 100644 index 000000000000..5e5fccb587b4 --- /dev/null +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -0,0 +1,107 @@ +//! Contains macOS-specific synchronization functions. +//! +//! For `os_unfair_lock`, see the documentation +//! +//! and in case of underspecification its implementation +//! . +//! +//! Note that we don't emulate every edge-case behaviour of the locks. Notably, +//! we don't abort when locking a lock owned by a thread that has already exited +//! and we do not detect copying of the lock, but macOS doesn't guarantee anything +//! in that case either. + +use crate::*; + +impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} +trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> { + let this = self.eval_context_mut(); + // os_unfair_lock holds a 32-bit value, is initialized with zero and + // must be assumed to be opaque. Therefore, we can just store our + // internal mutex ID in the structure without anyone noticing. + this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0) + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) { + if this.mutex_get_owner(id) == this.active_thread() { + // Matching the current macOS implementation: abort on reentrant locking. + throw_machine_stop!(TerminationInfo::Abort( + "attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned() + )); + } + + this.mutex_enqueue_and_block(id, None); + } else { + this.mutex_lock(id); + } + + Ok(()) + } + + fn os_unfair_lock_trylock( + &mut self, + lock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) { + // Contrary to the blocking lock function, this does not check for + // reentrancy. + this.write_scalar(Scalar::from_bool(false), dest)?; + } else { + this.mutex_lock(id); + this.write_scalar(Scalar::from_bool(true), dest)?; + } + + Ok(()) + } + + fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_unlock(id)?.is_none() { + // Matching the current macOS implementation: abort. + throw_machine_stop!(TerminationInfo::Abort( + "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned() + )); + } + + Ok(()) + } + + fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() { + throw_machine_stop!(TerminationInfo::Abort( + "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned() + )); + } + + Ok(()) + } + + fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let id = this.os_unfair_lock_getid(lock_op)?; + if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() { + throw_machine_stop!(TerminationInfo::Abort( + "called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned() + )); + } + + Ok(()) + } +} diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index be6732b1b67e..e8653117ae94 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -473,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ret = if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != this.active_thread() { - this.mutex_enqueue_and_block(id, Scalar::from_i32(0), dest.clone()); + this.mutex_enqueue_and_block(id, Some((Scalar::from_i32(0), dest.clone()))); return Ok(()); } else { // Trying to acquire the same mutex again. diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index d855c333a756..5b77092979d3 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -22,12 +22,17 @@ def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) -def cargo_miri(cmd, quiet = True): +def cargo_miri(cmd, quiet = True, targets = None): args = ["cargo", "miri", cmd] + CARGO_EXTRA_FLAGS if quiet: args += ["-q"] - if ARGS.target: + + if targets is not None: + for target in targets: + args.extend(("--target", target)) + elif ARGS.target is not None: args += ["--target", ARGS.target] + return args def normalize_stdout(str): @@ -186,10 +191,21 @@ def test_cargo_miri_test(): default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) + if ARGS.multi_target: + test_cargo_miri_multi_target() + + +def test_cargo_miri_multi_target(): + test("`cargo miri test` (multiple targets)", + cargo_miri("test", targets = ["aarch64-unknown-linux-gnu", "s390x-unknown-linux-gnu"]), + "test.multiple_targets.stdout.ref", "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, + ) args_parser = argparse.ArgumentParser(description='`cargo miri` testing') args_parser.add_argument('--target', help='the target to test') args_parser.add_argument('--bless', help='bless the reference files', action='store_true') +args_parser.add_argument('--multi-target', help='run tests related to multiple targets', action='store_true') ARGS = args_parser.parse_args() os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref new file mode 100644 index 000000000000..567c5db07d06 --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -0,0 +1,22 @@ + +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + +imported main +imported main + +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs new file mode 100644 index 000000000000..d6604f371394 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs @@ -0,0 +1,13 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_assert_not_owner(lock.get()); + //~^ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr new file mode 100644 index 000000000000..7e890681c436 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + --> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC + | +LL | libc::os_unfair_lock_assert_not_owner(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.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-dep/concurrency/apple_os_unfair_lock_assert_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs new file mode 100644 index 000000000000..ddd8b572eaf0 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs @@ -0,0 +1,12 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_assert_owner(lock.get()); + //~^ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr new file mode 100644 index 000000000000..3724f7996fb8 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + --> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC + | +LL | libc::os_unfair_lock_assert_owner(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.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-dep/concurrency/apple_os_unfair_lock_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs new file mode 100644 index 000000000000..eb98adeba073 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs @@ -0,0 +1,13 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_lock(lock.get()); + //~^ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr new file mode 100644 index 000000000000..644462a1b05f --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread + --> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC + | +LL | libc::os_unfair_lock_lock(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.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-dep/concurrency/apple_os_unfair_lock_unowned.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs new file mode 100644 index 000000000000..aed467552ab9 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs @@ -0,0 +1,12 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_unlock(lock.get()); + //~^ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr new file mode 100644 index 000000000000..6a8d12fa8076 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread + --> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC + | +LL | libc::os_unfair_lock_unlock(lock.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread + | + = note: BACKTRACE: + = note: inside `main` at $DIR/apple_os_unfair_lock_unowned.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-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs new file mode 100644 index 000000000000..c41d1d18018c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs @@ -0,0 +1,17 @@ +//@ignore-target-windows: only very limited libc on Windows +//@ignore-target-apple: `sched_setaffinity` is not supported on macOS +//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 + +fn main() { + use libc::{cpu_set_t, sched_setaffinity}; + + use std::mem::size_of; + + // If pid is zero, then the calling thread is used. + const PID: i32 = 0; + + let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; //~ ERROR: memory access failed + assert_eq!(err, 0); +} diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr new file mode 100644 index 000000000000..c01f15800fac --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds + --> $DIR/affinity.rs:LL:CC + | +LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds + | + = 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 +help: ALLOC was allocated here: + --> $DIR/affinity.rs:LL:CC + | +LL | let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + | ^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/affinity.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-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs new file mode 100644 index 000000000000..98ef454c88b3 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs @@ -0,0 +1,27 @@ +//! We test that if we requested to read 4 bytes, but actually read 3 bytes, +//! then 3 bytes (not 4) will be initialized. +//@ignore-target-windows: no file system support on Windows +//@compile-flags: -Zmiri-disable-isolation + +use std::ffi::CString; +use std::fs::remove_file; +use std::mem::MaybeUninit; + +#[path = "../../utils/mod.rs"] +mod utils; + +fn main() { + let path = + utils::prepare_with_content("fail-libc-read-and-uninit-premature-eof.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit(); + // Read 4 bytes from a 3-byte file. + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 4), 3); + buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr new file mode 100644 index 000000000000..e4c7aba07e34 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + --> $DIR/libc-read-and-uninit-premature-eof.rs:LL:CC + | +LL | ... buf.assume_init(); + | ^^^^^^^^^^^^^^^^^ constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer + | + = 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 $DIR/libc-read-and-uninit-premature-eof.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/alloc/global_system_mixup.rs b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs index 2e88e5644e44..19c62913b4c6 100644 --- a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs +++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs @@ -4,7 +4,7 @@ //@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" +//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^}]*\};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs new file mode 100644 index 000000000000..023bce1616b8 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs @@ -0,0 +1,20 @@ +#![feature(raw_ref_op)] +#![feature(strict_provenance)] +use std::ptr; + +fn direct_raw(x: *const (i32, i32)) -> *const i32 { + unsafe { &raw const (*x).0 } +} + +// Ensure that if a raw pointer is created via an intermediate +// reference, we catch that. (Just in case someone decides to +// desugar this differenly or so.) +fn via_ref(x: *const (i32, i32)) -> *const i32 { + unsafe { &(*x).0 as *const i32 } //~ERROR: dangling pointer +} + +fn main() { + let ptr = ptr::without_provenance(0x10); + direct_raw(ptr); // this is fine + via_ref(ptr); // this is not +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr new file mode 100644 index 000000000000..37f2bb395576 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) + --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + | +LL | unsafe { &(*x).0 as *const i32 } + | ^^^^^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) + | + = 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 `via_ref` at $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC +note: inside `main` + --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC + | +LL | via_ref(ptr); // this is not + | ^^^^^^^^^^^^ + +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/pass-dep/concurrency/apple-os-unfair-lock.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs new file mode 100644 index 000000000000..c2b9c37bbfb2 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs @@ -0,0 +1,25 @@ +//@ only-target-darwin + +use std::cell::UnsafeCell; + +fn main() { + let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); + + unsafe { + libc::os_unfair_lock_lock(lock.get()); + libc::os_unfair_lock_assert_owner(lock.get()); + assert!(!libc::os_unfair_lock_trylock(lock.get())); + libc::os_unfair_lock_unlock(lock.get()); + + libc::os_unfair_lock_assert_not_owner(lock.get()); + } + + // `os_unfair_lock`s can be moved and leaked. + // In the real implementation, even moving it while locked is possible + // (and "forks" the lock, i.e. old and new location have independent wait queues); + // Miri behavior differs here and anyway none of this is documented. + let lock = lock; + let locked = unsafe { libc::os_unfair_lock_trylock(lock.get()) }; + assert!(locked); + let _lock = lock; +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs new file mode 100644 index 000000000000..0e482ab26010 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -0,0 +1,218 @@ +//@ignore-target-windows: only very limited libc on Windows +//@ignore-target-apple: `sched_{g, s}etaffinity` are not supported on macOS +//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 +#![feature(io_error_more)] +#![feature(pointer_is_aligned_to)] +#![feature(strict_provenance)] + +use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity}; +use std::mem::{size_of, size_of_val}; + +// If pid is zero, then the calling thread is used. +const PID: i32 = 0; + +fn null_pointers() { + let err = unsafe { sched_getaffinity(PID, size_of::(), std::ptr::null_mut()) }; + assert_eq!(err, -1); + + let err = unsafe { sched_setaffinity(PID, size_of::(), std::ptr::null()) }; + assert_eq!(err, -1); +} + +fn configure_no_cpus() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // configuring no CPUs will fail + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + + // configuring no (physically available) CPUs will fail + unsafe { libc::CPU_SET(cpu_count, &mut cpuset) }; + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); +} + +fn configure_unavailable_cpu() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + // Safety: valid value for this type + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // by default, only available CPUs are configured + for i in 0..cpu_count { + assert!(unsafe { libc::CPU_ISSET(i, &cpuset) }); + } + assert!(unsafe { !libc::CPU_ISSET(cpu_count, &cpuset) }); + + // configure CPU that we don't have + unsafe { libc::CPU_SET(cpu_count, &mut cpuset) }; + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // the CPU is not set because it is not available + assert!(!unsafe { libc::CPU_ISSET(cpu_count, &cpuset) }); +} + +fn large_set() { + // rust's libc does not currently implement dynamic cpu set allocation + // and related functions like `CPU_ZERO_S`. So we have to be creative + + // i.e. this has 2048 bits, twice the standard number + let mut cpuset = [u64::MAX; 32]; + + let err = unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) }; + assert_eq!(err, 0); + + let err = unsafe { sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) }; + assert_eq!(err, 0); +} + +fn get_small_cpu_mask() { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // should be 4 on 32-bit systems and 8 otherwise for systems that implement sched_getaffinity + let step = size_of::(); + + for i in (0..=2).map(|x| x * step) { + if i == 0 { + // 0 always fails + let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) }; + assert_eq!(err, -1, "fail for {}", i); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + } else { + // other whole multiples of the size of c_ulong works + let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) }; + assert_eq!(err, 0, "fail for {i}"); + } + + // anything else returns an error + for j in 1..step { + let err = unsafe { sched_getaffinity(PID, i + j, &mut cpuset) }; + assert_eq!(err, -1, "success for {}", i + j); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + } + } +} + +fn set_small_cpu_mask() { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // setting a mask of size 0 is invalid + let err = unsafe { sched_setaffinity(PID, 0, &cpuset) }; + assert_eq!(err, -1); + assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); + + // on LE systems, any other number of bytes (at least up to `size_of()`) will work. + // on BE systems the CPUs 0..8 are stored in the right-most byte of the first chunk. If that + // byte is not included, no valid CPUs are configured. We skip those cases. + let cpu_zero_included_length = + if cfg!(target_endian = "little") { 1 } else { core::mem::size_of::() }; + + for i in cpu_zero_included_length..24 { + let err = unsafe { sched_setaffinity(PID, i, &cpuset) }; + assert_eq!(err, 0, "fail for {i}"); + } +} + +fn set_custom_cpu_mask() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread"); + + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // at the start, thread 1 should be set + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + assert!(unsafe { libc::CPU_ISSET(1, &cpuset) }); + + // make a valid mask + unsafe { libc::CPU_ZERO(&mut cpuset) }; + unsafe { libc::CPU_SET(0, &mut cpuset) }; + + // giving a smaller mask is fine + let err = unsafe { sched_setaffinity(PID, 8, &cpuset) }; + assert_eq!(err, 0); + + // and actually disables other threads + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) }); + + // it is important that we reset the cpu mask now for future tests + for i in 0..cpu_count { + unsafe { libc::CPU_SET(i, &mut cpuset) }; + } + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); +} + +fn parent_child() { + let cpu_count = std::thread::available_parallelism().unwrap().get(); + + assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread"); + + // configure the parent thread to only run only on CPU 0 + let mut parent_cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + unsafe { libc::CPU_SET(0, &mut parent_cpuset) }; + + let err = unsafe { sched_setaffinity(PID, size_of::(), &parent_cpuset) }; + assert_eq!(err, 0); + + std::thread::scope(|spawner| { + spawner.spawn(|| { + let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; + assert_eq!(err, 0); + + // the child inherits its parent's set + assert!(unsafe { libc::CPU_ISSET(0, &cpuset) }); + assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) }); + + // configure cpu 1 for the child + unsafe { libc::CPU_SET(1, &mut cpuset) }; + }); + }); + + let err = unsafe { sched_getaffinity(PID, size_of::(), &mut parent_cpuset) }; + assert_eq!(err, 0); + + // the parent's set should be unaffected + assert!(unsafe { !libc::CPU_ISSET(1, &parent_cpuset) }); + + // it is important that we reset the cpu mask now for future tests + let mut cpuset = parent_cpuset; + for i in 0..cpu_count { + unsafe { libc::CPU_SET(i, &mut cpuset) }; + } + + let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; + assert_eq!(err, 0); +} + +fn main() { + null_pointers(); + configure_no_cpus(); + configure_unavailable_cpu(); + large_set(); + get_small_cpu_mask(); + set_small_cpu_mask(); + set_custom_cpu_mask(); + parent_child(); +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index da685e5c6b7d..eddea92353e3 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -36,6 +36,7 @@ fn main() { #[cfg(target_os = "linux")] test_sync_file_range(); test_isatty(); + test_read_and_uninit(); } fn test_file_open_unix_allow_two_args() { @@ -388,3 +389,37 @@ fn test_isatty() { remove_file(&path).unwrap(); } } + +fn test_read_and_uninit() { + use std::mem::MaybeUninit; + { + // We test that libc::read initializes its buffer. + let path = utils::prepare_with_content("pass-libc-read-and-uninit.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf: MaybeUninit<[u8; 2]> = std::mem::MaybeUninit::uninit(); + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 2), 2); + let buf = buf.assume_init(); + assert_eq!(buf, [1, 2]); + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); + } + { + // We test that if we requested to read 4 bytes, but actually read 3 bytes, then + // 3 bytes (not 4) will be overwritten, and remaining byte will be left as-is. + let path = utils::prepare_with_content("pass-libc-read-and-uninit-2.txt", &[1u8, 2, 3]); + let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap(); + unsafe { + let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY); + assert_ne!(fd, -1); + let mut buf = [42u8; 5]; + assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::(), 4), 3); + assert_eq!(buf, [1, 2, 3, 42, 42]); + assert_eq!(libc::close(fd), 0); + } + remove_file(&path).unwrap(); + } +} diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 5464627fa144..6ab18a5345ea 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -4,8 +4,11 @@ #![feature(f128)] #![feature(f16)] #![allow(arithmetic_overflow)] +#![allow(internal_features)] -use std::fmt::Debug; +use std::any::type_name; +use std::cmp::min; +use std::fmt::{Debug, Display, LowerHex}; use std::hint::black_box; use std::{f32, f64}; @@ -29,15 +32,41 @@ fn main() { test_algebraic(); } -// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. -// Doesn't make a big difference when running this in Miri, but it means we can compare this -// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. -#[track_caller] -#[inline(never)] -fn assert_eq(x: T, y: T) { - assert_eq!(x, y); +trait Float: Copy + PartialEq + Debug { + /// The unsigned integer with the same bit width as this float + type Int: Copy + PartialEq + LowerHex + Debug; + const BITS: u32 = size_of::() as u32 * 8; + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + const SIGNIFICAND_BITS: u32; + + /// The saturated (all ones) value of the exponent (infinity representation) + const EXPONENT_SAT: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value (max representable positive exponent) + const EXPONENT_BIAS: u32 = Self::EXPONENT_SAT >> 1; + + fn to_bits(self) -> Self::Int; } +macro_rules! impl_float { + ($ty:ty, $ity:ty) => { + impl Float for $ty { + type Int = $ity; + // Just get this from std's value, which includes the implicit digit + const SIGNIFICAND_BITS: u32 = <$ty>::MANTISSA_DIGITS - 1; + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + } + }; +} + +impl_float!(f16, u16); +impl_float!(f32, u32); +impl_float!(f64, u64); +impl_float!(f128, u128); + trait FloatToInt: Copy { fn cast(self) -> Int; unsafe fn cast_unchecked(self) -> Int; @@ -58,19 +87,61 @@ macro_rules! float_to_int { }; } +float_to_int!(f16 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); +float_to_int!(f128 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] -fn test_both_cast(x: F, y: I) +fn test_both_cast(x: F, y: I, msg: impl Display) where F: FloatToInt, I: PartialEq + Debug, { - assert_eq!(x.cast(), y); - assert_eq!(unsafe { x.cast_unchecked() }, y); + let f_tname = type_name::(); + let i_tname = type_name::(); + assert_eq!(x.cast(), y, "{f_tname} -> {i_tname}: {msg}"); + assert_eq!(unsafe { x.cast_unchecked() }, y, "{f_tname} -> {i_tname}: {msg}",); +} + +/// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. +/// Doesn't make a big difference when running this in Miri, but it means we can compare this +/// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. +#[track_caller] +#[inline(never)] +fn assert_eq(x: T, y: T) { + assert_eq!(x, y); +} + +/// The same as `assert_eq` except prints a specific message on failure +#[track_caller] +#[inline(never)] +fn assert_eq_msg(x: T, y: T, msg: impl Display) { + assert_eq!(x, y, "{msg}"); +} + +/// Check that floats have bitwise equality +fn assert_biteq(a: F, b: F, msg: impl Display) { + let ab = a.to_bits(); + let bb = b.to_bits(); + let tname = type_name::(); + let width = (2 + F::BITS / 4) as usize; + assert_eq_msg::( + ab, + bb, + format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}"), + ); +} + +/// Check that two floats have equality +fn assert_feq(a: F, b: F, msg: impl Display) { + let ab = a.to_bits(); + let bb = b.to_bits(); + let tname = type_name::(); + let width = (2 + F::BITS / 4) as usize; + assert_eq_msg::(a, b, format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}")); } fn basic() { @@ -148,155 +219,368 @@ fn basic() { assert_eq!(34.2f64.abs(), 34.2f64); } -/// Many of these test values are taken from +/// Test casts from floats to ints and back +macro_rules! test_ftoi_itof { + ( + f: $fty:ty, + i: $ity:ty, + // Int min and max as float literals + imin_f: $imin_f:literal, + imax_f: $imax_f:literal $(,)? + ) => {{ + /// By default we test float to int `as` casting as well as to_int_unchecked + fn assert_ftoi(f: $fty, i: $ity, msg: &str) { + #[allow(unused_comparisons)] + if <$ity>::MIN >= 0 && f < 0.0 { + // If `ity` is signed and `f` is negative, it is unrepresentable so skip + // unchecked casts. + assert_ftoi_unrep(f, i, msg); + } else { + test_both_cast::<$fty, $ity>(f, i, msg); + } + } + + /// Unrepresentable values only get tested with `as` casting, not unchecked + fn assert_ftoi_unrep(f: $fty, i: $ity, msg: &str) { + assert_eq_msg::<$ity>( + f as $ity, + i, + format_args!("{} -> {}: {msg}", stringify!($fty), stringify!($ity)), + ); + } + + /// Int to float checks + fn assert_itof(i: $ity, f: $fty, msg: &str) { + assert_eq_msg::<$fty>( + i as $fty, + f, + format_args!("{} -> {}: {msg}", stringify!($ity), stringify!($fty)), + ); + } + + /// Check both float to int and int to float + fn assert_bidir(f: $fty, i: $ity, msg: &str) { + assert_ftoi(f, i, msg); + assert_itof(i, f, msg); + } + + /// Check both float to int and int to float for unrepresentable numbers + fn assert_bidir_unrep(f: $fty, i: $ity, msg: &str) { + assert_ftoi_unrep(f, i, msg); + assert_itof(i, f, msg); + } + + let fbits = <$fty>::BITS; + let fsig_bits = <$fty>::SIGNIFICAND_BITS; + let ibits = <$ity>::BITS; + let imax: $ity = <$ity>::MAX; + let imin: $ity = <$ity>::MIN; + let izero: $ity = 0; + #[allow(unused_comparisons)] + let isigned = <$ity>::MIN < 0; + + #[allow(overflowing_literals)] + let imin_f: $fty = $imin_f; + #[allow(overflowing_literals)] + let imax_f: $fty = $imax_f; + + // If an integer can fit entirely in the mantissa (counting the hidden bit), every value + // can be represented exactly. + let all_ints_exact_rep = ibits <= fsig_bits + 1; + + // We can represent the full range of the integer (but possibly not every value) without + // saturating to infinity if `1 << (I::BITS - 1)` (single one in the MSB position) is + // within the float's dynamic range. + let int_range_rep = ibits - 1 < <$fty>::EXPONENT_BIAS; + + // Skip unchecked cast when int min/max would be unrepresentable + let assert_ftoi_big = if all_ints_exact_rep { assert_ftoi } else { assert_ftoi_unrep }; + let assert_bidir_big = if all_ints_exact_rep { assert_bidir } else { assert_bidir_unrep }; + + // Near zero representations + assert_bidir(0.0, 0, "zero"); + assert_ftoi(-0.0, 0, "negative zero"); + assert_ftoi(1.0, 1, "one"); + assert_ftoi(-1.0, izero.saturating_sub(1), "negative one"); + assert_ftoi(1.0 - <$fty>::EPSILON, 0, "1.0 - ε"); + assert_ftoi(1.0 + <$fty>::EPSILON, 1, "1.0 + ε"); + assert_ftoi(-1.0 + <$fty>::EPSILON, 0, "-1.0 + ε"); + assert_ftoi(-1.0 - <$fty>::EPSILON, izero.saturating_sub(1), "-1.0 - ε"); + assert_ftoi(<$fty>::from_bits(0x1), 0, "min subnormal"); + assert_ftoi(<$fty>::from_bits(0x1 | 1 << (fbits - 1)), 0, "min neg subnormal"); + + // Spot checks. Use `saturating_sub` to create negative integers so that unsigned + // integers stay at zero. + assert_ftoi(0.9, 0, "0.9"); + assert_ftoi(-0.9, 0, "-0.9"); + assert_ftoi(1.1, 1, "1.1"); + assert_ftoi(-1.1, izero.saturating_sub(1), "-1.1"); + assert_ftoi(1.9, 1, "1.9"); + assert_ftoi(-1.9, izero.saturating_sub(1), "-1.9"); + assert_ftoi(5.0, 5, "5.0"); + assert_ftoi(-5.0, izero.saturating_sub(5), "-5.0"); + assert_ftoi(5.9, 5, "5.0"); + assert_ftoi(-5.9, izero.saturating_sub(5), "-5.0"); + + // Exercise the middle of the integer's bit range. A power of two fits as long as the + // exponent can fit its log2, so cap at the maximum representable power of two (which + // is the exponent's bias). + let half_i_max: $ity = 1 << min(ibits / 2, <$fty>::EXPONENT_BIAS); + let half_i_min = izero.saturating_sub(half_i_max); + assert_bidir(half_i_max as $fty, half_i_max, "half int max"); + assert_bidir(half_i_min as $fty, half_i_min, "half int min"); + + // Integer limits + assert_bidir_big(imax_f, imax, "i max"); + assert_bidir_big(imin_f, imin, "i min"); + + // We need a small perturbation to test against that does not round up to the next + // integer. `f16` needs a smaller perturbation since it only has resolution for ~1 decimal + // place near 10^3. + let perturb = if fbits < 32 { 0.9 } else { 0.99 }; + assert_ftoi_big(imax_f + perturb, <$ity>::MAX, "slightly above i max"); + assert_ftoi_big(imin_f - perturb, <$ity>::MIN, "slightly below i min"); + + // Tests for when we can represent the integer's magnitude + if int_range_rep { + // If the float can represent values larger than the integer, float extremes + // will saturate. + assert_ftoi_unrep(<$fty>::MAX, imax, "f max"); + assert_ftoi_unrep(<$fty>::MIN, imin, "f min"); + + // Max representable power of 10 + let pow10_max = (10 as $ity).pow(imax.ilog10()); + + // If the power of 10 should be representable (fits in a mantissa), check it + if ibits - pow10_max.leading_zeros() - pow10_max.trailing_zeros() <= fsig_bits + 1 { + assert_bidir(pow10_max as $fty, pow10_max, "pow10 max"); + } + } + + // Test rounding the largest and smallest integers, but skip this when + // all integers have an exact representation (it's less interesting then and the arithmetic gets more complicated). + if int_range_rep && !all_ints_exact_rep { + // The maximum representable integer is a saturated mantissa (including the implicit + // bit), shifted into the int's leftmost position. + // + // Positive signed integers never use their top bit, so shift by one bit fewer. + let sat_mantissa: $ity = (1 << (fsig_bits + 1)) - 1; + let adj = if isigned { 1 } else { 0 }; + let max_rep = sat_mantissa << (sat_mantissa.leading_zeros() - adj); + + // This value should roundtrip exactly + assert_bidir(max_rep as $fty, max_rep, "max representable int"); + + // The cutoff for where to round to `imax` is halfway between the maximum exactly + // representable integer and `imax`. This should round down (to `max_rep`), + // i.e., `max_rep as $fty == max_non_sat as $fty`. + let max_non_sat = max_rep + ((imax - max_rep) / 2); + assert_bidir(max_non_sat as $fty, max_rep, "max non saturating int"); + + // So the next value up should round up to the maximum value of the integer + assert_bidir_unrep((max_non_sat + 1) as $fty, imax, "min infinite int"); + + if isigned { + // Floats can always represent the minimum signed number if they can fit the + // exponent, because it is just a `1` in the MSB. So, no negative int -> float + // conversion will round to negative infinity (if the exponent fits). + // + // Since `imin` is thus the minimum representable value, we test rounding near + // the next value. This happens to be the opposite of the maximum representable + // value, and it should roundtrip exactly. + let next_min_rep = max_rep.wrapping_neg(); + assert_bidir(next_min_rep as $fty, next_min_rep, "min representable above imin"); + + // Following a similar pattern as for positive numbers, halfway between this value + // and `imin` should round back to `next_min_rep`. + let min_non_sat = imin - ((imin - next_min_rep) / 2) + 1; + assert_bidir( + min_non_sat as $fty, + next_min_rep, + "min int that does not round to imin", + ); + + // And then anything else saturates to the minimum value. + assert_bidir_unrep( + (min_non_sat - 1) as $fty, + imin, + "max negative int that rounds to imin", + ); + } + } + + // Check potentially saturating int ranges. (`imax_f` here will be `$fty::INFINITY` if + // it cannot be represented as a finite value.) + assert_itof(imax, imax_f, "imax"); + assert_itof(imin, imin_f, "imin"); + + // Float limits + assert_ftoi_unrep(<$fty>::INFINITY, imax, "f inf"); + assert_ftoi_unrep(<$fty>::NEG_INFINITY, imin, "f neg inf"); + assert_ftoi_unrep(<$fty>::NAN, 0, "f nan"); + assert_ftoi_unrep(-<$fty>::NAN, 0, "f neg nan"); + }}; +} + +/// Test casts from one float to another +macro_rules! test_ftof { + ( + f1: $f1:ty, + f2: $f2:ty $(,)? + ) => {{ + type F2Int = <$f2 as Float>::Int; + + let f1zero: $f1 = 0.0; + let f2zero: $f2 = 0.0; + let f1five: $f1 = 5.0; + let f2five: $f2 = 5.0; + + assert_biteq((f1zero as $f2), f2zero, "0.0"); + assert_biteq(((-f1zero) as $f2), (-f2zero), "-0.0"); + assert_biteq((f1five as $f2), f2five, "5.0"); + assert_biteq(((-f1five) as $f2), (-f2five), "-5.0"); + + assert_feq(<$f1>::INFINITY as $f2, <$f2>::INFINITY, "max -> inf"); + assert_feq(<$f1>::NEG_INFINITY as $f2, <$f2>::NEG_INFINITY, "max -> inf"); + assert!((<$f1>::NAN as $f2).is_nan(), "{} -> {} nan", stringify!($f1), stringify!($f2)); + + let min_sub_casted = <$f1>::from_bits(0x1) as $f2; + let min_neg_sub_casted = <$f1>::from_bits(0x1 | 1 << (<$f1>::BITS - 1)) as $f2; + + if <$f1>::BITS > <$f2>::BITS { + assert_feq(<$f1>::MAX as $f2, <$f2>::INFINITY, "max -> inf"); + assert_feq(<$f1>::MIN as $f2, <$f2>::NEG_INFINITY, "max -> inf"); + assert_biteq(min_sub_casted, f2zero, "min subnormal -> 0.0"); + assert_biteq(min_neg_sub_casted, -f2zero, "min neg subnormal -> -0.0"); + } else { + // When increasing precision, the minimum subnormal will just roll to the next + // exponent. This exponent will be the current exponent (with bias), plus + // `sig_bits - 1` to account for the implicit change in exponent (since the + // mantissa starts with 0). + let sub_casted = <$f2>::from_bits( + ((<$f2>::EXPONENT_BIAS - (<$f1>::EXPONENT_BIAS + <$f1>::SIGNIFICAND_BITS - 1)) + as F2Int) + << <$f2>::SIGNIFICAND_BITS, + ); + assert_biteq(min_sub_casted, sub_casted, "min subnormal"); + assert_biteq(min_neg_sub_casted, -sub_casted, "min neg subnormal"); + } + }}; +} + +/// Many of these test patterns were adapted from the values in /// https://github.com/WebAssembly/testsuite/blob/master/conversions.wast. fn casts() { - // f32 -> i8 - test_both_cast::(127.99, 127); - test_both_cast::(-128.99, -128); + /* int <-> float generic tests */ - // f32 -> i32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); - test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_both_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); - test_both_cast::(1.9, 1); - test_both_cast::(-1.9, -1); - test_both_cast::(5.0, 5); - test_both_cast::(-5.0, -5); - test_both_cast::(2147483520.0, 2147483520); - test_both_cast::(-2147483648.0, -2147483648); - // unrepresentable casts - assert_eq::(2147483648.0f32 as i32, i32::MAX); - assert_eq::(-2147483904.0f32 as i32, i32::MIN); - assert_eq::(f32::MAX as i32, i32::MAX); - assert_eq::(f32::MIN as i32, i32::MIN); - assert_eq::(f32::INFINITY as i32, i32::MAX); - assert_eq::(f32::NEG_INFINITY as i32, i32::MIN); - assert_eq::(f32::NAN as i32, 0); - assert_eq::((-f32::NAN) as i32, 0); + test_ftoi_itof! { f: f16, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f16, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f16, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f16, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f16, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f16, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f16, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f16, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f16, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f16, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f32 -> u32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(-0.9999999, 0); - test_both_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); - test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_both_cast::(1.9, 1); - test_both_cast::(5.0, 5); - test_both_cast::(2147483648.0, 0x8000_0000); - test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); - test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); - test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_both_cast::((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss - // unrepresentable casts - assert_eq::((u32::MAX - 127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable - assert_eq::(4294967296.0f32 as u32, u32::MAX); - assert_eq::(-5.0f32 as u32, 0); - assert_eq::(f32::MAX as u32, u32::MAX); - assert_eq::(f32::MIN as u32, 0); - assert_eq::(f32::INFINITY as u32, u32::MAX); - assert_eq::(f32::NEG_INFINITY as u32, 0); - assert_eq::(f32::NAN as u32, 0); - assert_eq::((-f32::NAN) as u32, 0); + test_ftoi_itof! { f: f32, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f32, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f32, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f32, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f32, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f32, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f32, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f32, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f32, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f32, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f32 -> i64 - test_both_cast::(4294967296.0, 4294967296); - test_both_cast::(-4294967296.0, -4294967296); - test_both_cast::(9223371487098961920.0, 9223371487098961920); - test_both_cast::(-9223372036854775808.0, -9223372036854775808); + test_ftoi_itof! { f: f64, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f64, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f64, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f64, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f64, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f64, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f64, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f64, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f64, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f64, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f64 -> i8 - test_both_cast::(127.99, 127); - test_both_cast::(-128.99, -128); + test_ftoi_itof! { f: f128, i: i8, imin_f: -128.0, imax_f: 127.0 }; + test_ftoi_itof! { f: f128, i: u8, imin_f: 0.0, imax_f: 255.0 }; + test_ftoi_itof! { f: f128, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 }; + test_ftoi_itof! { f: f128, i: u16, imin_f: 0.0, imax_f: 65_535.0 }; + test_ftoi_itof! { f: f128, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 }; + test_ftoi_itof! { f: f128, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 }; + test_ftoi_itof! { + f: f128, + i: i64, + imin_f: -9_223_372_036_854_775_808.0, + imax_f: 9_223_372_036_854_775_807.0 + }; + test_ftoi_itof! { f: f128, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 }; + test_ftoi_itof! { + f: f128, + i: i128, + imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0, + imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0, + }; + test_ftoi_itof! { + f: f128, + i: u128, + imin_f: 0.0, + imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0 + }; - // f64 -> i32 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::( - /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), - -1, - ); - test_both_cast::(1.9, 1); - test_both_cast::(-1.9, -1); - test_both_cast::(1e8, 100_000_000); - test_both_cast::(2147483647.0, 2147483647); - test_both_cast::(-2147483648.0, -2147483648); - // unrepresentable casts - assert_eq::(2147483648.0f64 as i32, i32::MAX); - assert_eq::(-2147483649.0f64 as i32, i32::MIN); - - // f64 -> i64 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_both_cast::( - /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), - 0, - ); - test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::( - /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), - -1, - ); - test_both_cast::(5.0, 5); - test_both_cast::(5.9, 5); - test_both_cast::(-5.0, -5); - test_both_cast::(-5.9, -5); - test_both_cast::(4294967296.0, 4294967296); - test_both_cast::(-4294967296.0, -4294967296); - test_both_cast::(9223372036854774784.0, 9223372036854774784); - test_both_cast::(-9223372036854775808.0, -9223372036854775808); - // unrepresentable casts - assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); - assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); - assert_eq::(f64::MAX as i64, i64::MAX); - assert_eq::(f64::MIN as i64, i64::MIN); - assert_eq::(f64::INFINITY as i64, i64::MAX); - assert_eq::(f64::NEG_INFINITY as i64, i64::MIN); - assert_eq::(f64::NAN as i64, 0); - assert_eq::((-f64::NAN) as i64, 0); - - // f64 -> u64 - test_both_cast::(0.0, 0); - test_both_cast::(-0.0, 0); - test_both_cast::(-0.99999999999, 0); - test_both_cast::(5.0, 5); - test_both_cast::(1e16, 10000000000000000); - test_both_cast::((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss - test_both_cast::(9223372036854775808.0, 9223372036854775808); - // unrepresentable casts - assert_eq::(-5.0f64 as u64, 0); - assert_eq::((u64::MAX - 1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable - assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); - assert_eq::(f64::MAX as u64, u64::MAX); - assert_eq::(f64::MIN as u64, 0); - assert_eq::(f64::INFINITY as u64, u64::MAX); - assert_eq::(f64::NEG_INFINITY as u64, 0); - assert_eq::(f64::NAN as u64, 0); - assert_eq::((-f64::NAN) as u64, 0); - - // f64 -> i128 - assert_eq::(f64::MAX as i128, i128::MAX); - assert_eq::(f64::MIN as i128, i128::MIN); - - // f64 -> u128 - assert_eq::(f64::MAX as u128, u128::MAX); - assert_eq::(f64::MIN as u128, 0); + /* int <-> float spot checks */ // int -> f32 - assert_eq::(127i8 as f32, 127.0); - assert_eq::(2147483647i32 as f32, 2147483648.0); - assert_eq::((-2147483648i32) as f32, -2147483648.0); assert_eq::(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06)); - assert_eq::(16777217i32 as f32, 16777216.0); - assert_eq::((-16777217i32) as f32, -16777216.0); - assert_eq::(16777219i32 as f32, 16777220.0); - assert_eq::((-16777219i32) as f32, -16777220.0); assert_eq::( 0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff), @@ -313,36 +597,33 @@ fn casts() { 0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001), ); - assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation // int -> f64 - assert_eq::(127i8 as f64, 127.0); - assert_eq::(i16::MIN as f64, -32768.0f64); - assert_eq::(2147483647i32 as f64, 2147483647.0); - assert_eq::(-2147483648i32 as f64, -2147483648.0); assert_eq::(987654321i32 as f64, 987654321.0); - assert_eq::(9223372036854775807i64 as f64, 9223372036854775807.0); - assert_eq::(-9223372036854775808i64 as f64, -9223372036854775808.0); assert_eq::(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?) assert_eq::(9007199254740993i64 as f64, 9007199254740992.0); assert_eq::(-9007199254740993i64 as f64, -9007199254740992.0); assert_eq::(9007199254740995i64 as f64, 9007199254740996.0); assert_eq::(-9007199254740995i64 as f64, -9007199254740996.0); - assert_eq::(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... + + /* float -> float generic tests */ + + test_ftof! { f1: f16, f2: f32 }; + test_ftof! { f1: f16, f2: f64 }; + test_ftof! { f1: f16, f2: f128 }; + test_ftof! { f1: f32, f2: f16 }; + test_ftof! { f1: f32, f2: f64 }; + test_ftof! { f1: f32, f2: f128 }; + test_ftof! { f1: f64, f2: f16 }; + test_ftof! { f1: f64, f2: f32 }; + test_ftof! { f1: f64, f2: f128 }; + test_ftof! { f1: f128, f2: f16 }; + test_ftof! { f1: f128, f2: f32 }; + test_ftof! { f1: f128, f2: f64 }; + + /* float -> float spot checks */ // f32 -> f64 - assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); - assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); - assert_eq::(5.0f32 as f64, 5.0f64); - assert_eq::( - /*0x1p-149*/ f32::from_bits(0x1) as f64, - /*0x1p-149*/ f64::from_bits(0x36a0000000000000), - ); - assert_eq::( - /*-0x1p-149*/ f32::from_bits(0x80000001) as f64, - /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000), - ); assert_eq::( /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000), @@ -359,15 +640,8 @@ fn casts() { /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37, ); - assert_eq::(f32::INFINITY as f64, f64::INFINITY); - assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); // f64 -> f32 - assert_eq::((0.0f64 as f32).to_bits(), 0.0f32.to_bits()); - assert_eq::(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits()); - assert_eq::(5.0f64 as f32, 5.0f32); - assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); - assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); assert_eq::( /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000), @@ -376,10 +650,6 @@ fn casts() { /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728), ); - assert_eq::(f64::MAX as f32, f32::INFINITY); - assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); - assert_eq::(f64::INFINITY as f32, f32::INFINITY); - assert_eq::(f64::NEG_INFINITY as f32, f32::NEG_INFINITY); } fn ops() { diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs new file mode 100644 index 000000000000..845f50c1ebaa --- /dev/null +++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs @@ -0,0 +1,43 @@ +//@only-target-darwin + +use std::thread; + +extern "C" { + fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8); +} + +fn register(f: F) +where + F: FnOnce() + 'static, +{ + // This will receive the pointer passed into `_tlv_atexit`, which is the + // original `f` but boxed up. + unsafe extern "C" fn run(ptr: *mut u8) + where + F: FnOnce() + 'static, + { + let f = unsafe { Box::from_raw(ptr as *mut F) }; + f() + } + + unsafe { + _tlv_atexit(run::, Box::into_raw(Box::new(f)) as *mut u8); + } +} + +fn main() { + thread::spawn(|| { + register(|| println!("dtor 2")); + register(|| println!("dtor 1")); + println!("exiting thread"); + }) + .join() + .unwrap(); + + println!("exiting main"); + register(|| println!("dtor 5")); + register(|| { + println!("registering dtor in dtor 3"); + register(|| println!("dtor 4")); + }); +} diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout new file mode 100644 index 000000000000..89d6ca259354 --- /dev/null +++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout @@ -0,0 +1,7 @@ +exiting thread +dtor 1 +dtor 2 +exiting main +registering dtor in dtor 3 +dtor 4 +dtor 5 diff --git a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs index 2d142bef73c4..a3356b682a6a 100644 --- a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs +++ b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs @@ -39,8 +39,6 @@ fn test_ptr(ptr: *mut ()) { // Distance. let ptr = ptr.cast::(); ptr.offset_from(ptr); - /* - FIXME: this is disabled for now as these cases are not yet allowed. // Distance from other "bad" pointers that have the same address, but different provenance. Some // of this is library UB, but we don't want it to be language UB since that would violate // provenance monotonicity: if we allow computing the distance between two ptrs with no @@ -54,6 +52,5 @@ fn test_ptr(ptr: *mut ()) { // - Distance from use-after-free pointer drop(b); ptr.offset_from(other_ptr.with_addr(ptr.addr())); - */ } } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index ec3b8a96ef3b..969552dec84a 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -11,3 +11,5 @@ wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.28.1" ar = "0.9.0" + +build_helper = { path = "../build_helper" } diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index c506c3d6b61a..5017a4b88dad 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -5,8 +5,8 @@ use std::panic; use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; -use crate::drop_bomb::DropBomb; use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output}; +use build_helper::drop_bomb::DropBomb; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 24fa88af82ec..ad989b74e4d9 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -2,8 +2,8 @@ use regex::Regex; use similar::TextDiff; use std::path::{Path, PathBuf}; -use crate::drop_bomb::DropBomb; use crate::fs_wrapper; +use build_helper::drop_bomb::DropBomb; #[cfg(test)] mod tests; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5655318267a2..e5f1ce1bf345 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -7,7 +7,6 @@ pub mod cc; pub mod clang; mod command; pub mod diff; -mod drop_bomb; pub mod fs_wrapper; pub mod llvm; pub mod run; @@ -303,6 +302,11 @@ pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, exp .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) } +/// Returns true if the filename at `path` ends with `suffix`. +pub fn has_suffix>(path: P, suffix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) +} + /// Gathers all files in the current working directory that have the extension `ext`, and counts /// the number of lines within that contain a match with the regex pattern `re`. pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index a2a7c8064dca..ae200d514310 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -4,13 +4,15 @@ use std::path::Path; use crate::{command, cwd, env_var, set_host_rpath}; -/// Construct a new `rustc` invocation. +/// Construct a new `rustc` invocation. This will automatically set the library +/// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. #[track_caller] pub fn rustc() -> Rustc { Rustc::new() } -/// Construct a plain `rustc` invocation with no flags set. +/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_rpath`] +/// still presets the environment variable `HOST_RPATH_DIR` by default. #[track_caller] pub fn bare_rustc() -> Rustc { Rustc::bare() @@ -42,7 +44,8 @@ fn setup_common() -> Command { impl Rustc { // `rustc` invocation constructor methods - /// Construct a new `rustc` invocation. + /// Construct a new `rustc` invocation. This will automatically set the library + /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index ff6234401238..7bf8af4caba0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -5,11 +5,10 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use intern::sym; use once_cell::unsync::Lazy; -use rustc_index::IndexVec; use rustc_pattern_analysis::{ constructor::{Constructor, ConstructorSet, VariantVisibility}, usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport}, - Captures, PatCx, PrivateUninhabitedField, + Captures, IndexVec, PatCx, PrivateUninhabitedField, }; use smallvec::{smallvec, SmallVec}; use stdx::never; @@ -54,7 +53,7 @@ impl EnumVariantContiguousIndex { } } -impl rustc_index::Idx for EnumVariantContiguousIndex { +impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex { fn new(idx: usize) -> Self { EnumVariantContiguousIndex(idx) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs index 1e829299e6f3..2ff967416c00 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs @@ -15,7 +15,7 @@ pub struct VersionInfo { pub version: &'static str, /// The release channel we were built for (stable/beta/nightly/dev). /// - /// `None` if not built via rustbuild. + /// `None` if not built via bootstrap. pub release_channel: Option<&'static str>, /// Information about the Git repository we may have been built from. /// diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 424c93a75218..18e32e5c65b0 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -bcf1f6db4594ae6132378b179a30cdb3599a863d +a91f7d72f12efcc00ecf71591f066c534d45ddf7 diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index c211b34850a0..e7020980dc3d 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -109,7 +109,7 @@ impl Combiner { .with_context(|| format!("failed to read components in '{}'", input_tarball))?; for component in pkg_components.split_whitespace() { // All we need to do is copy the component directory. We could - // move it, but rustbuild wants to reuse the unpacked package + // move it, but bootstrap wants to reuse the unpacked package // dir for OS-specific installers on macOS and Windows. let component_dir = package_dir.join(component); create_dir(&component_dir)?; diff --git a/src/tools/rust-installer/test.sh b/src/tools/rust-installer/test.sh index 16b05c66197c..7b3e74560062 100755 --- a/src/tools/rust-installer/test.sh +++ b/src/tools/rust-installer/test.sh @@ -974,7 +974,7 @@ combined_remains() { --package-name=rust \ --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz" for component in rustc cargo rust-docs; do - # rustbuild wants the original extracted package intact too + # bootstrap wants the original extracted package intact too try test -d "$WORK_DIR/$component/$component" try test -d "$WORK_DIR/rust/$component" done diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 33120cf93f90..f7ec7d0b3f6b 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile run-make/emit-to-stdout/Makefile -run-make/env-dep-info/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile @@ -37,7 +36,6 @@ run-make/extern-fn-with-packed-struct/Makefile run-make/extern-fn-with-union/Makefile run-make/extern-multiple-copies/Makefile run-make/extern-multiple-copies2/Makefile -run-make/extra-filename-with-temp-outputs/Makefile run-make/fmt-write-bloat/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile @@ -58,9 +56,7 @@ run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile -run-make/issue-83045/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile -run-make/issue-85019-moved-src-dir/Makefile run-make/issue-85401-static-mir/Makefile run-make/issue-88756-default-output/Makefile run-make/issue-97463-abi-param-passing/Makefile @@ -116,7 +112,6 @@ run-make/return-non-c-like-enum-from-c/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile -run-make/rustc-macro-dep-files/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 82fa43f581fd..3c72fae0881e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -353,6 +353,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-hash", "rustc-rayon", "rustc-rayon-core", + "rustc-stable-hash", "rustc_apfloat", "rustc_version", "rustix", diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs new file mode 100644 index 000000000000..c4a2c1ad44ec --- /dev/null +++ b/tests/assembly/x86-return-float.rs @@ -0,0 +1,328 @@ +//@ assembly-output: emit-asm +//@ only-x86 +// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled. +// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable +// SSE2. +// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order. +//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4 +// Force frame pointers to make ASM more consistent between targets +//@ compile-flags: -O -C force-frame-pointers +//@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst +//@ revisions: unix windows +//@[unix] ignore-windows +//@[windows] only-windows + +#![crate_type = "lib"] +#![feature(f16, f128)] + +// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87 +// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens +// signalling NaNs. + +// Returning individual floats + +// CHECK-LABEL: return_f32: +#[no_mangle] +pub fn return_f32(x: f32) -> f32 { + // CHECK: movl {{.*}}(%ebp), %eax + // CHECK-NOT: ax + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64: +#[no_mangle] +pub fn return_f64(x: f64) -> f64 { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL:.*]] + // CHECK-NEXT: movsd %[[VAL]], (%[[PTR]]) + // CHECK: retl + x +} + +// Returning scalar pairs containing floats + +// CHECK-LABEL: return_f32_f32: +#[no_mangle] +pub fn return_f32_f32(x: (f32, f32)) -> (f32, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f64: +#[no_mangle] +pub fn return_f64_f64(x: (f64, f64)) -> (f64, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_f64: +#[no_mangle] +pub fn return_f32_f64(x: (f32, f64)) -> (f32, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_f32: +#[no_mangle] +pub fn return_f64_f32(x: (f64, f32)) -> (f64, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f32_other: +#[no_mangle] +pub fn return_f32_other(x: (f32, usize)) -> (f32, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_f64_other: +#[no_mangle] +pub fn return_f64_other(x: (f64, usize)) -> (f64, usize) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f32: +#[no_mangle] +pub fn return_other_f32(x: (usize, f32)) -> (usize, f32) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + // CHECK: retl + x +} + +// CHECK-LABEL: return_other_f64: +#[no_mangle] +pub fn return_other_f64(x: (usize, f64)) -> (usize, f64) { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]]) + // CHECK: retl + x +} + +// Calling functions returning floats + +// CHECK-LABEL: call_f32: +#[no_mangle] +pub unsafe fn call_f32(x: &mut f32) { + extern "Rust" { + fn get_f32() -> f32; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32 + // CHECK-NEXT: movl %eax, (%[[PTR]]) + *x = get_f32(); +} + +// CHECK-LABEL: call_f64: +#[no_mangle] +pub unsafe fn call_f64(x: &mut f64) { + extern "Rust" { + fn get_f64() -> f64; + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64 + // CHECK: movsd {{.*}}(%{{ebp|esp}}), %[[VAL:.*]] + // CHECK-NEXT: movsd %[[VAL:.*]], (%[[PTR]]) + *x = get_f64(); +} + +// Calling functions returning scalar pairs containing floats + +// CHECK-LABEL: call_f32_f32: +#[no_mangle] +pub unsafe fn call_f32_f32(x: &mut (f32, f32)) { + extern "Rust" { + fn get_f32_f32() -> (f32, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f32 + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_f32(); +} + +// CHECK-LABEL: call_f64_f64: +#[no_mangle] +pub unsafe fn call_f64_f64(x: &mut (f64, f64)) { + extern "Rust" { + fn get_f64_f64() -> (f64, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f64 + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f64(); +} + +// CHECK-LABEL: call_f32_f64: +#[no_mangle] +pub unsafe fn call_f32_f64(x: &mut (f32, f64)) { + extern "Rust" { + fn get_f32_f64() -> (f32, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_f64 + // unix: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // windows: movss (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_f32_f64(); +} + +// CHECK-LABEL: call_f64_f32: +#[no_mangle] +pub unsafe fn call_f64_f32(x: &mut (f64, f32)) { + extern "Rust" { + fn get_f64_f32() -> (f64, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_f32 + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movss 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_f32(); +} + +// CHECK-LABEL: call_f32_other: +#[no_mangle] +pub unsafe fn call_f32_other(x: &mut (f32, usize)) { + extern "Rust" { + fn get_f32_other() -> (f32, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f32_other + // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]]) + *x = get_f32_other(); +} + +// CHECK-LABEL: call_f64_other: +#[no_mangle] +pub unsafe fn call_f64_other(x: &mut (f64, usize)) { + extern "Rust" { + fn get_f64_other() -> (f64, usize); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_f64_other + // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // windows: movsd (%esp), %[[VAL1:.*]] + // windows-NEXT: movl 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]]) + *x = get_f64_other(); +} + +// CHECK-LABEL: call_other_f32: +#[no_mangle] +pub unsafe fn call_other_f32(x: &mut (usize, f32)) { + extern "Rust" { + fn get_other_f32() -> (usize, f32); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f32 + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]]) + *x = get_other_f32(); +} + +// CHECK-LABEL: call_other_f64: +#[no_mangle] +pub unsafe fn call_other_f64(x: &mut (usize, f64)) { + extern "Rust" { + fn get_other_f64() -> (usize, f64); + } + // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]] + // CHECK: calll {{()|_}}get_other_f64 + // unix: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]] + // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]] + // windows: movl (%esp), %[[VAL1:.*]] + // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]] + // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]]) + // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]]) + // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]]) + *x = get_other_f64(); +} + +// The "C" ABI for `f16` and `f128` on x86 has never used the x87 floating point stack. Do some +// basic checks to ensure this remains the case for the "Rust" ABI. + +// CHECK-LABEL: return_f16: +#[no_mangle] +pub fn return_f16(x: f16) -> f16 { + // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0 + // CHECK-NOT: xmm0 + // CHECK: retl + x +} + +// CHECK-LABEL: return_f128: +#[no_mangle] +pub fn return_f128(x: f128) -> f128 { + // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]] + // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]] + // CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]]) + // CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]]) + // CHECK: retl + x +} diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 32c5be1ec651..80b572fbbc9f 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,3 +1,8 @@ +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 + // Verify that our intrinsics generate the correct LLVM calls for f128 #![crate_type = "lib"] @@ -138,14 +143,16 @@ pub fn f128_as_f16(a: f128) -> f16 { a as f16 } -// CHECK-LABEL: float @f128_as_f32( +// other-LABEL: float @f128_as_f32( +// x86-LABEL: i32 @f128_as_f32( #[no_mangle] pub fn f128_as_f32(a: f128) -> f32 { // CHECK: fptrunc fp128 %{{.+}} to float a as f32 } -// CHECK-LABEL: double @f128_as_f64( +// other-LABEL: double @f128_as_f64( +// x86-LABEL: void @f128_as_f64( #[no_mangle] pub fn f128_as_f64(a: f128) -> f64 { // CHECK: fptrunc fp128 %{{.+}} to double diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index 96daac869c28..2910d7d3e928 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,3 +1,8 @@ +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 + // Verify that our intrinsics generate the correct LLVM calls for f16 #![crate_type = "lib"] @@ -140,14 +145,16 @@ pub fn f16_as_self(a: f16) -> f16 { a as f16 } -// CHECK-LABEL: float @f16_as_f32( +// other-LABEL: float @f16_as_f32( +// x86-LABEL: i32 @f16_as_f32( #[no_mangle] pub fn f16_as_f32(a: f16) -> f32 { // CHECK: fpext half %{{.+}} to float a as f32 } -// CHECK-LABEL: double @f16_as_f64( +// other-LABEL: double @f16_as_f64( +// x86-LABEL: void @f16_as_f64( #[no_mangle] pub fn f16_as_f64(a: f16) -> f64 { // CHECK: fpext half %{{.+}} to double diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs index 9693c414a67d..4d6895166f1c 100644 --- a/tests/codegen/issues/issue-32031.rs +++ b/tests/codegen/issues/issue-32031.rs @@ -1,11 +1,16 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 #![crate_type = "lib"] #[no_mangle] pub struct F32(f32); -// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b) +// other: define{{.*}}float @add_newtype_f32(float %a, float %b) +// x86: define{{.*}}i32 @add_newtype_f32(float %a, float %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f32(a: F32, b: F32) -> F32 { @@ -15,7 +20,8 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 { #[no_mangle] pub struct F64(f64); -// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b) +// other: define{{.*}}double @add_newtype_f64(double %a, double %b) +// x86: define{{.*}}void @add_newtype_f64(ptr{{.*}}sret([8 x i8]){{.*}}%_0, double %a, double %b) #[inline(never)] #[no_mangle] pub fn add_newtype_f64(a: F64, b: F64) -> F64 { diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index 9e02fa9ff359..08015014456c 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -1,5 +1,9 @@ //@ ignore-emscripten vectors passed directly //@ compile-flags: -O -C no-prepopulate-passes +// 32-bit x86 returns `f32` differently to avoid the x87 stack. +//@ revisions: x86 other +//@[x86] only-x86 +//@[other] ignore-x86 // This test that using union forward the abi of the inner type, as // discussed in #54668 @@ -67,7 +71,8 @@ pub union UnionF32 { a: f32, } -// CHECK: define {{(dso_local )?}}float @test_UnionF32(float %_1) +// other: define {{(dso_local )?}}float @test_UnionF32(float %_1) +// x86: define {{(dso_local )?}}i32 @test_UnionF32(float %_1) #[no_mangle] pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} @@ -78,7 +83,8 @@ pub union UnionF32F32 { b: f32, } -// CHECK: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +// other: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) +// x86: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1) #[no_mangle] pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index f36ef7af7ac3..6edd35921fe9 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -31,16 +31,18 @@ Number of file 0 mappings: 24 = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) -Function name: closure::main::{closure#0} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +Function name: closure::main::{closure#0} +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 0 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Zero) at (prev + 40, 5) to (start + 2, 20) -- Code(Zero) at (prev + 2, 21) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) -- Code(Zero) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) +- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Function name: closure::main::{closure#10} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 9c18827d8e68..11a99f5395ec 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -81,101 +81,130 @@ Number of file 0 mappings: 11 = (((c4 + Zero) + Zero) + c3) Function name: try_error_result::test2 -Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] +Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 36 +Number of expressions: 59 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) -- expression 1 operands: lhs = Zero, rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(16), rhs = Zero -- expression 4 operands: lhs = Expression(7, Sub), rhs = Zero -- expression 5 operands: lhs = Counter(16), rhs = Zero -- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero -- expression 7 operands: lhs = Counter(16), rhs = Zero -- expression 8 operands: lhs = Expression(18, Sub), rhs = Zero -- expression 9 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 10 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 12 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 14 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 17 operands: lhs = Expression(18, Sub), rhs = Zero -- expression 18 operands: lhs = Expression(19, Sub), rhs = Zero -- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(16) -- expression 20 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 21 operands: lhs = Expression(25, Sub), rhs = Zero -- expression 22 operands: lhs = Counter(17), rhs = Zero -- expression 23 operands: lhs = Counter(17), rhs = Zero -- expression 24 operands: lhs = Expression(25, Sub), rhs = Zero -- expression 25 operands: lhs = Counter(17), rhs = Zero -- expression 26 operands: lhs = Expression(30, Sub), rhs = Zero -- expression 27 operands: lhs = Counter(19), rhs = Zero -- expression 28 operands: lhs = Counter(19), rhs = Zero -- expression 29 operands: lhs = Expression(30, Sub), rhs = Zero -- expression 30 operands: lhs = Counter(19), rhs = Zero -- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(3) -- expression 32 operands: lhs = Expression(33, Add), rhs = Zero -- expression 33 operands: lhs = Zero, rhs = Expression(34, Add) -- expression 34 operands: lhs = Expression(35, Add), rhs = Zero -- expression 35 operands: lhs = Counter(6), rhs = Zero +- expression 3 operands: lhs = Counter(16), rhs = Counter(4) +- expression 4 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 5 operands: lhs = Counter(16), rhs = Counter(4) +- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(7) +- expression 7 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 8 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(16), rhs = Counter(4) +- expression 10 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 11 operands: lhs = Counter(16), rhs = Counter(4) +- expression 12 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 14 operands: lhs = Counter(16), rhs = Counter(4) +- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(7) +- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(6) +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 18 operands: lhs = Counter(16), rhs = Counter(4) +- expression 19 operands: lhs = Expression(23, Sub), rhs = Counter(9) +- expression 20 operands: lhs = Counter(18), rhs = Counter(8) +- expression 21 operands: lhs = Counter(18), rhs = Counter(8) +- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(9) +- expression 23 operands: lhs = Counter(18), rhs = Counter(8) +- expression 24 operands: lhs = Expression(34, Sub), rhs = Counter(11) +- expression 25 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 26 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 27 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 28 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 29 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 30 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 31 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 32 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 33 operands: lhs = Expression(34, Sub), rhs = Counter(11) +- expression 34 operands: lhs = Expression(35, Sub), rhs = Counter(10) +- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(16) +- expression 36 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 37 operands: lhs = Expression(41, Sub), rhs = Counter(13) +- expression 38 operands: lhs = Counter(17), rhs = Counter(12) +- expression 39 operands: lhs = Counter(17), rhs = Counter(12) +- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(13) +- expression 41 operands: lhs = Counter(17), rhs = Counter(12) +- expression 42 operands: lhs = Expression(46, Sub), rhs = Counter(15) +- expression 43 operands: lhs = Counter(19), rhs = Counter(14) +- expression 44 operands: lhs = Counter(19), rhs = Counter(14) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(15) +- expression 46 operands: lhs = Counter(19), rhs = Counter(14) +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(54, Add) +- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(51, Add) +- expression 50 operands: lhs = Counter(4), rhs = Counter(5) +- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 52 operands: lhs = Counter(6), rhs = Counter(7) +- expression 53 operands: lhs = Counter(8), rhs = Counter(9) +- expression 54 operands: lhs = Expression(55, Add), rhs = Expression(56, Add) +- expression 55 operands: lhs = Counter(10), rhs = Counter(11) +- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(58, Add) +- expression 57 operands: lhs = Counter(12), rhs = Counter(13) +- expression 58 operands: lhs = Counter(14), rhs = Counter(15) Number of file 0 mappings: 40 - Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) - = (c0 + (Zero + c2)) -- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26) - = ((c0 + (Zero + c2)) - c3) + = (c0 + (c1 + c2)) +- Code(Expression(36, Sub)) at (prev + 2, 9) to (start + 4, 26) + = ((c0 + (c1 + c2)) - c3) - Code(Counter(16)) at (prev + 6, 13) to (start + 0, 47) -- Code(Zero) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(7, Sub)) at (prev + 0, 49) to (start + 3, 53) - = (c16 - Zero) -- Code(Zero) at (prev + 4, 17) to (start + 0, 18) -- Code(Expression(6, Sub)) at (prev + 2, 17) to (start + 4, 18) - = ((c16 - Zero) - Zero) -- Code(Zero) at (prev + 5, 17) to (start + 0, 20) -- Code(Expression(6, Sub)) at (prev + 0, 23) to (start + 0, 65) - = ((c16 - Zero) - Zero) +- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(18, Sub)) at (prev + 0, 49) to (start + 3, 53) + = (c16 - c4) +- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) +- Code(Expression(17, Sub)) at (prev + 2, 17) to (start + 4, 18) + = ((c16 - c4) - c5) +- Code(Expression(15, Sub)) at (prev + 5, 17) to (start + 0, 20) + = ((((c16 - c4) - c5) - c6) - c7) +- Code(Expression(17, Sub)) at (prev + 0, 23) to (start + 0, 65) + = ((c16 - c4) - c5) - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Zero) at (prev + 0, 67) to (start + 0, 95) -- Code(Zero) at (prev + 0, 95) to (start + 0, 96) -- Code(Zero) at (prev + 1, 13) to (start + 0, 32) -- Code(Zero) at (prev + 1, 17) to (start + 0, 20) -- Code(Zero) at (prev + 0, 23) to (start + 0, 65) -- Code(Zero) at (prev + 0, 65) to (start + 0, 66) -- Code(Zero) at (prev + 0, 67) to (start + 0, 96) -- Code(Zero) at (prev + 0, 96) to (start + 0, 97) -- Code(Zero) at (prev + 1, 13) to (start + 0, 32) -- Code(Expression(17, Sub)) at (prev + 4, 17) to (start + 0, 20) - = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero) -- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 66) - = (((c0 + (Zero + c2)) - c3) - c16) -- Code(Zero) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(18, Sub)) at (prev + 0, 68) to (start + 0, 97) - = ((((c0 + (Zero + c2)) - c3) - c16) - Zero) -- Code(Zero) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(17, Sub)) at (prev + 1, 13) to (start + 0, 32) - = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero) -- Code(Expression(24, Sub)) at (prev + 1, 17) to (start + 0, 20) - = ((c17 - Zero) - Zero) +- Code(Expression(16, Sub)) at (prev + 0, 67) to (start + 0, 95) + = (((c16 - c4) - c5) - c6) +- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) +- Code(Expression(15, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((((c16 - c4) - c5) - c6) - c7) +- Code(Expression(22, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c18 - c8) - c9) +- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 65) +- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) +- Code(Expression(23, Sub)) at (prev + 0, 67) to (start + 0, 96) + = (c18 - c8) +- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) +- Code(Expression(22, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((c18 - c8) - c9) +- Code(Expression(33, Sub)) at (prev + 4, 17) to (start + 0, 20) + = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) +- Code(Expression(35, Sub)) at (prev + 0, 23) to (start + 0, 66) + = (((c0 + (c1 + c2)) - c3) - c16) +- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) +- Code(Expression(34, Sub)) at (prev + 0, 68) to (start + 0, 97) + = ((((c0 + (c1 + c2)) - c3) - c16) - c10) +- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) +- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32) + = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) +- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c17 - c12) - c13) - Code(Counter(17)) at (prev + 0, 23) to (start + 1, 54) -- Code(Zero) at (prev + 1, 54) to (start + 0, 55) -- Code(Expression(25, Sub)) at (prev + 1, 18) to (start + 0, 47) - = (c17 - Zero) -- Code(Zero) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(24, Sub)) at (prev + 1, 13) to (start + 0, 32) - = ((c17 - Zero) - Zero) -- Code(Expression(29, Sub)) at (prev + 1, 17) to (start + 0, 20) - = ((c19 - Zero) - Zero) +- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) +- Code(Expression(41, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c17 - c12) +- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 32) + = ((c17 - c12) - c13) +- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c19 - c14) - c15) - Code(Counter(19)) at (prev + 0, 23) to (start + 1, 54) -- Code(Zero) at (prev + 2, 17) to (start + 0, 18) -- Code(Expression(30, Sub)) at (prev + 1, 18) to (start + 0, 47) - = (c19 - Zero) -- Code(Zero) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(29, Sub)) at (prev + 2, 13) to (start + 0, 32) - = ((c19 - Zero) - Zero) +- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) +- Code(Expression(46, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c19 - c14) +- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 32) + = ((c19 - c14) - c15) - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) -- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2) - = (((Zero + ((c6 + Zero) + Zero)) + Zero) + c3) +- Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((((c4 + c5) + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15)))) + c3) diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs deleted file mode 100644 index 9b6c5169d444..000000000000 --- a/tests/crashes/126416.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126416 - -trait Output<'a, T: 'a> { - type Type; -} - -struct Wrapper; - -impl Wrapper { - fn do_something_wrapper(&mut self, _: F) - where - F: for<'a> FnOnce(>::Type), - { - } -} - -fn main() { - let mut wrapper = Wrapper; - wrapper.do_something_wrapper(|value| ()); -} diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir index bade0fa4b45c..9ebfff18f483 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir @@ -62,7 +62,7 @@ fn full_tested_match() -> () { _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb16]; + _7 = guard() -> [return: bb8, unwind: bb15]; } bb8: { @@ -118,11 +118,7 @@ fn full_tested_match() -> () { unreachable; } - bb15: { - goto -> bb14; - } - - bb16 (cleanup): { + bb15 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir index 0d78bb8b2358..4d2989ea93ec 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir @@ -68,7 +68,7 @@ fn full_tested_match2() -> () { _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb16]; + _7 = guard() -> [return: bb8, unwind: bb15]; } bb8: { @@ -118,11 +118,7 @@ fn full_tested_match2() -> () { unreachable; } - bb15: { - goto -> bb14; - } - - bb16 (cleanup): { + bb15 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index ebb75ae141a3..4ed936107066 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -38,65 +38,61 @@ fn main() -> () { StorageLive(_2); _2 = Option::::Some(const 1_i32); PlaceMention(_2); - _5 = discriminant(_2); - switchInt(move _5) -> [1: bb8, otherwise: bb2]; + _4 = discriminant(_2); + switchInt(move _4) -> [1: bb2, otherwise: bb1]; } bb1: { - FakeRead(ForMatchedPlace(None), _2); - unreachable; + falseEdge -> [real: bb14, imaginary: bb4]; } bb2: { - falseEdge -> [real: bb15, imaginary: bb3]; + falseEdge -> [real: bb9, imaginary: bb1]; } bb3: { - _4 = discriminant(_2); - switchInt(move _4) -> [1: bb6, otherwise: bb4]; + goto -> bb1; } bb4: { + _5 = discriminant(_2); + switchInt(move _5) -> [1: bb6, otherwise: bb5]; + } + + bb5: { StorageLive(_14); _14 = _2; _1 = const 4_i32; StorageDead(_14); - goto -> bb21; - } - - bb5: { - goto -> bb1; + goto -> bb20; } bb6: { - falseEdge -> [real: bb16, imaginary: bb4]; + falseEdge -> [real: bb15, imaginary: bb5]; } bb7: { - goto -> bb4; + goto -> bb5; } bb8: { - falseEdge -> [real: bb10, imaginary: bb2]; + FakeRead(ForMatchedPlace(None), _2); + unreachable; } bb9: { - goto -> bb2; - } - - bb10: { StorageLive(_7); _7 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_8); - _8 = guard() -> [return: bb11, unwind: bb24]; + _8 = guard() -> [return: bb10, unwind: bb22]; + } + + bb10: { + switchInt(move _8) -> [0: bb12, otherwise: bb11]; } bb11: { - switchInt(move _8) -> [0: bb13, otherwise: bb12]; - } - - bb12: { StorageDead(_8); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _7); @@ -105,42 +101,42 @@ fn main() -> () { _1 = const 1_i32; StorageDead(_6); StorageDead(_7); - goto -> bb21; + goto -> bb20; + } + + bb12: { + goto -> bb13; } bb13: { - goto -> bb14; + StorageDead(_8); + StorageDead(_7); + falseEdge -> [real: bb3, imaginary: bb1]; } bb14: { - StorageDead(_8); - StorageDead(_7); - falseEdge -> [real: bb9, imaginary: bb2]; - } - - bb15: { StorageLive(_9); _9 = _2; _1 = const 2_i32; StorageDead(_9); - goto -> bb21; + goto -> bb20; } - bb16: { + bb15: { StorageLive(_11); _11 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_12); StorageLive(_13); _13 = (*_11); - _12 = guard2(move _13) -> [return: bb17, unwind: bb24]; + _12 = guard2(move _13) -> [return: bb16, unwind: bb22]; + } + + bb16: { + switchInt(move _12) -> [0: bb18, otherwise: bb17]; } bb17: { - switchInt(move _12) -> [0: bb19, otherwise: bb18]; - } - - bb18: { StorageDead(_13); StorageDead(_12); FakeRead(ForMatchGuard, _3); @@ -150,21 +146,21 @@ fn main() -> () { _1 = const 3_i32; StorageDead(_10); StorageDead(_11); - goto -> bb21; - } - - bb19: { goto -> bb20; } - bb20: { + bb18: { + goto -> bb19; + } + + bb19: { StorageDead(_13); StorageDead(_12); StorageDead(_11); - falseEdge -> [real: bb7, imaginary: bb4]; + falseEdge -> [real: bb7, imaginary: bb5]; } - bb21: { + bb20: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -172,16 +168,12 @@ fn main() -> () { return; } - bb22: { + bb21: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb23: { - goto -> bb22; - } - - bb24 (cleanup): { + bb22 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir index faa2456fd100..b0ebdc37b067 100644 --- a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir @@ -6,17 +6,16 @@ fn match_bool(_1: bool) -> usize { bb0: { PlaceMention(_1); - switchInt(_1) -> [0: bb2, otherwise: bb4]; + switchInt(_1) -> [0: bb1, otherwise: bb2]; } bb1: { - FakeRead(ForMatchedPlace(None), _1); - unreachable; + _0 = const 20_usize; + goto -> bb6; } bb2: { - _0 = const 20_usize; - goto -> bb7; + falseEdge -> [real: bb5, imaginary: bb1]; } bb3: { @@ -24,19 +23,16 @@ fn match_bool(_1: bool) -> usize { } bb4: { - falseEdge -> [real: bb6, imaginary: bb2]; + FakeRead(ForMatchedPlace(None), _1); + unreachable; } bb5: { - goto -> bb2; + _0 = const 10_usize; + goto -> bb6; } bb6: { - _0 = const 10_usize; - goto -> bb7; - } - - bb7: { return; } } diff --git a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir index 905aa19da706..5e685f43cd61 100644 --- a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir +++ b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir @@ -8,7 +8,7 @@ fn match_enum(_1: E1) -> bool { bb0: { PlaceMention(_1); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb5, 2: bb7, otherwise: bb2]; + switchInt(move _2) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb1]; } bb1: { @@ -17,44 +17,40 @@ fn match_enum(_1: E1) -> bool { } bb2: { - goto -> bb1; + goto -> bb8; } bb3: { - goto -> bb9; + goto -> bb1; } bb4: { - goto -> bb2; + goto -> bb8; } bb5: { - goto -> bb9; + goto -> bb1; } bb6: { - goto -> bb2; + _0 = const false; + goto -> bb10; } bb7: { - _0 = const false; - goto -> bb11; + goto -> bb1; } bb8: { - goto -> bb2; + falseEdge -> [real: bb9, imaginary: bb6]; } bb9: { - falseEdge -> [real: bb10, imaginary: bb7]; + _0 = const true; + goto -> bb10; } bb10: { - _0 = const true; - goto -> bb11; - } - - bb11: { return; } } diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index 060cd6132e3a..2b5dbacc2d92 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -23,52 +23,52 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { StorageDead(_5); StorageDead(_4); PlaceMention(_3); - _9 = ::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19]; + _9 = ::eq((_3.0: &str), const "a") -> [return: bb9, unwind: bb19]; } bb1: { - switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3]; + switchInt((_3.1: bool)) -> [0: bb10, otherwise: bb11]; } bb2: { + falseEdge -> [real: bb12, imaginary: bb5]; + } + + bb3: { + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb4]; + } + + bb4: { + falseEdge -> [real: bb16, imaginary: bb1]; + } + + bb5: { + _8 = ::eq((_3.0: &str), const "b") -> [return: bb8, unwind: bb19]; + } + + bb6: { + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb7]; + } + + bb7: { + falseEdge -> [real: bb15, imaginary: bb3]; + } + + bb8: { + switchInt(move _8) -> [0: bb1, otherwise: bb6]; + } + + bb9: { + switchInt(move _9) -> [0: bb5, otherwise: bb2]; + } + + bb10: { _0 = const 5_u32; goto -> bb18; } - bb3: { - falseEdge -> [real: bb17, imaginary: bb2]; - } - - bb4: { - falseEdge -> [real: bb12, imaginary: bb7]; - } - - bb5: { - switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6]; - } - - bb6: { - falseEdge -> [real: bb16, imaginary: bb1]; - } - - bb7: { - _8 = ::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19]; - } - - bb8: { - switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9]; - } - - bb9: { - falseEdge -> [real: bb15, imaginary: bb5]; - } - - bb10: { - switchInt(move _8) -> [0: bb1, otherwise: bb8]; - } - bb11: { - switchInt(move _9) -> [0: bb7, otherwise: bb4]; + falseEdge -> [real: bb17, imaginary: bb10]; } bb12: { @@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { bb14: { StorageDead(_10); - falseEdge -> [real: bb5, imaginary: bb7]; + falseEdge -> [real: bb3, imaginary: bb5]; } bb15: { diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir index db758368a138..6d3b2cf29103 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir @@ -26,7 +26,7 @@ fn move_out_by_subslice() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; } bb1: { @@ -34,7 +34,7 @@ fn move_out_by_subslice() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb13]; + drop(_6) -> [return: bb2, unwind: bb12]; } bb2: { @@ -42,7 +42,7 @@ fn move_out_by_subslice() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; } bb3: { @@ -50,18 +50,18 @@ fn move_out_by_subslice() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb12]; + drop(_11) -> [return: bb4, unwind: bb11]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb13]; + drop(_7) -> [return: bb5, unwind: bb12]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb14]; + drop(_2) -> [return: bb6, unwind: bb13]; } bb6: { @@ -71,7 +71,7 @@ fn move_out_by_subslice() -> () { StorageLive(_12); _12 = move _1[0..2]; _0 = const (); - drop(_12) -> [return: bb9, unwind: bb11]; + drop(_12) -> [return: bb8, unwind: bb10]; } bb7: { @@ -80,32 +80,28 @@ fn move_out_by_subslice() -> () { } bb8: { - goto -> bb7; + StorageDead(_12); + drop(_1) -> [return: bb9, unwind: bb13]; } bb9: { - StorageDead(_12); - drop(_1) -> [return: bb10, unwind: bb14]; - } - - bb10: { StorageDead(_1); return; } + bb10 (cleanup): { + drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + } + bb11 (cleanup): { - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_7) -> [return: bb12, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_7) -> [return: bb13, unwind terminate(cleanup)]; + drop(_2) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { - drop(_2) -> [return: bb14, unwind terminate(cleanup)]; - } - - bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir index 84cd557715c2..003b90a912d2 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir @@ -26,7 +26,7 @@ fn move_out_from_end() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; } bb1: { @@ -34,7 +34,7 @@ fn move_out_from_end() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb13]; + drop(_6) -> [return: bb2, unwind: bb12]; } bb2: { @@ -42,7 +42,7 @@ fn move_out_from_end() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; } bb3: { @@ -50,18 +50,18 @@ fn move_out_from_end() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb12]; + drop(_11) -> [return: bb4, unwind: bb11]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb13]; + drop(_7) -> [return: bb5, unwind: bb12]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb14]; + drop(_2) -> [return: bb6, unwind: bb13]; } bb6: { @@ -71,7 +71,7 @@ fn move_out_from_end() -> () { StorageLive(_12); _12 = move _1[1 of 2]; _0 = const (); - drop(_12) -> [return: bb9, unwind: bb11]; + drop(_12) -> [return: bb8, unwind: bb10]; } bb7: { @@ -80,32 +80,28 @@ fn move_out_from_end() -> () { } bb8: { - goto -> bb7; + StorageDead(_12); + drop(_1) -> [return: bb9, unwind: bb13]; } bb9: { - StorageDead(_12); - drop(_1) -> [return: bb10, unwind: bb14]; - } - - bb10: { StorageDead(_1); return; } + bb10 (cleanup): { + drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + } + bb11 (cleanup): { - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_7) -> [return: bb12, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_7) -> [return: bb13, unwind terminate(cleanup)]; + drop(_2) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { - drop(_2) -> [return: bb14, unwind terminate(cleanup)]; - } - - bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff index ac33f51984cd..8088984bc77a 100644 --- a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff +++ b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff @@ -119,11 +119,7 @@ } } - ALLOC0 (size: 8, align: 4) { - 20 00 00 00 20 00 00 00 │ ... ... - } + ALLOC0 (size: 8, align: 4) { .. } - ALLOC1 (size: 4, align: 2) { - 01 00 63 00 │ ..c. - } + ALLOC1 (size: 4, align: 2) { .. } diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs index 907d7fef0674..3b2bc4559ced 100644 --- a/tests/mir-opt/const_debuginfo.rs +++ b/tests/mir-opt/const_debuginfo.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: SingleUseConsts -//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN +//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN -Zdump-mir-exclude-alloc-bytes #![allow(unused)] diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff index 3f4958f60e85..ac372f837268 100644 --- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff +++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff @@ -44,9 +44,7 @@ StorageDead(_2); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/address_of_pair.rs b/tests/mir-opt/const_prop/address_of_pair.rs index 6d0c0f8ad52a..9acaaa0ccaf9 100644 --- a/tests/mir-opt/const_prop/address_of_pair.rs +++ b/tests/mir-opt/const_prop/address_of_pair.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR address_of_pair.fn0.GVN.diff pub fn fn0() -> bool { diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff index 0e93c167ebc9..798f957caa58 100644 --- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff index 589eed5776c9..a09f8ee5be12 100644 --- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/checked_add.rs b/tests/mir-opt/const_prop/checked_add.rs index 0560b0495731..d450f7d03f38 100644 --- a/tests/mir-opt/const_prop/checked_add.rs +++ b/tests/mir-opt/const_prop/checked_add.rs @@ -1,6 +1,6 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: GVN -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR checked_add.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff index b6ff7b0fc234..7584353620ec 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff @@ -24,9 +24,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 2a 00 00 00 2b 00 00 00 │ *...+... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs index 7de647ed9c37..80cd75215c1b 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_aggregate.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff index 4ed7c9851479..e16e2969eb89 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff @@ -31,9 +31,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 2a 00 00 00 2b 00 00 00 │ *...+... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs index 5656c0e7a686..856afd53ab46 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_aggregate_mut_ref.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff index d1d23675bfd9..19d79694666f 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff @@ -48,9 +48,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff index 4d69c9ce2efe..2bb277bf27f7 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff @@ -48,9 +48,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs index cc92949128f7..2c6cc0db6b21 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs @@ -1,5 +1,6 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR mutable_variable_unprop_assign.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff index b2d40daa80c4..037fe60c2fdb 100644 --- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff @@ -17,9 +17,7 @@ + _0 = const 4_u32; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff index 2eafc51cd3db..438a1cebea8c 100644 --- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff @@ -17,9 +17,7 @@ + _0 = const 4_u32; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir index f87c26bb004c..66fd61cc3aee 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir @@ -15,6 +15,4 @@ fn add() -> u32 { } } -ALLOC0 (size: 8, align: 4) { - 04 00 00 00 00 __ __ __ │ .....░░░ -} +ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir index 33f97591387c..f9b07a59de9c 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir @@ -15,6 +15,4 @@ fn add() -> u32 { } } -ALLOC0 (size: 8, align: 4) { - 04 00 00 00 00 __ __ __ │ .....░░░ -} +ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs index e7eea11ae492..c5293aa73e55 100644 --- a/tests/mir-opt/const_prop/return_place.rs +++ b/tests/mir-opt/const_prop/return_place.rs @@ -1,6 +1,6 @@ //@ test-mir-pass: GVN // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR return_place.add.GVN.diff // EMIT_MIR return_place.add.PreCodegen.before.mir diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff index ef298dddd5a4..8415789de6ec 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff index 5379df3f60b4..fea7caac3cdc 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff index ef298dddd5a4..8415789de6ec 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff index 5379df3f60b4..fea7caac3cdc 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff @@ -49,9 +49,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 12, align: 4) { -+ 01 00 00 00 02 00 00 00 03 00 00 00 │ ............ } ++ ++ ALLOC0 (size: 12, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index 63cdbf01b3e8..265a496f39a3 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: GVN -//@ compile-flags: -Zmir-enable-passes=+InstSimplify +//@ compile-flags: -Zmir-enable-passes=+InstSimplify -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff index c2f3fb1b3b57..bf8fece3d37b 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff @@ -31,9 +31,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff index 55d9a3b0cac6..02a75849d887 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff @@ -31,9 +31,7 @@ + nop; return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs index e42a62cb6fdf..baed5670dda8 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR tuple_literal_propagation.main.GVN.diff diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff new file mode 100644 index 000000000000..1aeaaff21dce --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -0,0 +1,65 @@ +- // MIR for `foo` before DataflowConstProp ++ // MIR for `foo` after DataflowConstProp + + fn foo() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const Foo; + StorageLive(_2); +- _2 = _1; ++ _2 = const (5_u32, 3_u32); + StorageLive(_3); +- _3 = (_2.1: u32); ++ _3 = const 3_u32; + StorageLive(_4); + StorageLive(_5); +- _5 = _3; +- _4 = Ge(move _5, const 2_u32); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ _5 = const 3_u32; ++ _4 = const true; ++ switchInt(const true) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); +- _0 = (_2.0: u32); ++ _0 = const 5_u32; + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 05 00 00 00 03 00 00 00 │ ........ + } + diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs new file mode 100644 index 000000000000..aca5f047222f --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -0,0 +1,42 @@ +//! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning +//! the contained scalars. +//@ test-mir-pass: DataflowConstProp + +const Foo: (u32, u32) = (5, 3); + +fn foo() -> u32 { + // CHECK-LABEL: fn foo( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + + // CHECK:bb0: { + // CHECK: [[a]] = const Foo; + // CHECK: [[b]] = const (5_u32, 3_u32); + // CHECK: [[c]] = const 3_u32; + // CHECK: {{_.*}} = const 3_u32; + // CHECK: {{_.*}} = const true; + // CHECK: switchInt(const true) -> [0: bb2, otherwise: bb1]; + + // CHECK:bb1: { + // CHECK: _0 = const 5_u32; + // CHECK: goto -> bb3; + + // CHECK:bb2: { + // CHECK: _0 = const 13_u32; + // CHECK: goto -> bb3; + + let a = Foo; + // This copies the struct in `a`. We want to ensure that we do track the contents of `a` + // because we need to read `b` later. + let b = a; + let c = b.1; + if c >= 2 { b.0 } else { 13 } +} + +fn main() { + // CHECK-LABEL: fn main( + foo(); +} + +// EMIT_MIR aggregate_copy.foo.DataflowConstProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff index 53663c6476bd..79ea55617481 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff @@ -76,13 +76,9 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 80 01 __ __ __ │ .....░░░ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 03 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff index 34feb2a64062..bd22c50dd8fc 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff @@ -76,13 +76,9 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 80 01 __ __ __ │ .....░░░ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 03 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs index a73693464f95..f5a6cdb2c8d3 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.rs +++ b/tests/mir-opt/dataflow-const-prop/checked.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: DataflowConstProp -//@ compile-flags: -Coverflow-checks=on +//@ compile-flags: -Coverflow-checks=on -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR checked.main.DataflowConstProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 8005bc23cf69..4097e060f4d4 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -94,15 +94,9 @@ } } - ALLOC2 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC2 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index 42b1be32387c..ff44d0df5e3e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -98,15 +98,9 @@ } } - ALLOC2 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC2 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 7b57b0db50c9..3662c3b59d27 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -94,15 +94,9 @@ } } - ALLOC2 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC2 (size: 16, align: 8) { .. } - ALLOC1 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC1 (size: 16, align: 8) { .. } - ALLOC0 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 2e75a63e2905..68dee57dee9e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -98,15 +98,9 @@ } } - ALLOC2 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC2 (size: 16, align: 8) { .. } - ALLOC1 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC1 (size: 16, align: 8) { .. } - ALLOC0 (size: 16, align: 8) { - 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - } + ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index 06011f9d7596..9d96e895c8aa 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -102,17 +102,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; } -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index eb4a3ffd91d2..0bdff584b01e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -106,17 +106,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; } -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 01 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index a7cc243e548e..99e96fe5d70f 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -102,17 +102,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; } -+ } -+ -+ ALLOC2 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC2 (size: 16, align: 8) { .. } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index c905a48862ca..5eefabeac386 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -106,17 +106,11 @@ _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; } -+ } -+ -+ ALLOC2 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC2 (size: 16, align: 8) { .. } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs index 3a0cbac328cb..087bd7a18572 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs @@ -1,5 +1,5 @@ //@ test-mir-pass: DataflowConstProp -//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline +//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index 946cfa4c76c0..37304e3a270e 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(custom_mir, core_intrinsics, rustc_attrs)] diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff index 89ed26f065b2..a64dda0d06c4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff @@ -60,9 +60,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff index 89ed26f065b2..a64dda0d06c4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff @@ -60,9 +60,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index fe8ed0114897..b4d14f25fe2a 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {ALLOC1: &E}; + _2 = const {ALLOC0: &E}; - _1 = (*_2); + _1 = const E::V1(0_i32); StorageDead(_2); @@ -79,7 +79,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {ALLOC2: &&E}; + _8 = const {ALLOC1: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -111,21 +111,14 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC3 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (static: RC, size: 4, align: 4) { .. } - ALLOC2 (static: RC, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ - } +- ALLOC2 (size: 8, align: 4) { .. } ++ ALLOC3 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 04 00 00 00 │ ........ - } - - ALLOC1 (static: statics::C, size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (static: statics::C, size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index df3a989d09eb..57d02b87d136 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {ALLOC1: &E}; + _2 = const {ALLOC0: &E}; - _1 = (*_2); + _1 = const E::V1(0_i32); StorageDead(_2); @@ -79,7 +79,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {ALLOC2: &&E}; + _8 = const {ALLOC1: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -111,21 +111,14 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 8, align: 4) { .. } + -+ ALLOC3 (size: 8, align: 4) { -+ 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC1 (static: RC, size: 8, align: 8) { .. } - ALLOC2 (static: RC, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ - } +- ALLOC2 (size: 8, align: 4) { .. } ++ ALLOC3 (size: 8, align: 4) { .. } - ALLOC0 (size: 8, align: 4) { - 01 00 00 00 04 00 00 00 │ ........ - } - - ALLOC1 (static: statics::C, size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ - } + ALLOC0 (static: statics::C, size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index f674169e28b2..5e89382ea8f4 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -106,13 +106,12 @@ - _7 = (_10.0: f32); + _7 = const 4f32; StorageLive(_8); -- _8 = (_10.1: std::option::Option); -+ _8 = const Option::::Some(S(1_i32)); + _8 = (_10.1: std::option::Option); StorageLive(_9); _9 = (_10.2: &[f32]); StorageDead(_10); StorageLive(_14); - _14 = const {ALLOC4: &&SmallStruct}; + _14 = const {ALLOC0: &&SmallStruct}; _31 = deref_copy (*_14); StorageLive(_11); _32 = deref_copy (*_14); @@ -149,7 +148,7 @@ _21 = (_22.2: &[f32]); StorageDead(_22); StorageLive(_26); - _26 = const {ALLOC5: &&BigStruct}; + _26 = const {ALLOC1: &&BigStruct}; _35 = deref_copy (*_26); StorageLive(_23); _36 = deref_copy (*_26); @@ -157,8 +156,7 @@ + _23 = const 82f32; StorageLive(_24); _37 = deref_copy (*_26); -- _24 = ((*_37).1: std::option::Option); -+ _24 = const Option::::Some(S(35_i32)); + _24 = ((*_37).1: std::option::Option); StorageLive(_25); _38 = deref_copy (*_26); _25 = ((*_38).2: &[f32]); @@ -168,12 +166,11 @@ - _28 = _23; + _28 = const 82f32; StorageLive(_29); -- _29 = _24; -+ _29 = const Option::::Some(S(35_i32)); + _29 = _24; StorageLive(_30); _30 = _25; - _27 = BigStruct(move _28, move _29, move _30); -+ _27 = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move _30); ++ _27 = BigStruct(const 82f32, move _29, move _30); StorageDead(_30); StorageDead(_29); StorageDead(_28); @@ -197,51 +194,23 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 4, align: 4) { .. } + -+ ALLOC6 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC7 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC8 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC9 (size: 8, align: 4) { -+ 01 00 00 00 01 00 00 00 │ ........ -+ } -+ -+ ALLOC10 (size: 4, align: 4) { -+ 01 00 00 00 │ .... - } + ALLOC1 (static: BIG_STAT, size: 4, align: 4) { .. } - ALLOC5 (static: BIG_STAT, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ - } +- ALLOC2 (size: 20, align: 4) { .. } ++ ALLOC3 (size: 20, align: 4) { .. } - ALLOC0 (size: 20, align: 4) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼.... - 0x10 │ 00 00 a4 42 │ ...B - } +- ALLOC3 (size: 8, align: 4) { .. } ++ ALLOC4 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 00 00 34 42 00 00 90 42 │ ..4B...B - } + ALLOC0 (static: SMALL_STAT, size: 4, align: 4) { .. } - ALLOC4 (static: SMALL_STAT, size: 4, align: 4) { - ╾ALLOC2╼ │ ╾──╼ - } +- ALLOC4 (size: 20, align: 4) { .. } ++ ALLOC5 (size: 20, align: 4) { .. } - ALLOC2 (size: 20, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 10 41 │ ...A - } - - ALLOC3 (size: 4, align: 4) { - 00 00 50 41 │ ..PA - } +- ALLOC5 (size: 4, align: 4) { .. } ++ ALLOC6 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index c2608190a6b9..a707d7e5e76e 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -106,13 +106,12 @@ - _7 = (_10.0: f32); + _7 = const 4f32; StorageLive(_8); -- _8 = (_10.1: std::option::Option); -+ _8 = const Option::::Some(S(1_i32)); + _8 = (_10.1: std::option::Option); StorageLive(_9); _9 = (_10.2: &[f32]); StorageDead(_10); StorageLive(_14); - _14 = const {ALLOC4: &&SmallStruct}; + _14 = const {ALLOC0: &&SmallStruct}; _31 = deref_copy (*_14); StorageLive(_11); _32 = deref_copy (*_14); @@ -149,7 +148,7 @@ _21 = (_22.2: &[f32]); StorageDead(_22); StorageLive(_26); - _26 = const {ALLOC5: &&BigStruct}; + _26 = const {ALLOC1: &&BigStruct}; _35 = deref_copy (*_26); StorageLive(_23); _36 = deref_copy (*_26); @@ -157,8 +156,7 @@ + _23 = const 82f32; StorageLive(_24); _37 = deref_copy (*_26); -- _24 = ((*_37).1: std::option::Option); -+ _24 = const Option::::Some(S(35_i32)); + _24 = ((*_37).1: std::option::Option); StorageLive(_25); _38 = deref_copy (*_26); _25 = ((*_38).2: &[f32]); @@ -168,12 +166,11 @@ - _28 = _23; + _28 = const 82f32; StorageLive(_29); -- _29 = _24; -+ _29 = const Option::::Some(S(35_i32)); + _29 = _24; StorageLive(_30); _30 = _25; - _27 = BigStruct(move _28, move _29, move _30); -+ _27 = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move _30); ++ _27 = BigStruct(const 82f32, move _29, move _30); StorageDead(_30); StorageDead(_29); StorageDead(_28); @@ -197,51 +194,23 @@ StorageDead(_1); return; } -+ } + } + ++ ALLOC2 (size: 4, align: 4) { .. } + -+ ALLOC6 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC7 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC8 (size: 8, align: 4) { -+ 01 00 00 00 23 00 00 00 │ ....#... -+ } -+ -+ ALLOC9 (size: 8, align: 4) { -+ 01 00 00 00 01 00 00 00 │ ........ -+ } -+ -+ ALLOC10 (size: 4, align: 4) { -+ 01 00 00 00 │ .... - } + ALLOC1 (static: BIG_STAT, size: 8, align: 8) { .. } - ALLOC5 (static: BIG_STAT, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ - } +- ALLOC2 (size: 32, align: 8) { .. } ++ ALLOC3 (size: 32, align: 8) { .. } - ALLOC0 (size: 32, align: 8) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼ - 0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░ - } +- ALLOC3 (size: 8, align: 4) { .. } ++ ALLOC4 (size: 8, align: 4) { .. } - ALLOC1 (size: 8, align: 4) { - 00 00 34 42 00 00 90 42 │ ..4B...B - } + ALLOC0 (static: SMALL_STAT, size: 8, align: 8) { .. } - ALLOC4 (static: SMALL_STAT, size: 8, align: 8) { - ╾ALLOC2╼ │ ╾──────╼ - } +- ALLOC4 (size: 32, align: 8) { .. } ++ ALLOC5 (size: 32, align: 8) { .. } - ALLOC2 (size: 32, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼ - 0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░ - } - - ALLOC3 (size: 4, align: 4) { - 00 00 50 41 │ ..PA - } +- ALLOC5 (size: 4, align: 4) { .. } ++ ALLOC6 (size: 4, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index eed782c9036b..89ad1b870294 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH #[derive(Copy, Clone)] @@ -45,7 +46,7 @@ fn main() { const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); // CHECK: [[a1]] = const 4f32; - // CHECK: [[b1]] = const Option::::Some(S(1_i32)); + // CHECK: [[b1]] = ({{_.*}}.1: std::option::Option); // CHECK: [[c1]] = ({{_.*}}.2: &[f32]); let SmallStruct(a1, b1, c1) = SMALL_VAL; @@ -68,12 +69,12 @@ fn main() { static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]); // CHECK: [[a4]] = const 82f32; - // CHECK: [[b4]] = const Option::::Some(S(35_i32)); + // CHECK: [[b4]] = ((*{{_.*}}).1: std::option::Option); // CHECK: [[c4]] = ((*{{_.*}}).2: &[f32]); let BigStruct(a4, b4, c4) = *BIG_STAT; // We arbitrarily limit the size of synthetized values to 4 pointers. // `BigStruct` can be read, but we will keep a MIR aggregate for this. - // CHECK: [[bs]] = BigStruct(const 82f32, const Option::::Some(S(35_i32)), move {{_.*}}); + // CHECK: [[bs]] = BigStruct(const 82f32, move {{.*}}, move {{_.*}}); let bs = BigStruct(a4, b4, c4); } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff index 44dd40174092..a023243ad9da 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff @@ -7,10 +7,20 @@ bb0: { StorageLive(_1); - _1 = Less; - _0 = move _1 as i8 (Transmute); +- _1 = Less; +- _0 = move _1 as i8 (Transmute); ++ _1 = const Less; ++ _0 = const std::cmp::Ordering::Less as i8 (Transmute); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 1, align: 1) { ++ ff │ . ++ } ++ ++ ALLOC1 (size: 1, align: 1) { ++ ff │ . } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff index 44dd40174092..a023243ad9da 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff @@ -7,10 +7,20 @@ bb0: { StorageLive(_1); - _1 = Less; - _0 = move _1 as i8 (Transmute); +- _1 = Less; +- _0 = move _1 as i8 (Transmute); ++ _1 = const Less; ++ _0 = const std::cmp::Ordering::Less as i8 (Transmute); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 1, align: 1) { ++ ff │ . ++ } ++ ++ ALLOC1 (size: 1, align: 1) { ++ ff │ . } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff index f5723cac7d9c..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff @@ -92,21 +92,13 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC3 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff index f5723cac7d9c..e4031b65caaf 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff @@ -92,21 +92,13 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC1 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC2 (size: 8, align: 4) { -+ 02 00 00 00 03 00 00 00 │ ........ -+ } -+ -+ ALLOC3 (size: 8, align: 4) { -+ 01 00 00 00 02 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 8, align: 4) { .. } ++ ++ ALLOC2 (size: 8, align: 4) { .. } ++ ++ ALLOC3 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index d624e21f21ac..19b675770abe 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR tuple.main.DataflowConstProp.diff diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff index 938b9bb14ade..3a5762e4f3d1 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff @@ -22,59 +22,55 @@ bb1: { StorageDead(_3); - _7 = Len((*_2)); - _8 = const 4_usize; - _9 = Ge(move _7, move _8); -- switchInt(move _9) -> [0: bb2, otherwise: bb7]; -+ switchInt(move _9) -> [0: bb2, otherwise: bb6]; + _4 = Len((*_2)); + _5 = const 4_usize; + _6 = Ge(move _4, move _5); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _4 = Len((*_2)); - _5 = const 3_usize; - _6 = Ge(move _4, move _5); -- switchInt(move _6) -> [0: bb3, otherwise: bb4]; -+ switchInt(move _6) -> [0: bb10, otherwise: bb3]; + _7 = Len((*_2)); + _8 = const 3_usize; + _9 = Ge(move _7, move _8); +- switchInt(move _9) -> [0: bb7, otherwise: bb8]; ++ switchInt(move _9) -> [0: bb10, otherwise: bb7]; } bb3: { -- _0 = const false; -- goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10]; + switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2]; } bb4: { -- switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3]; -+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10]; + switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2]; } bb5: { -- switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2]; } bb6: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3]; -+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2]; - } - - bb7: { -- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2]; -+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2]; - } - - bb8: { -- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2]; -+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2]; - } - - bb9: { -- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; + switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; } + bb7: { +- _0 = const false; +- goto -> bb14; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; + } + + bb8: { +- switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; + } + + bb9: { +- switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; ++ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + } + bb10: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; - } - - bb11: { diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff index ce89694076b0..21b197d2f270 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff @@ -22,59 +22,55 @@ bb1: { StorageDead(_3); - _7 = Len((*_2)); - _8 = const 4_usize; - _9 = Ge(move _7, move _8); -- switchInt(move _9) -> [0: bb2, otherwise: bb7]; -+ switchInt(move _9) -> [0: bb2, otherwise: bb6]; + _4 = Len((*_2)); + _5 = const 4_usize; + _6 = Ge(move _4, move _5); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _4 = Len((*_2)); - _5 = const 3_usize; - _6 = Ge(move _4, move _5); -- switchInt(move _6) -> [0: bb3, otherwise: bb4]; -+ switchInt(move _6) -> [0: bb10, otherwise: bb3]; + _7 = Len((*_2)); + _8 = const 3_usize; + _9 = Ge(move _7, move _8); +- switchInt(move _9) -> [0: bb7, otherwise: bb8]; ++ switchInt(move _9) -> [0: bb10, otherwise: bb7]; } bb3: { -- _0 = const false; -- goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10]; + switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2]; } bb4: { -- switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3]; -+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10]; + switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2]; } bb5: { -- switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2]; } bb6: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3]; -+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2]; - } - - bb7: { -- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2]; -+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2]; - } - - bb8: { -- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2]; -+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2]; - } - - bb9: { -- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; + switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; } + bb7: { +- _0 = const false; +- goto -> bb14; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; + } + + bb8: { +- switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; + } + + bb9: { +- switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; ++ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + } + bb10: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; - } - - bb11: { diff --git a/tests/mir-opt/dest-prop/branch.rs b/tests/mir-opt/dest-prop/branch.rs index 481d4130c7b5..0ac79ee4ec29 100644 --- a/tests/mir-opt/dest-prop/branch.rs +++ b/tests/mir-opt/dest-prop/branch.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Tests that assignment in both branches of an `if` are eliminated. //@ test-mir-pass: DestinationPropagation @@ -12,6 +11,10 @@ fn cond() -> bool { // EMIT_MIR branch.foo.DestinationPropagation.diff fn foo() -> i32 { + // CHECK-LABEL: fn foo( + // CHECK: debug y => [[y:_.*]]; + // CHECK: [[y]] = val() + // CHECK-NOT: [[y]] = {{_.*}}; let x = val(); let y = if cond() { diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.rs b/tests/mir-opt/dest-prop/copy_propagation_arg.rs index db4969924ffb..084bd0544c17 100644 --- a/tests/mir-opt/dest-prop/copy_propagation_arg.rs +++ b/tests/mir-opt/dest-prop/copy_propagation_arg.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // Check that DestinationPropagation does not propagate an assignment to a function argument // (doing so can break usages of the original argument value) @@ -9,18 +8,29 @@ fn dummy(x: u8) -> u8 { // EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff fn foo(mut x: u8) { + // CHECK-LABEL: fn foo( + // CHECK: debug x => [[x:_.*]]; + // CHECK: dummy(move [[x]]) + // CHECK: [[x]] = move {{_.*}}; // calling `dummy` to make a use of `x` that copyprop cannot eliminate x = dummy(x); // this will assign a local to `x` } // EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff fn bar(mut x: u8) { + // CHECK-LABEL: fn bar( + // CHECK: debug x => [[x:_.*]]; + // CHECK: dummy(move [[x]]) + // CHECK: [[x]] = const 5_u8; dummy(x); x = 5; } // EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff fn baz(mut x: i32) -> i32 { + // CHECK-LABEL: fn baz( + // CHECK: debug x => [[x:_.*]]; + // CHECK-NOT: [[x]] = // self-assignment to a function argument should be eliminated x = x; x @@ -28,6 +38,12 @@ fn baz(mut x: i32) -> i32 { // EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff fn arg_src(mut x: i32) -> i32 { + // CHECK-LABEL: fn arg_src( + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + // CHECK: [[y]] = [[x]] + // CHECK: [[x]] = const 123_i32; + // CHECK-NOT: {{_.*}} = [[y]]; let y = x; x = 123; // Don't propagate this assignment to `y` y diff --git a/tests/mir-opt/dest-prop/cycle.rs b/tests/mir-opt/dest-prop/cycle.rs index e414daf20f2d..86b9b713fd00 100644 --- a/tests/mir-opt/dest-prop/cycle.rs +++ b/tests/mir-opt/dest-prop/cycle.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code. //@ test-mir-pass: DestinationPropagation @@ -8,6 +7,10 @@ fn val() -> i32 { // EMIT_MIR cycle.main.DestinationPropagation.diff fn main() { + // CHECK-LABEL: main( + // CHECK: debug x => [[x:_.*]]; + // CHECK: [[x]] = val() + // CHECK-NOT: [[x]] = {{_.*}}; let mut x = val(); let y = x; let z = y; diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.rs b/tests/mir-opt/dest-prop/dead_stores_79191.rs index 5c218a328f58..61060e4f8506 100644 --- a/tests/mir-opt/dest-prop/dead_stores_79191.rs +++ b/tests/mir-opt/dest-prop/dead_stores_79191.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ test-mir-pass: DestinationPropagation @@ -8,6 +7,13 @@ fn id(x: T) -> T { // EMIT_MIR dead_stores_79191.f.DestinationPropagation.after.mir fn f(mut a: usize) -> usize { + // CHECK-LABEL: fn f( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: [[b]] = [[a]]; + // CHECK: [[a]] = const 5_usize; + // CHECK: [[a]] = move [[b]]; + // CHECK: id::(move [[a]]) let b = a; a = 5; a = b; diff --git a/tests/mir-opt/dest-prop/dead_stores_better.rs b/tests/mir-opt/dest-prop/dead_stores_better.rs index 06445dc87031..d2b9fe057123 100644 --- a/tests/mir-opt/dest-prop/dead_stores_better.rs +++ b/tests/mir-opt/dest-prop/dead_stores_better.rs @@ -1,4 +1,3 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates // that that pass enables this one to do more optimizations. @@ -12,6 +11,13 @@ fn id(x: T) -> T { // EMIT_MIR dead_stores_better.f.DestinationPropagation.after.mir pub fn f(mut a: usize) -> usize { + // CHECK-LABEL: fn f( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: [[b]] = [[a]]; + // CHECK: [[a]] = const 5_usize; + // CHECK: [[a]] = move [[b]]; + // CHECK: id::(move [[a]]) let b = a; a = 5; a = b; diff --git a/tests/mir-opt/dest-prop/simple.rs b/tests/mir-opt/dest-prop/simple.rs index 8e5d6340e566..833d49b8c466 100644 --- a/tests/mir-opt/dest-prop/simple.rs +++ b/tests/mir-opt/dest-prop/simple.rs @@ -1,9 +1,15 @@ -// skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. //@ test-mir-pass: DestinationPropagation // EMIT_MIR simple.nrvo.DestinationPropagation.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { + // CHECK-LABEL: fn nrvo( + // CHECK: debug init => [[init:_.*]]; + // CHECK: debug buf => [[buf:_.*]]; + // CHECK: [[buf]] = [const 0_u8; 1024]; + // CHECK-NOT: {{_.*}} = [[init]]; + // CHECK: move [[init]](move {{_.*}}) + // CHECK: {{_.*}} = [[buf]] let mut buf = [0; 1024]; init(&mut buf); buf diff --git a/tests/mir-opt/dest-prop/union.rs b/tests/mir-opt/dest-prop/union.rs index 66fadd847122..4e6fb71bf75e 100644 --- a/tests/mir-opt/dest-prop/union.rs +++ b/tests/mir-opt/dest-prop/union.rs @@ -8,6 +8,8 @@ fn val() -> u32 { // EMIT_MIR union.main.DestinationPropagation.diff fn main() { + // CHECK-LABEL: fn args( + // CHECK: {{_.*}} = Un { us: const 1_u32 }; union Un { us: u32, } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff index 775a60f1c960..085c55caaa03 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 02 00 00 00 05 20 00 00 │ ..... .. } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff index c4b57579943d..798b7c10fe8d 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 02 00 00 00 00 00 00 00 05 20 00 00 00 00 00 00 │ ......... ...... } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs index 2cc5df84d6b5..e42be8ac06dc 100644 --- a/tests/mir-opt/enum_opt.rs +++ b/tests/mir-opt/enum_opt.rs @@ -1,7 +1,7 @@ // skip-filecheck //@ test-mir-pass: EnumSizeOpt // EMIT_MIR_FOR_EACH_BIT_WIDTH -//@ compile-flags: -Zunsound-mir-opts +//@ compile-flags: -Zunsound-mir-opts -Zdump-mir-exclude-alloc-bytes #![feature(arbitrary_enum_discriminant, repr128)] diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff index f7d0d1fb56c3..a04829af4b53 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 05 20 00 00 01 00 00 00 │ . ...... } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff index 15f1bd0df51a..f5521a1e22a4 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff @@ -64,9 +64,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 05 20 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ . .............. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff index 5bf22af6ae83..0e3f2459fae3 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff @@ -140,9 +140,7 @@ _0 = const (); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff index 18d2029e4450..2873d7ef0ab1 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff @@ -140,9 +140,7 @@ _0 = const (); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index 0c49e706c9ec..b5c0cee78468 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; + let _7: {closure@$DIR/gvn.rs:615:19: 615:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; +- _7 = {closure@$DIR/gvn.rs:615:19: 615:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index e5f865b74b9f..7bc6573c13d4 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21}; + let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:614:19: 614:21}; + let _7: {closure@$DIR/gvn.rs:615:19: 615:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:614:19: 614:21}; +- _7 = {closure@$DIR/gvn.rs:615:19: 615:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff index f853942bbb66..e84f91e495d9 100644 --- a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff @@ -13,7 +13,5 @@ } } - ALLOC0 (static: A, size: 2, align: 1) { - 00 __ │ .░ - } + ALLOC0 (static: A, size: 2, align: 1) { .. } diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff index f853942bbb66..e84f91e495d9 100644 --- a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff @@ -13,7 +13,5 @@ } } - ALLOC0 (static: A, size: 2, align: 1) { - 00 __ │ .░ - } + ALLOC0 (static: A, size: 2, align: 1) { .. } diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index c7fae0bd0810..430f979fec71 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY //@ only-64bit diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff index 07c4c7663c15..3eed0473f7fc 100644 --- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff @@ -176,13 +176,9 @@ + nop; return; } -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff index df0f93f1077e..9a6e255a872e 100644 --- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff @@ -176,13 +176,9 @@ + nop; return; } -+ } -+ -+ ALLOC1 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ -+ } -+ -+ ALLOC0 (size: 16, align: 8) { -+ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } ++ ++ ALLOC1 (size: 16, align: 8) { .. } ++ ++ ALLOC0 (size: 16, align: 8) { .. } diff --git a/tests/mir-opt/issue_72181.bar.built.after.mir b/tests/mir-opt/issue_72181.bar.built.after.mir index 3ab9152f8bb6..b6cc7d221956 100644 --- a/tests/mir-opt/issue_72181.bar.built.after.mir +++ b/tests/mir-opt/issue_72181.bar.built.after.mir @@ -19,8 +19,4 @@ fn bar(_1: [(Never, u32); 1]) -> u32 { FakeRead(ForMatchedPlace(None), _1); unreachable; } - - bb2: { - goto -> bb1; - } } diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir index fa101512d729..89d351d5172c 100644 --- a/tests/mir-opt/issue_72181.main.built.after.mir +++ b/tests/mir-opt/issue_72181.main.built.after.mir @@ -20,7 +20,7 @@ fn main() -> () { bb0: { StorageLive(_1); - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb7]; + _1 = std::mem::size_of::() -> [return: bb1, unwind: bb5]; } bb1: { @@ -40,7 +40,7 @@ fn main() -> () { _6 = const 0_usize; _7 = Len(_2); _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb4, unwind: bb7]; + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb5]; } bb2: { @@ -49,10 +49,6 @@ fn main() -> () { } bb3: { - goto -> bb2; - } - - bb4: { _5 = (_2[_6].0: u64); PlaceMention(_5); StorageDead(_6); @@ -62,16 +58,12 @@ fn main() -> () { return; } - bb5: { + bb4: { FakeRead(ForMatchedPlace(None), _5); unreachable; } - bb6: { - goto -> bb5; - } - - bb7 (cleanup): { + bb5 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir index 674a4013fe77..89da9a801136 100644 --- a/tests/mir-opt/issue_72181_1.f.built.after.mir +++ b/tests/mir-opt/issue_72181_1.f.built.after.mir @@ -6,15 +6,11 @@ fn f(_1: Void) -> ! { bb0: { PlaceMention(_1); - goto -> bb1; - } - - bb1: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb2: { + bb1: { return; } } diff --git a/tests/mir-opt/issue_91633.bar.built.after.mir b/tests/mir-opt/issue_91633.bar.built.after.mir index 3dcdcab9dea3..53829588a1b3 100644 --- a/tests/mir-opt/issue_91633.bar.built.after.mir +++ b/tests/mir-opt/issue_91633.bar.built.after.mir @@ -12,7 +12,7 @@ fn bar(_1: Box<[T]>) -> () { StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb5]; + _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb4]; } bb1: { @@ -20,7 +20,7 @@ fn bar(_1: Box<[T]>) -> () { PlaceMention((*_2)); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb4, unwind: bb6]; + drop(_1) -> [return: bb3, unwind: bb5]; } bb2: { @@ -29,18 +29,14 @@ fn bar(_1: Box<[T]>) -> () { } bb3: { - goto -> bb2; - } - - bb4: { return; } - bb5 (cleanup): { - drop(_1) -> [return: bb6, unwind terminate(cleanup)]; + bb4 (cleanup): { + drop(_1) -> [return: bb5, unwind terminate(cleanup)]; } - bb6 (cleanup): { + bb5 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_91633.hey.built.after.mir b/tests/mir-opt/issue_91633.hey.built.after.mir index e782f4d1a23f..a537e509996d 100644 --- a/tests/mir-opt/issue_91633.hey.built.after.mir +++ b/tests/mir-opt/issue_91633.hey.built.after.mir @@ -14,7 +14,7 @@ fn hey(_1: &[T]) -> () { StorageLive(_3); StorageLive(_4); _4 = &(*_1); - _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb4]; + _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb3]; } bb1: { @@ -32,11 +32,7 @@ fn hey(_1: &[T]) -> () { unreachable; } - bb3: { - goto -> bb2; - } - - bb4 (cleanup): { + bb3 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index b7a054b5d540..72e7f4794f98 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; } bb2: { @@ -100,24 +100,20 @@ fn main() -> () { } bb3: { - goto -> bb2; + switchInt(move _10) -> [0: bb5, otherwise: bb4]; } bb4: { - switchInt(move _10) -> [0: bb6, otherwise: bb5]; + StorageDead(_12); + StorageDead(_11); + goto -> bb9; } bb5: { - StorageDead(_12); - StorageDead(_11); - goto -> bb10; + goto -> bb6; } bb6: { - goto -> bb7; - } - - bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -136,10 +132,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; } - bb8: { + bb7: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -151,23 +147,23 @@ fn main() -> () { unreachable; } + bb8: { + goto -> bb10; + } + bb9: { - goto -> bb11; + _1 = const (); + goto -> bb10; } bb10: { - _1 = const (); + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); goto -> bb11; } bb11: { - StorageDead(_10); - StorageDead(_9); - StorageDead(_8); - goto -> bb12; - } - - bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -177,10 +173,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; } - bb13: { + bb12: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -199,33 +195,29 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; } - bb14: { + bb13: { FakeRead(ForMatchedPlace(None), _23); unreachable; } + bb14: { + switchInt(move _30) -> [0: bb16, otherwise: bb15]; + } + bb15: { - goto -> bb14; + StorageDead(_32); + StorageDead(_31); + goto -> bb20; } bb16: { - switchInt(move _30) -> [0: bb18, otherwise: bb17]; + goto -> bb17; } bb17: { - StorageDead(_32); - StorageDead(_31); - goto -> bb22; - } - - bb18: { - goto -> bb19; - } - - bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -244,10 +236,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; } - bb20: { + bb18: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -259,23 +251,23 @@ fn main() -> () { unreachable; } - bb21: { - goto -> bb23; + bb19: { + goto -> bb21; } - bb22: { + bb20: { _22 = const (); - goto -> bb23; + goto -> bb21; } - bb23: { + bb21: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb24; + goto -> bb22; } - bb24: { + bb22: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -284,7 +276,7 @@ fn main() -> () { return; } - bb25 (cleanup): { + bb23 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index b7a054b5d540..72e7f4794f98 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; } bb2: { @@ -100,24 +100,20 @@ fn main() -> () { } bb3: { - goto -> bb2; + switchInt(move _10) -> [0: bb5, otherwise: bb4]; } bb4: { - switchInt(move _10) -> [0: bb6, otherwise: bb5]; + StorageDead(_12); + StorageDead(_11); + goto -> bb9; } bb5: { - StorageDead(_12); - StorageDead(_11); - goto -> bb10; + goto -> bb6; } bb6: { - goto -> bb7; - } - - bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -136,10 +132,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; } - bb8: { + bb7: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -151,23 +147,23 @@ fn main() -> () { unreachable; } + bb8: { + goto -> bb10; + } + bb9: { - goto -> bb11; + _1 = const (); + goto -> bb10; } bb10: { - _1 = const (); + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); goto -> bb11; } bb11: { - StorageDead(_10); - StorageDead(_9); - StorageDead(_8); - goto -> bb12; - } - - bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -177,10 +173,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; } - bb13: { + bb12: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -199,33 +195,29 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; } - bb14: { + bb13: { FakeRead(ForMatchedPlace(None), _23); unreachable; } + bb14: { + switchInt(move _30) -> [0: bb16, otherwise: bb15]; + } + bb15: { - goto -> bb14; + StorageDead(_32); + StorageDead(_31); + goto -> bb20; } bb16: { - switchInt(move _30) -> [0: bb18, otherwise: bb17]; + goto -> bb17; } bb17: { - StorageDead(_32); - StorageDead(_31); - goto -> bb22; - } - - bb18: { - goto -> bb19; - } - - bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -244,10 +236,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; } - bb20: { + bb18: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -259,23 +251,23 @@ fn main() -> () { unreachable; } - bb21: { - goto -> bb23; + bb19: { + goto -> bb21; } - bb22: { + bb20: { _22 = const (); - goto -> bb23; + goto -> bb21; } - bb23: { + bb21: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb24; + goto -> bb22; } - bb24: { + bb22: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -284,7 +276,7 @@ fn main() -> () { return; } - bb25 (cleanup): { + bb23 (cleanup): { resume; } } diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff new file mode 100644 index 000000000000..0c8e04a1e74d --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff @@ -0,0 +1,56 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff new file mode 100644 index 000000000000..0c8e04a1e74d --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff @@ -0,0 +1,56 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; ++ goto -> bb2; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index b4c133716800..de290c1ef447 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -506,6 +506,21 @@ fn assume(a: u8, b: bool) -> u8 { } } +/// Verify that jump threading succeeds seeing through copies of aggregates. +fn aggregate_copy() -> u32 { + // CHECK-LABEL: fn aggregate_copy( + // CHECK-NOT: switchInt( + + const Foo: (u32, u32) = (5, 3); + + let a = Foo; + // This copies a tuple, we want to ensure that the threading condition on `b.1` propagates to a + // condition on `a.1`. + let b = a; + let c = b.1; + if c == 2 { b.0 } else { 13 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -534,3 +549,4 @@ fn main() { // EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff // EMIT_MIR jump_threading.aggregate.JumpThreading.diff // EMIT_MIR jump_threading.assume.JumpThreading.diff +// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 209f0d09c294..4f29e5244d7c 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -32,25 +32,33 @@ bb0: { PlaceMention(_2); -- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; +- switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } bb1: { -- switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; +- switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- falseEdge -> [real: bb8, imaginary: bb1]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; +- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5]; - } - - bb4: { +- falseEdge -> [real: bb13, imaginary: bb3]; +- } +- +- bb5: { +- falseEdge -> [real: bb20, imaginary: bb6]; +- } +- +- bb6: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,14 +67,6 @@ + goto -> bb16; } -- bb5: { -- falseEdge -> [real: bb13, imaginary: bb2]; -- } -- -- bb6: { -- falseEdge -> [real: bb8, imaginary: bb1]; -- } -- - bb7: { + bb4: { _0 = const 1_i32; @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb2]; +- falseEdge -> [real: bb3, imaginary: bb3]; + goto -> bb2; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 209f0d09c294..4f29e5244d7c 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -32,25 +32,33 @@ bb0: { PlaceMention(_2); -- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; +- switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } bb1: { -- switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; +- switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- falseEdge -> [real: bb8, imaginary: bb1]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; +- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5]; - } - - bb4: { +- falseEdge -> [real: bb13, imaginary: bb3]; +- } +- +- bb5: { +- falseEdge -> [real: bb20, imaginary: bb6]; +- } +- +- bb6: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,14 +67,6 @@ + goto -> bb16; } -- bb5: { -- falseEdge -> [real: bb13, imaginary: bb2]; -- } -- -- bb6: { -- falseEdge -> [real: bb8, imaginary: bb1]; -- } -- - bb7: { + bb4: { _0 = const 1_i32; @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb2]; +- falseEdge -> [real: bb3, imaginary: bb3]; + goto -> bb2; } diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir index 56edd38a6da4..e357e785e33e 100644 --- a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir @@ -18,24 +18,24 @@ fn shortcut_second_or() -> () { _1 = (move _2, const 0_i32); StorageDead(_2); PlaceMention(_1); - switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb4, otherwise: bb2]; + switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb2, otherwise: bb1]; } bb1: { + switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb4, otherwise: bb3]; + } + + bb2: { + switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb3]; + } + + bb3: { _0 = const (); goto -> bb14; } - bb2: { - switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb3, otherwise: bb1]; - } - - bb3: { - switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1]; - } - bb4: { - switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1]; + switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb3]; } bb5: { @@ -43,7 +43,7 @@ fn shortcut_second_or() -> () { } bb6: { - falseEdge -> [real: bb11, imaginary: bb2]; + falseEdge -> [real: bb11, imaginary: bb1]; } bb7: { @@ -51,7 +51,7 @@ fn shortcut_second_or() -> () { } bb8: { - falseEdge -> [real: bb13, imaginary: bb1]; + falseEdge -> [real: bb13, imaginary: bb3]; } bb9: { diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff index 2f34a62b3d13..45b8d89c0f4f 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index da7add371a5b..e6ee1e6f9a34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff index 2f34a62b3d13..45b8d89c0f4f 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index da7add371a5b..e6ee1e6f9a34 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -61,9 +61,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 04 00 00 00 00 __ __ __ │ .....░░░ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs index de5e2d5c3121..44b4b0ad888a 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs @@ -1,6 +1,6 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ compile-flags: -C overflow-checks=on +//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes struct Point { x: u32, diff --git a/tests/run-make/env-dep-info/Makefile b/tests/run-make/env-dep-info/Makefile deleted file mode 100644 index bc0ffc2df1e0..000000000000 --- a/tests/run-make/env-dep-info/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -include ../tools.mk - -# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` -# instead of hardcoding them everywhere they're needed. -ifeq ($(IS_MUSL_HOST),1) -ADDITIONAL_ARGS := $(RUSTFLAGS) -endif - -all: - EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs - $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d - $(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d - # Proc macro - $(BARE_RUSTC) $(ADDITIONAL_ARGS) --out-dir $(TMPDIR) macro_def.rs - EXISTING_PROC_MACRO_ENV=1 $(RUSTC) --emit dep-info macro_use.rs - $(CGREP) "# env-dep:EXISTING_PROC_MACRO_ENV=1" < $(TMPDIR)/macro_use.d - $(CGREP) "# env-dep:NONEXISTENT_PROC_MACEO_ENV" < $(TMPDIR)/macro_use.d diff --git a/tests/run-make/env-dep-info/correct_macro.d b/tests/run-make/env-dep-info/correct_macro.d new file mode 100644 index 000000000000..edfe0e632024 --- /dev/null +++ b/tests/run-make/env-dep-info/correct_macro.d @@ -0,0 +1,6 @@ +macro_use.d: macro_use.rs + +macro_use.rs: + +# env-dep:EXISTING_PROC_MACRO_ENV=1 +# env-dep:NONEXISTENT_PROC_MACEO_ENV diff --git a/tests/run-make/env-dep-info/correct_main.d b/tests/run-make/env-dep-info/correct_main.d new file mode 100644 index 000000000000..ef89729841d8 --- /dev/null +++ b/tests/run-make/env-dep-info/correct_main.d @@ -0,0 +1,8 @@ +main.d: main.rs + +main.rs: + +# env-dep:ESCAPE\nESCAPE\\ +# env-dep:EXISTING_ENV=1 +# env-dep:EXISTING_OPT_ENV=1 +# env-dep:NONEXISTENT_OPT_ENV diff --git a/tests/run-make/env-dep-info/rmake.rs b/tests/run-make/env-dep-info/rmake.rs new file mode 100644 index 000000000000..5b51a5476f49 --- /dev/null +++ b/tests/run-make/env-dep-info/rmake.rs @@ -0,0 +1,21 @@ +// Inside dep-info emit files, #71858 made it so all accessed environment +// variables are usefully printed. This test checks that this feature works +// as intended by checking if the environment variables used in compilation +// appear in the output dep-info files. +// See https://github.com/rust-lang/rust/issues/40364 + +use run_make_support::{diff, rustc}; + +fn main() { + rustc() + .env("EXISTING_ENV", "1") + .env("EXISTING_OPT_ENV", "1") + .emit("dep-info") + .input("main.rs") + .run(); + diff().expected_file("correct_main.d").actual_file("main.d").run(); + // Procedural macro + rustc().input("macro_def.rs").run(); + rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run(); + diff().expected_file("correct_macro.d").actual_file("macro_use.d").run(); +} diff --git a/tests/run-make/extra-filename-with-temp-outputs/Makefile b/tests/run-make/extra-filename-with-temp-outputs/Makefile deleted file mode 100644 index 64745bef5b86..000000000000 --- a/tests/run-make/extra-filename-with-temp-outputs/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) -C extra-filename=bar foo.rs -C save-temps - rm $(TMPDIR)/foobar.foo*0.rcgu.o - rm $(TMPDIR)/$(call BIN,foobar) diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs new file mode 100644 index 000000000000..c39e397a7cb3 --- /dev/null +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -0,0 +1,21 @@ +// In order to prevent temporary files from overwriting each other in parallel +// compilation, rustc was changed to mix an extra filename with temporary +// outputs. However, as this is a similar behavior with the codegen flag +// -C extra-filename, this test checks that the manually passed flag +// is not overwritten by this feature, and that the output files +// are named as expected. +// See https://github.com/rust-lang/rust/pull/15686 + +use run_make_support::{ + bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files, +}; + +fn main() { + rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run(); + let object_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o") + }); + let object_file = object_files.get(0).unwrap(); + fs_wrapper::remove_file(object_file); + fs_wrapper::remove_file(bin_name("foobar")); +} diff --git a/tests/run-make/issue-83045/a.rs b/tests/run-make/ice-dep-cannot-find-dep/a.rs similarity index 100% rename from tests/run-make/issue-83045/a.rs rename to tests/run-make/ice-dep-cannot-find-dep/a.rs diff --git a/tests/run-make/issue-83045/b.rs b/tests/run-make/ice-dep-cannot-find-dep/b.rs similarity index 100% rename from tests/run-make/issue-83045/b.rs rename to tests/run-make/ice-dep-cannot-find-dep/b.rs diff --git a/tests/run-make/issue-83045/c.rs b/tests/run-make/ice-dep-cannot-find-dep/c.rs similarity index 100% rename from tests/run-make/issue-83045/c.rs rename to tests/run-make/ice-dep-cannot-find-dep/c.rs diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs new file mode 100644 index 000000000000..33c755bddd7b --- /dev/null +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -0,0 +1,38 @@ +// This test case creates a situation where the crate loader would run +// into an ICE (internal compiler error) when confronted with an invalid setup where it cannot +// find the dependency of a direct dependency. +// +// The test case makes sure that the compiler produces the expected +// error message but does not ICE immediately after. +// +// See https://github.com/rust-lang/rust/issues/83045 + +//@ only-x86_64 +//@ only-linux +// Reason: This is a platform-independent issue, no need to waste time testing +// everywhere. + +// NOTE: We use `bare_rustc` below so that the compiler can't find liba.rlib +// If we used `rustc` the additional '-L rmake_out' option would allow rustc to +// actually find the crate. + +use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc}; + +fn main() { + rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run(); + rustc() + .crate_name("b") + .crate_type("rlib") + .extern_("a", rust_lib_name("a")) + .input("b.rs") + .arg("--verbose") + .run(); + bare_rustc() + .extern_("b", rust_lib_name("b")) + .crate_type("rlib") + .edition("2018") + .input("c.rs") + .run_fail() + .assert_stderr_contains("E0463") + .assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/issue-83045/Makefile b/tests/run-make/issue-83045/Makefile deleted file mode 100644 index b76e184b610c..000000000000 --- a/tests/run-make/issue-83045/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -include ../tools.mk - -# This test case creates a situation where the crate loader would run -# into an ICE when confronted with an invalid setup where it cannot -# find the dependency of a direct dependency. -# -# The test case makes sure that the compiler produces the expected -# error message but does not ICE immediately after. -# -# See https://github.com/rust-lang/rust/issues/83045 - -# This is a platform-independent issue, no need to waste time testing -# everywhere. -# only-x86_64 -# only-linux - -# NOTE: We use BARE_RUSTC below so that the compiler can't find liba.rlib -# If we used RUSTC the additional '-L TMPDIR' option would allow rustc to -# actually find the crate. -# -# We check that we get the expected error message -# But that we do not get an ICE - -all: - $(RUSTC) --crate-name=a --crate-type=rlib a.rs --verbose - $(RUSTC) --crate-name=b --crate-type=rlib --extern a=$(TMPDIR)/liba.rlib b.rs --verbose - $(BARE_RUSTC) --out-dir $(TMPDIR) \ - --extern b=$(TMPDIR)/libb.rlib \ - --crate-type=rlib \ - --edition=2018 \ - c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt - $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt diff --git a/tests/run-make/issue-85019-moved-src-dir/Makefile b/tests/run-make/issue-85019-moved-src-dir/Makefile deleted file mode 100644 index dec289058f93..000000000000 --- a/tests/run-make/issue-85019-moved-src-dir/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../tools.mk - -INCR=$(TMPDIR)/incr -FIRST_SRC=$(TMPDIR)/first_src -SECOND_SRC=$(TMPDIR)/second_src - -# ignore-none no-std is not supported -# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for 'std' - -# Tests that we don't get an ICE when the working directory -# (but not the build directory!) changes between compilation -# sessions - -all: - mkdir $(INCR) - # Build from 'FIRST_SRC' - mkdir $(FIRST_SRC) - cp my_lib.rs $(FIRST_SRC)/my_lib.rs - cp main.rs $(FIRST_SRC)/main.rs - cd $(FIRST_SRC) && \ - $(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \ - $(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET) - # Build from 'SECOND_SRC', keeping the output directory and incremental directory - # the same - mv $(FIRST_SRC) $(SECOND_SRC) - cd $(SECOND_SRC) && \ - $(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \ - $(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET) diff --git a/tests/run-make/issue-85019-moved-src-dir/main.rs b/tests/run-make/moved-src-dir-fingerprint-ice/main.rs similarity index 100% rename from tests/run-make/issue-85019-moved-src-dir/main.rs rename to tests/run-make/moved-src-dir-fingerprint-ice/main.rs diff --git a/tests/run-make/issue-85019-moved-src-dir/my_lib.rs b/tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs similarity index 100% rename from tests/run-make/issue-85019-moved-src-dir/my_lib.rs rename to tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs new file mode 100644 index 000000000000..c64260299892 --- /dev/null +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -0,0 +1,38 @@ +// A SourceFile created during compilation may have a relative +// path (e.g. if rustc itself is invoked with a relative path). +// When we write out crate metadata, we convert all relative paths +// to absolute paths using the current working directory. +// However, the working directory was previously not included in the crate hash. +// This meant that the crate metadata could change while the crate +// hash remained the same. Among other problems, this could cause a +// fingerprint mismatch ICE, since incremental compilation uses +// the crate metadata hash to determine if a foreign query is green. +// This test checks that we don't get an ICE when the working directory +// (but not the build directory!) changes between compilation +// sessions. +// See https://github.com/rust-lang/rust/issues/85019 + +//@ ignore-none +// Reason: no-std is not supported +//@ ignore-nvptx64-nvidia-cuda +// FIXME: can't find crate for 'std' + +use run_make_support::{fs_wrapper, rust_lib_name, rustc}; + +fn main() { + fs_wrapper::create_dir("incr"); + fs_wrapper::create_dir("first_src"); + fs_wrapper::create_dir("output"); + fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs"); + fs_wrapper::rename("main.rs", "first_src/main.rs"); + // Build from "first_src" + std::env::set_current_dir("first_src").unwrap(); + rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); + rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); + std::env::set_current_dir("..").unwrap(); + fs_wrapper::rename("first_src", "second_src"); + std::env::set_current_dir("second_src").unwrap(); + // Build from "second_src" - the output and incremental directory remain identical + rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); + rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); +} diff --git a/tests/run-make/rustc-macro-dep-files/Makefile b/tests/run-make/rustc-macro-dep-files/Makefile deleted file mode 100644 index 76d713c4bb3c..000000000000 --- a/tests/run-make/rustc-macro-dep-files/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` -# instead of hardcoding them everywhere they're needed. -ifeq ($(IS_MUSL_HOST),1) -ADDITIONAL_ARGS := $(RUSTFLAGS) -endif -all: - $(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR) - $(RUSTC) bar.rs --target $(TARGET) --emit dep-info - $(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d diff --git a/tests/run-make/rustc-macro-dep-files/correct.d b/tests/run-make/rustc-macro-dep-files/correct.d new file mode 100644 index 000000000000..8cb708fff61b --- /dev/null +++ b/tests/run-make/rustc-macro-dep-files/correct.d @@ -0,0 +1,3 @@ +bar.d: bar.rs + +bar.rs: diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs new file mode 100644 index 000000000000..bc02a04c9b8f --- /dev/null +++ b/tests/run-make/rustc-macro-dep-files/rmake.rs @@ -0,0 +1,14 @@ +// --emit dep-info used to print all macro-generated code it could +// find as if it was part of a nonexistent file named "proc-macro source", +// which is not a valid path. After this was fixed in #36776, this test checks +// that macro code is not falsely seen as coming from a different file in dep-info. +// See https://github.com/rust-lang/rust/issues/36625 + +use run_make_support::{diff, rustc, target}; + +fn main() { + rustc().input("foo.rs").run(); + rustc().input("bar.rs").target(target()).emit("dep-info").run(); + // The emitted file should not contain "proc-macro source". + diff().expected_file("correct.d").actual_file("bar.d").run(); +} diff --git a/tests/run-make/wasm-abi/foo.rs b/tests/run-make/wasm-abi/foo.rs deleted file mode 100644 index 0678eb3ff51a..000000000000 --- a/tests/run-make/wasm-abi/foo.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![crate_type = "cdylib"] -#![deny(warnings)] -#![feature(wasm_abi)] - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoI32 { - pub a: i32, - pub b: i32, -} - -#[no_mangle] -pub extern "wasm" fn return_two_i32() -> TwoI32 { - TwoI32 { a: 1, b: 2 } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoI64 { - pub a: i64, - pub b: i64, -} - -#[no_mangle] -pub extern "wasm" fn return_two_i64() -> TwoI64 { - TwoI64 { a: 3, b: 4 } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoF32 { - pub a: f32, - pub b: f32, -} - -#[no_mangle] -pub extern "wasm" fn return_two_f32() -> TwoF32 { - TwoF32 { a: 5., b: 6. } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct TwoF64 { - pub a: f64, - pub b: f64, -} - -#[no_mangle] -pub extern "wasm" fn return_two_f64() -> TwoF64 { - TwoF64 { a: 7., b: 8. } -} - -#[repr(C)] -#[derive(PartialEq, Debug)] -pub struct Mishmash { - pub a: f64, - pub b: f32, - pub c: i32, - pub d: i64, - pub e: TwoI32, -} - -#[no_mangle] -pub extern "wasm" fn return_mishmash() -> Mishmash { - Mishmash { a: 9., b: 10., c: 11, d: 12, e: TwoI32 { a: 13, b: 14 } } -} - -#[link(wasm_import_module = "host")] -extern "wasm" { - fn two_i32() -> TwoI32; - fn two_i64() -> TwoI64; - fn two_f32() -> TwoF32; - fn two_f64() -> TwoF64; - fn mishmash() -> Mishmash; -} - -#[no_mangle] -pub unsafe extern "C" fn call_imports() { - assert_eq!(two_i32(), TwoI32 { a: 100, b: 101 }); - assert_eq!(two_i64(), TwoI64 { a: 102, b: 103 }); - assert_eq!(two_f32(), TwoF32 { a: 104., b: 105. }); - assert_eq!(two_f64(), TwoF64 { a: 106., b: 107. }); - assert_eq!( - mishmash(), - Mishmash { a: 108., b: 109., c: 110, d: 111, e: TwoI32 { a: 112, b: 113 } } - ); -} diff --git a/tests/run-make/wasm-abi/host.wat b/tests/run-make/wasm-abi/host.wat deleted file mode 100644 index e87097ac8a14..000000000000 --- a/tests/run-make/wasm-abi/host.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - (func (export "two_i32") (result i32 i32) - i32.const 100 - i32.const 101) - (func (export "two_i64") (result i64 i64) - i64.const 102 - i64.const 103) - (func (export "two_f32") (result f32 f32) - f32.const 104 - f32.const 105) - (func (export "two_f64") (result f64 f64) - f64.const 106 - f64.const 107) - - (func (export "mishmash") (result f64 f32 i32 i64 i32 i32) - f64.const 108 - f32.const 109 - i32.const 110 - i64.const 111 - i32.const 112 - i32.const 113) -) diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs deleted file mode 100644 index ff12bcd536e7..000000000000 --- a/tests/run-make/wasm-abi/rmake.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ only-wasm32-wasip1 -//@ needs-wasmtime - -use run_make_support::{cmd, rustc}; -use std::path::Path; - -fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").run(); - - let file = Path::new("foo.wasm"); - - run(&file, "return_two_i32", "1\n2\n"); - run(&file, "return_two_i64", "3\n4\n"); - run(&file, "return_two_f32", "5\n6\n"); - run(&file, "return_two_f64", "7\n8\n"); - run(&file, "return_mishmash", "9\n10\n11\n12\n13\n14\n"); - run(&file, "call_imports", ""); -} - -fn run(file: &Path, method: &str, expected_output: &str) { - cmd("wasmtime") - .arg("run") - .arg("--preload=host=host.wat") - .arg("--invoke") - .arg(method) - .arg(file) - .run() - .assert_stdout_equals(expected_output); -} diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs new file mode 100644 index 000000000000..bf98868d1453 --- /dev/null +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -0,0 +1,6 @@ +#![feature(precise_capturing)] + +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\" +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\" +// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\" +pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout index e288f8dfce65..9eb8b391e780 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout @@ -9,9 +9,14 @@ error: expected item, found `;` --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12 | LL | struct S {}; // unexpected semicolon after struct def - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - struct S {}; // unexpected semicolon after struct def +LL + struct S {} // unexpected semicolon after struct def + | error: aborting due to 1 previous error diff --git a/tests/rustdoc/issue-102154.rs b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs similarity index 73% rename from tests/rustdoc/issue-102154.rs rename to tests/rustdoc-ui/ice-assoc-type-loop-102154.rs index b36f270806ff..68e22ce6ea15 100644 --- a/tests/rustdoc/issue-102154.rs +++ b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs @@ -1,3 +1,6 @@ +//@ check-pass +// https://github.com/rust-lang/rust/issues/102154 + trait A { type B; } diff --git a/tests/rustdoc/issue-100620.rs b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs similarity index 79% rename from tests/rustdoc/issue-100620.rs rename to tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs index 097666eb515d..e12b214410bc 100644 --- a/tests/rustdoc/issue-100620.rs +++ b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs @@ -1,3 +1,6 @@ +//@ check-pass +// https://github.com/rust-lang/rust/issues/100620 + pub trait Bar {} pub trait Qux {} diff --git a/tests/rustdoc/issue-100241.rs b/tests/rustdoc-ui/ice-unresolved-import-100241.rs similarity index 77% rename from tests/rustdoc/issue-100241.rs rename to tests/rustdoc-ui/ice-unresolved-import-100241.rs index e4c613dd2791..eef4b8355bfd 100644 --- a/tests/rustdoc/issue-100241.rs +++ b/tests/rustdoc-ui/ice-unresolved-import-100241.rs @@ -3,6 +3,8 @@ // Check that this isn't an ICE //@ should-fail +// https://github.com/rust-lang/rust/issues/100241 + mod foo { pub use inner::S; //~^ ERROR unresolved imports `inner`, `foo::S` diff --git a/tests/rustdoc/issue-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs similarity index 100% rename from tests/rustdoc/issue-108281.rs rename to tests/rustdoc/attributes-inlining-108281.rs diff --git a/tests/rustdoc/issue-101743-bold-tag.rs b/tests/rustdoc/bold-tag-101743.rs similarity index 100% rename from tests/rustdoc/issue-101743-bold-tag.rs rename to tests/rustdoc/bold-tag-101743.rs diff --git a/tests/rustdoc/issue-106421-not-internal.rs b/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs similarity index 66% rename from tests/rustdoc/issue-106421-not-internal.rs rename to tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs index f328a1036ebe..a85cfa78cdcd 100644 --- a/tests/rustdoc/issue-106421-not-internal.rs +++ b/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs @@ -2,7 +2,10 @@ //@ ignore-cross-compile // This is the version where a non-compiler-internal crate inlines a compiler-internal one. // In this case, the item shouldn't be documented, because regular users can't get at it. +// https://github.com/rust-lang/rust/issues/106421 +#![crate_name="bar"] + extern crate foo; -//@ !has issue_106421_not_internal/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +//@ !has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' pub use foo::FatalError; diff --git a/tests/rustdoc/issue-106421.rs b/tests/rustdoc/force-unstable-if-unmarked-106421.rs similarity index 53% rename from tests/rustdoc/issue-106421.rs rename to tests/rustdoc/force-unstable-if-unmarked-106421.rs index c2064c710907..aa88a569aef2 100644 --- a/tests/rustdoc/issue-106421.rs +++ b/tests/rustdoc/force-unstable-if-unmarked-106421.rs @@ -1,8 +1,10 @@ //@ aux-build:issue-106421-force-unstable.rs //@ ignore-cross-compile //@ compile-flags: -Zforce-unstable-if-unmarked +// https://github.com/rust-lang/rust/issues/106421 +#![crate_name="bar"] extern crate foo; -//@ has issue_106421/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +//@ has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' pub use foo::FatalError; diff --git a/tests/rustdoc/issue-105952.rs b/tests/rustdoc/ice-associated-const-equality-105952.rs similarity index 86% rename from tests/rustdoc/issue-105952.rs rename to tests/rustdoc/ice-associated-const-equality-105952.rs index 173efb82f4b9..1bcdfac73429 100644 --- a/tests/rustdoc/issue-105952.rs +++ b/tests/rustdoc/ice-associated-const-equality-105952.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/105952 #![crate_name = "foo"] #![feature(associated_const_equality)] diff --git a/tests/rustdoc/issue-107995.rs b/tests/rustdoc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/issue-107995.rs rename to tests/rustdoc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs new file mode 100644 index 000000000000..d1987a555c15 --- /dev/null +++ b/tests/rustdoc/impl-trait-precise-capturing.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] +#![feature(precise_capturing)] + +//@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>" +pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {} + +//@ has foo/fn.params.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>" +pub fn params<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + +//@ has foo/fn.none.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>" +pub fn none() -> impl Sized + use<> {} + +//@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized" +pub fn first() -> impl use<> + Sized {} diff --git a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/tests/rustdoc/inline-impl-through-glob-import-100204.rs similarity index 86% rename from tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs rename to tests/rustdoc/inline-impl-through-glob-import-100204.rs index 7f05e57ec09b..ba6ed4278716 100644 --- a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs +++ b/tests/rustdoc/inline-impl-through-glob-import-100204.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/100204 #![crate_name="second"] extern crate first; diff --git a/tests/rustdoc/issue-106142.rs b/tests/rustdoc/issue-106142.rs deleted file mode 100644 index 52adc5dbbf1a..000000000000 --- a/tests/rustdoc/issue-106142.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ has 'issue_106142/a/index.html' -//@ count 'issue_106142/a/index.html' '//ul[@class="item-table"]//li//a' 1 - -#![allow(rustdoc::broken_intra_doc_links)] - -pub mod a { - /// [`m`] - pub fn f() {} - - #[macro_export] - macro_rules! m { - () => {}; - } -} diff --git a/tests/rustdoc/issue-108231.rs b/tests/rustdoc/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/issue-108231.rs rename to tests/rustdoc/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs new file mode 100644 index 000000000000..0d146a3c5cd0 --- /dev/null +++ b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs @@ -0,0 +1,17 @@ +// https://github.com/rust-lang/rust/issues/106142 +#![crate_name="foo"] + +//@ has 'foo/a/index.html' +//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1 + +#![allow(rustdoc::broken_intra_doc_links)] + +pub mod a { + /// [`m`] + pub fn f() {} + + #[macro_export] + macro_rules! m { + () => {}; + } +} diff --git a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs similarity index 85% rename from tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs rename to tests/rustdoc/multiple-foreigns-w-same-name-99734.rs index d7c4f1db320c..60a2aa388ee1 100644 --- a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs +++ b/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99734 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs similarity index 84% rename from tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs rename to tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs index e7fb4fb3f0ea..4a1798a84969 100644 --- a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs +++ b/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99221 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/tests/rustdoc/multiple-mods-w-same-name-99734.rs similarity index 84% rename from tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs rename to tests/rustdoc/multiple-mods-w-same-name-99734.rs index 627cfc0b80b3..d48464c478f3 100644 --- a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs +++ b/tests/rustdoc/multiple-mods-w-same-name-99734.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99734 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/tests/rustdoc/multiple-structs-w-same-name-99221.rs similarity index 84% rename from tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs rename to tests/rustdoc/multiple-structs-w-same-name-99221.rs index 8758342fe073..4c2f77fec23d 100644 --- a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs +++ b/tests/rustdoc/multiple-structs-w-same-name-99221.rs @@ -2,6 +2,7 @@ //@ build-aux-docs //@ ignore-cross-compile +// https://github.com/rust-lang/rust/issues/99221 #![crate_name = "foo"] #[macro_use] diff --git a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs similarity index 93% rename from tests/rustdoc/issue-105735-overlapping-reexport-2.rs rename to tests/rustdoc/overlapping-reexport-105735-2.rs index 946184c5a047..9f823ec5923c 100644 --- a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs +++ b/tests/rustdoc/overlapping-reexport-105735-2.rs @@ -1,4 +1,5 @@ // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export. +// https://github.com/rust-lang/rust/issues/105735 #![crate_name = "foo"] #![no_std] diff --git a/tests/rustdoc/issue-105735-overlapping-reexport.rs b/tests/rustdoc/overlapping-reexport-105735.rs similarity index 93% rename from tests/rustdoc/issue-105735-overlapping-reexport.rs rename to tests/rustdoc/overlapping-reexport-105735.rs index 0fd17fd9577c..2a2d0fa98309 100644 --- a/tests/rustdoc/issue-105735-overlapping-reexport.rs +++ b/tests/rustdoc/overlapping-reexport-105735.rs @@ -1,4 +1,5 @@ // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export. +// https://github.com/rust-lang/rust/issues/105735 #![crate_name = "foo"] #![no_std] diff --git a/tests/rustdoc/issue-107350.rs b/tests/rustdoc/pub-use-loop-107350.rs similarity index 100% rename from tests/rustdoc/issue-107350.rs rename to tests/rustdoc/pub-use-loop-107350.rs diff --git a/tests/rustdoc/issue-108679-reexport-of-reexport.rs b/tests/rustdoc/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/issue-108679-reexport-of-reexport.rs rename to tests/rustdoc/reexport-of-reexport-108679.rs diff --git a/tests/ui/abi/numbers-arithmetic/return-float.rs b/tests/ui/abi/numbers-arithmetic/return-float.rs new file mode 100644 index 000000000000..66a6d66911d3 --- /dev/null +++ b/tests/ui/abi/numbers-arithmetic/return-float.rs @@ -0,0 +1,61 @@ +//@ run-pass +//@ compile-flags: -Copt-level=0 + +// Test that floats (in particular signalling NaNs) are losslessly returned from functions. + +fn main() { + // FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled on + // x86. + if cfg!(not(all(target_arch = "x86", not(target_feature = "sse2")))) { + let bits_f32 = std::hint::black_box([ + 4.2_f32.to_bits(), + f32::INFINITY.to_bits(), + f32::NEG_INFINITY.to_bits(), + f32::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the + // other is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f32/tests.rs + f32::NAN.to_bits() ^ 0x002A_AAAA, + f32::NAN.to_bits() ^ 0x0055_5555, + // Same as above but with the sign bit flipped. + f32::NAN.to_bits() ^ 0x802A_AAAA, + f32::NAN.to_bits() ^ 0x8055_5555, + ]); + for bits in bits_f32 { + assert_eq!(identity(f32::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f32::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f32::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f32::from_bits(bits), f32::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } + + let bits_f64 = std::hint::black_box([ + 4.2_f64.to_bits(), + f64::INFINITY.to_bits(), + f64::NEG_INFINITY.to_bits(), + f64::NAN.to_bits(), + // These two masks cover all the mantissa bits. One of them is a signalling NaN, the + // other is quiet. + // Similar to the masks in `test_float_bits_conv` in library/std/src/f64/tests.rs + f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x0005_5555_5555_5555, + // Same as above but with the sign bit flipped. + f64::NAN.to_bits() ^ 0x800A_AAAA_AAAA_AAAA, + f64::NAN.to_bits() ^ 0x8005_5555_5555_5555, + ]); + for bits in bits_f64 { + assert_eq!(identity(f64::from_bits(bits)).to_bits(), bits); + // Test types that are returned as scalar pairs. + assert_eq!(identity((f64::from_bits(bits), 42)).0.to_bits(), bits); + assert_eq!(identity((42, f64::from_bits(bits))).1.to_bits(), bits); + let (a, b) = identity((f64::from_bits(bits), f64::from_bits(bits))); + assert_eq!((a.to_bits(), b.to_bits()), (bits, bits)); + } + } +} + +#[inline(never)] +fn identity(x: T) -> T { + x +} diff --git a/tests/ui/abi/removed-wasm-abi.rs b/tests/ui/abi/removed-wasm-abi.rs new file mode 100644 index 000000000000..a45e42bfe020 --- /dev/null +++ b/tests/ui/abi/removed-wasm-abi.rs @@ -0,0 +1,4 @@ +extern "wasm" fn test() {} +//~^ ERROR invalid ABI: found `wasm` + +fn main() {} diff --git a/tests/ui/abi/removed-wasm-abi.stderr b/tests/ui/abi/removed-wasm-abi.stderr new file mode 100644 index 000000000000..6007c4e25801 --- /dev/null +++ b/tests/ui/abi/removed-wasm-abi.stderr @@ -0,0 +1,12 @@ +error[E0703]: invalid ABI: found `wasm` + --> $DIR/removed-wasm-abi.rs:1:8 + | +LL | extern "wasm" fn test() {} + | ^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + = note: non-standard wasm ABI is no longer supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0703`. diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 72a9519e3e77..123e76632574 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,53 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 7 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 473b59a334df..7376bb17d6b9 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index f0af3d251e24..23b0e581887f 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,39 +1,33 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index b466a2a6ff86..708fd2c92a99 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index b466a2a6ff86..708fd2c92a99 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 + --> $DIR/unsupported.rs:45:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index cd7e76c7158f..c12883e3fce2 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -19,7 +19,6 @@ abi_ptx, abi_msp430_interrupt, abi_avr_interrupt, - wasm_abi, abi_x86_interrupt, abi_riscv_interrupt )] @@ -28,8 +27,6 @@ trait Sized {} extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI -extern "wasm" fn wasm() {} -//~^ ERROR is not a supported ABI extern "aapcs" fn aapcs() {} //[x64]~^ ERROR is not a supported ABI //[i686]~^^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 4a2b7e749692..7b918a948d3b 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,47 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:29:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:31:1 - | -LL | extern "wasm" fn wasm() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:53:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:59:1 + --> $DIR/unsupported.rs:56:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 = note: `#[warn(unsupported_calling_conventions)]` on by default -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index 539c134472fd..d21a8ab1f85f 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -313,74 +313,90 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:47:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:50:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:59:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:61:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:63:41 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 57 previous errors diff --git a/tests/ui/asm/binary_asm_labels.rs b/tests/ui/asm/binary_asm_labels.rs new file mode 100644 index 000000000000..3f545880254c --- /dev/null +++ b/tests/ui/asm/binary_asm_labels.rs @@ -0,0 +1,17 @@ +//@ needs-asm-support +//@ only-x86_64 + +// tests that labels containing only the digits 0 and 1 are rejected +// uses of such labels can sometimes be interpreted as a binary literal + +use std::arch::{asm, global_asm}; + +fn main() { + unsafe { + asm!("0: jmp 0b"); //~ ERROR avoid using labels containing only the digits + asm!("1: jmp 1b"); //~ ERROR avoid using labels containing only the digits + asm!("10: jmp 10b"); //~ ERROR avoid using labels containing only the digits + asm!("01: jmp 01b"); //~ ERROR avoid using labels containing only the digits + asm!("1001101: jmp 1001101b"); //~ ERROR avoid using labels containing only the digits + } +} diff --git a/tests/ui/asm/binary_asm_labels.stderr b/tests/ui/asm/binary_asm_labels.stderr new file mode 100644 index 000000000000..1f2943084f1e --- /dev/null +++ b/tests/ui/asm/binary_asm_labels.stderr @@ -0,0 +1,43 @@ +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:11:15 + | +LL | asm!("0: jmp 0b"); + | ^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + = note: `#[deny(binary_asm_labels)]` on by default + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:12:15 + | +LL | asm!("1: jmp 1b"); + | ^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:13:15 + | +LL | asm!("10: jmp 10b"); + | ^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:14:15 + | +LL | asm!("01: jmp 01b"); + | ^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: avoid using labels containing only the digits `0` and `1` in inline assembly + --> $DIR/binary_asm_labels.rs:15:15 + | +LL | asm!("1001101: jmp 1001101b"); + | ^^^^^^^ use a different label that doesn't start with `0` or `1` + | + = note: an LLVM bug makes these labels ambiguous with a binary literal number + +error: aborting due to 5 previous errors + diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 96ccdef75b0c..d2ca6fe8808b 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -28,11 +28,13 @@ fn main() { // Multiple labels on one line asm!("foo: bar1: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Multiple lines asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels asm!("foo2: foo3: nop", "nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("nop", "foo4: nop"); //~ ERROR avoid using named labels asm!("foo5: nop", "foo6: nop"); //~^ ERROR avoid using named labels @@ -41,16 +43,19 @@ fn main() { // Statement separator asm!("foo7: nop; foo8: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("foo9: nop; nop"); //~ ERROR avoid using named labels asm!("nop; foo10: nop"); //~ ERROR avoid using named labels // Escaped newline asm!("bar2: nop\n bar3: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels asm!("bar4: nop\n nop"); //~ ERROR avoid using named labels asm!("nop\n bar5: nop"); //~ ERROR avoid using named labels asm!("nop\n bar6: bar7: nop"); //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Raw strings asm!( @@ -60,6 +65,7 @@ fn main() { " ); //~^^^^ ERROR avoid using named labels + //~^^^^ ERROR avoid using named labels asm!( r###" @@ -81,9 +87,15 @@ fn main() { asm!("blah1: 2bar: nop"); //~ ERROR avoid using named labels // Duplicate labels - asm!("def: def: nop"); //~ ERROR avoid using named labels - asm!("def: nop\ndef: nop"); //~ ERROR avoid using named labels - asm!("def: nop; def: nop"); //~ ERROR avoid using named labels + asm!("def: def: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + asm!("def: nop\ndef: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + asm!("def: nop; def: nop"); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels // Trying to break parsing asm!(":"); @@ -141,7 +153,11 @@ fn main() { asm!("{1}: nop", "/* {0} */", const 10, const 20); //~ ERROR avoid using named labels // Test include_str in asm - asm!(include_str!("named-asm-labels.s")); //~ ERROR avoid using named labels + asm!(include_str!("named-asm-labels.s")); + //~^ ERROR avoid using named labels + //~^^ ERROR avoid using named labels + //~^^^ ERROR avoid using named labels + //~^^^^ ERROR avoid using named labels // Test allowing or warning on the lint instead #[allow(named_asm_labels)] diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index 36fd69839518..20b7d64f9e75 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -21,13 +21,22 @@ error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:29:15 | LL | asm!("foo: bar1: nop"); - | ^^^ ^^^^ + | ^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:15 + --> $DIR/named-asm-labels.rs:29:20 + | +LL | asm!("foo: bar1: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:34:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -36,16 +45,25 @@ LL | asm!("foo1: nop", "nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:34:15 + --> $DIR/named-asm-labels.rs:35:15 | LL | asm!("foo2: foo3: nop", "nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:36:22 + --> $DIR/named-asm-labels.rs:35:21 + | +LL | asm!("foo2: foo3: nop", "nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:38:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -54,7 +72,7 @@ LL | asm!("nop", "foo4: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:37:15 + --> $DIR/named-asm-labels.rs:39:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -63,7 +81,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:37:28 + --> $DIR/named-asm-labels.rs:39:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -72,16 +90,25 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:42:15 + --> $DIR/named-asm-labels.rs:44:15 | LL | asm!("foo7: nop; foo8: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:15 + --> $DIR/named-asm-labels.rs:44:26 + | +LL | asm!("foo7: nop; foo8: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:47:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -90,7 +117,7 @@ LL | asm!("foo9: nop; nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:45:20 + --> $DIR/named-asm-labels.rs:48:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -99,16 +126,25 @@ LL | asm!("nop; foo10: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:48:15 + --> $DIR/named-asm-labels.rs:51:15 | LL | asm!("bar2: nop\n bar3: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:50:15 + --> $DIR/named-asm-labels.rs:51:27 + | +LL | asm!("bar2: nop\n bar3: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:54:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -117,7 +153,7 @@ LL | asm!("bar4: nop\n nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:51:21 + --> $DIR/named-asm-labels.rs:55:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -126,19 +162,35 @@ LL | asm!("nop\n bar5: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:52:21 + --> $DIR/named-asm-labels.rs:56:21 | LL | asm!("nop\n bar6: bar7: nop"); - | ^^^^ ^^^^ + | ^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:58:13 + --> $DIR/named-asm-labels.rs:56:27 + | +LL | asm!("nop\n bar6: bar7: nop"); + | ^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:63:13 | LL | blah2: nop | ^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:64:13 + | LL | blah3: nop | ^^^^^ | @@ -146,7 +198,7 @@ LL | blah3: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:67:19 + --> $DIR/named-asm-labels.rs:73:19 | LL | nop ; blah4: nop | ^^^^^ @@ -155,7 +207,7 @@ LL | nop ; blah4: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:81:15 + --> $DIR/named-asm-labels.rs:87:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -164,7 +216,7 @@ LL | asm!("blah1: 2bar: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:84:15 + --> $DIR/named-asm-labels.rs:90:15 | LL | asm!("def: def: nop"); | ^^^ @@ -173,7 +225,17 @@ LL | asm!("def: def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:85:15 + --> $DIR/named-asm-labels.rs:90:15 + | +LL | asm!("def: def: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:93:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -182,7 +244,17 @@ LL | asm!("def: nop\ndef: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:86:15 + --> $DIR/named-asm-labels.rs:93:15 + | +LL | asm!("def: nop\ndef: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:96:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -191,7 +263,17 @@ LL | asm!("def: nop; def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:94:15 + --> $DIR/named-asm-labels.rs:96:15 + | +LL | asm!("def: nop; def: nop"); + | ^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:106:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -200,7 +282,7 @@ LL | asm!("fooo\u{003A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:95:15 + --> $DIR/named-asm-labels.rs:107:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -209,7 +291,7 @@ LL | asm!("foooo\x3A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:98:15 + --> $DIR/named-asm-labels.rs:110:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -218,7 +300,7 @@ LL | asm!("fooooo:\u{000A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:99:15 + --> $DIR/named-asm-labels.rs:111:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -227,16 +309,17 @@ LL | asm!("foooooo:\x0A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:103:14 + --> $DIR/named-asm-labels.rs:115:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:111:13 + --> $DIR/named-asm-labels.rs:123:13 | LL | ab: nop // ab: does foo | ^^ @@ -245,97 +328,140 @@ LL | ab: nop // ab: does foo = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:131:19 + --> $DIR/named-asm-labels.rs:143:19 | LL | asm!("test_{}: nop", in(reg) 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:133:15 + --> $DIR/named-asm-labels.rs:145:15 | LL | asm!("test_{}: nop", const 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:134:15 + --> $DIR/named-asm-labels.rs:146:15 | LL | asm!("test_{}: nop", sym main); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:135:15 + --> $DIR/named-asm-labels.rs:147:15 | LL | asm!("{}_test: nop", const 10); | ^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:136:15 + --> $DIR/named-asm-labels.rs:148:15 | LL | asm!("test_{}_test: nop", const 10); | ^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:137:15 + --> $DIR/named-asm-labels.rs:149:15 | LL | asm!("{}: nop", const 10); | ^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:139:15 + --> $DIR/named-asm-labels.rs:151:15 | LL | asm!("{uwu}: nop", uwu = const 10); | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:140:15 + --> $DIR/named-asm-labels.rs:152:15 | LL | asm!("{0}: nop", const 10); | ^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:141:15 + --> $DIR/named-asm-labels.rs:153:15 | LL | asm!("{1}: nop", "/* {0} */", const 10, const 20); | ^^^ | = help: only local labels of the form `:` should be used in inline asm + = note: format arguments may expand to a non-numeric value = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:144:14 + --> $DIR/named-asm-labels.rs:156:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:156:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: the label may be declared in the expansion of a macro + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:154:19 + --> $DIR/named-asm-labels.rs:170:19 | LL | asm!("warned: nop"); | ^^^^^^ @@ -343,13 +469,13 @@ LL | asm!("warned: nop"); = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information note: the lint level is defined here - --> $DIR/named-asm-labels.rs:152:16 + --> $DIR/named-asm-labels.rs:168:16 | LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:163:20 + --> $DIR/named-asm-labels.rs:179:20 | LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -358,7 +484,7 @@ LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:169:20 + --> $DIR/named-asm-labels.rs:185:20 | LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -367,7 +493,7 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:177:20 + --> $DIR/named-asm-labels.rs:193:20 | LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } | ^^^^^ @@ -376,7 +502,7 @@ LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:187:24 + --> $DIR/named-asm-labels.rs:203:24 | LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } | ^^^^^ @@ -385,7 +511,7 @@ LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:196:15 + --> $DIR/named-asm-labels.rs:212:15 | LL | asm!("closure1: nop"); | ^^^^^^^^ @@ -394,7 +520,7 @@ LL | asm!("closure1: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:200:15 + --> $DIR/named-asm-labels.rs:216:15 | LL | asm!("closure2: nop"); | ^^^^^^^^ @@ -403,7 +529,7 @@ LL | asm!("closure2: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:210:19 + --> $DIR/named-asm-labels.rs:226:19 | LL | asm!("closure3: nop"); | ^^^^^^^^ @@ -411,5 +537,5 @@ LL | asm!("closure3: nop"); = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information -error: aborting due to 44 previous errors; 1 warning emitted +error: aborting due to 56 previous errors; 1 warning emitted diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 80ee5191dbbe..1999cd09aa3b 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -371,47 +371,57 @@ LL | global_asm!("{}", label {}); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:71:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:74:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 64 previous errors diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index 07a609c52139..185262321181 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -1,29 +1,35 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:41:26 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const x); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:44:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_foo(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:47:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_bar(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: invalid `sym` operand --> $DIR/type-check-1.rs:49:24 diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index f2854ae51285..9751f7b09d0e 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -15,29 +15,35 @@ LL | asm!("{1}", in("eax") foo, const bar); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:13:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:15:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:17:42 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index a98bb0764c0e..0ccde7d8709f 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -2,115 +2,229 @@ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:8:13 | LL | let _ = await bar(); - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await bar(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:12:13 | LL | let _ = await? bar(); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await? bar(); +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:16:13 | LL | let _ = await bar()?; - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await bar()?; +LL + let _ = bar()?.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:20:13 | LL | let _ = await { bar() }; - | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await { bar() }; +LL + let _ = { bar() }.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:24:13 | LL | let _ = await(bar()); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await(bar()); +LL + let _ = (bar()).await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:28:13 | LL | let _ = await { bar() }?; - | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + | ^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await { bar() }?; +LL + let _ = { bar() }.await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:32:14 | LL | let _ = (await bar())?; - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = (await bar())?; +LL + let _ = (bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:36:24 | LL | let _ = bar().await(); - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:40:24 | LL | let _ = bar().await()?; - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await()?; +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:52:13 | LL | let _ = await bar(); - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await bar(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:56:13 | LL | let _ = await? bar(); - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await? bar(); +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:60:13 | LL | let _ = await bar()?; - | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + | ^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await bar()?; +LL + let _ = bar()?.await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:64:14 | LL | let _ = (await bar())?; - | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = (await bar())?; +LL + let _ = (bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:68:24 | LL | let _ = bar().await(); - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await(); +LL + let _ = bar().await; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:73:24 | LL | let _ = bar().await()?; - | ^^ help: `await` is not a method call, remove the parentheses + | ^^ + | +help: `await` is not a method call, remove the parentheses + | +LL - let _ = bar().await()?; +LL + let _ = bar().await?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:101:13 | LL | let _ = await!(bar()); - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await!(bar()); +LL + let _ = bar().await); + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:105:13 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:110:17 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:117:17 | LL | let _ = await!(bar())?; - | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + | ^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - let _ = await!(bar())?; +LL + let _ = bar().await)?; + | error: expected expression, found `=>` --> $DIR/incorrect-syntax-suggestions.rs:124:25 @@ -124,7 +238,13 @@ error: incorrect use of `await` --> $DIR/incorrect-syntax-suggestions.rs:124:11 | LL | match await { await => () } - | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - match await { await => () } +LL + match { await => () }.await + | error: expected one of `.`, `?`, `{`, or an operator, found `}` --> $DIR/incorrect-syntax-suggestions.rs:127:1 diff --git a/tests/ui/attributes/issue-90873.stderr b/tests/ui/attributes/issue-90873.stderr index 5a8bbaf8ec19..444497538e8d 100644 --- a/tests/ui/attributes/issue-90873.stderr +++ b/tests/ui/attributes/issue-90873.stderr @@ -32,7 +32,12 @@ error: missing type for `static` item --> $DIR/issue-90873.rs:1:17 | LL | #![u=||{static d=||1;}] - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | #![u=||{static d: =||1;}] + | ++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs new file mode 100644 index 000000000000..00eb249da1dd --- /dev/null +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ check-run-results +//@ edition:2021 +//@ exec-env:RUST_BACKTRACE=0 +//@ needs-threads +use std::thread; +const PANIC_MESSAGE: &str = "oops oh no woe is me"; + +fn entry() { + panic!("{PANIC_MESSAGE}") +} + +fn main() { + let (a, b) = (thread::spawn(entry), thread::spawn(entry)); + assert_eq!(&**a.join().unwrap_err().downcast::().unwrap(), PANIC_MESSAGE); + assert_eq!(&**b.join().unwrap_err().downcast::().unwrap(), PANIC_MESSAGE); +} diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr new file mode 100644 index 000000000000..b7c815a94c86 --- /dev/null +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -0,0 +1,5 @@ +thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +oops oh no woe is me +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +oops oh no woe is me diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs new file mode 100644 index 000000000000..2de43f634877 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.rs @@ -0,0 +1,68 @@ +fn s() -> String { + let a = String::new(); + dbg!(a); + return a; //~ ERROR use of moved value: +} + +fn m() -> String { + let a = String::new(); + dbg!(1, 2, a, 1, 2); + return a; //~ ERROR use of moved value: +} + +fn t(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return b; //~ ERROR use of moved value: +} + +fn x(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return a; //~ ERROR use of moved value: +} + +macro_rules! my_dbg { + () => { + eprintln!("[{}:{}:{}]", file!(), line!(), column!()) + }; + ($val:expr $(,)?) => { + match $val { + tmp => { + eprintln!("[{}:{}:{}] {} = {:#?}", + file!(), line!(), column!(), stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($(my_dbg!($val)),+,) + }; +} + +fn test_my_dbg() -> String { + let b: String = "".to_string(); + my_dbg!(b, 1); + return b; //~ ERROR use of moved value: +} + +fn test_not_macro() -> String { + let a = String::new(); + let _b = match a { + tmp => { + eprintln!("dbg: {}", tmp); + tmp + } + }; + return a; //~ ERROR use of moved value: +} + +fn get_expr(_s: String) {} + +fn test() { + let a: String = "".to_string(); + let _res = get_expr(dbg!(a)); + let _l = a.len(); //~ ERROR borrow of moved value +} + +fn main() {} diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr new file mode 100644 index 000000000000..efacc0c3f134 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.stderr @@ -0,0 +1,117 @@ +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:4:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a); + | ------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:10:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(1, 2, a, 1, 2); + | ------------------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(1, 2, &a, 1, 2); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:16:12 + | +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, b); + | ---------- value moved here +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(a, &b); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:22:12 + | +LL | fn x(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let b: String = "".to_string(); +LL | dbg!(a, b); + | ---------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a, b); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:46:12 + | +LL | tmp => { + | --- value moved here +... +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | my_dbg!(b, 1); +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | my_dbg!(&b, 1); + | + +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:57:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _b = match a { +LL | tmp => { + | --- value moved here +... +LL | return a; + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: borrow of moved value: `a` + --> $DIR/dbg-issue-120327.rs:65:14 + | +LL | let a: String = "".to_string(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _res = get_expr(dbg!(a)); + | ------- value moved here +LL | let _l = a.len(); + | ^ value borrowed here after move + | +help: consider borrowing instead of transferring ownership + | +LL | let _res = get_expr(dbg!(&a)); + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index cc63466585a6..00a97ca1488a 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, and `avxvnniint8` and 191 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 197 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 8a99ace75d85..78b7f0f5d997 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs index 033e42243386..45bc1ab5b1bb 100644 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,4 +1,4 @@ -//@ build-fail +//@ check-pass // Closures include captured types twice in a type tree. // @@ -45,7 +45,6 @@ fn main() { let f = dup(f); let f = dup(f); - //~^ ERROR reached the type-length limit let f = dup(f); let f = dup(f); let f = dup(f); diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr deleted file mode 100644 index 2120b4569639..000000000000 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>` - --> $DIR/issue-72408-nested-closures-exponential.rs:47:13 - | -LL | let f = dup(f); - | ^^^^^^ - | - = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate - -error: aborting due to 1 previous error - diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 4d3f2c18dc83..83a8b6b3ef6a 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,5 +1,5 @@ +//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` //@ build-fail -//@ error-pattern: reached the type-length limit while instantiating #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index e06fcd289669..f7a3e2df3dba 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,8 +1,11 @@ -error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL +error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` | - = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt' + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: 31 redundant requirements hidden + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` + = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 8084a6220456..759df3c90c6f 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -2,9 +2,13 @@ error: malformed `cfg_attr` attribute input --> $DIR/cfg-attr-parse.rs:4:1 | LL | #[cfg_attr()] - | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: expected `,`, found end of `cfg_attr` input --> $DIR/cfg-attr-parse.rs:8:17 diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 83c71e07253b..e9ea22e472c1 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/legacy-const-generics-bad.rs:7:35 | -LL | let a = 1; - | ----- help: consider using `const` instead of `let`: `const a` LL | legacy_const_generics::foo(0, a, 2); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const a: /* Type */ = 1; + | ~~~~~ ++++++++++++ error: generic parameters may not be used in const operations --> $DIR/legacy-const-generics-bad.rs:12:35 diff --git a/tests/ui/consts/const-eval/issue-104390.stderr b/tests/ui/consts/const-eval/issue-104390.stderr index 865b9996ea39..4c425ecfc130 100644 --- a/tests/ui/consts/const-eval/issue-104390.stderr +++ b/tests/ui/consts/const-eval/issue-104390.stderr @@ -38,28 +38,43 @@ error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:3:25 | LL | fn f3() -> impl Sized { &'a 2E } - | ^--^^^ + | ^---^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f3() -> impl Sized { &'a 2E } +LL + fn f3() -> impl Sized { &2E } + | error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:5:25 | LL | fn f4() -> impl Sized { &'static 2E } - | ^-------^^^ + | ^--------^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f4() -> impl Sized { &'static 2E } +LL + fn f4() -> impl Sized { &2E } + | error: borrow expressions cannot be annotated with lifetimes --> $DIR/issue-104390.rs:8:25 | LL | fn f6() -> impl Sized { &'_ 2E } - | ^--^^^ + | ^---^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - fn f6() -> impl Sized { &'_ 2E } +LL + fn f6() -> impl Sized { &2E } + | error: aborting due to 9 previous errors diff --git a/tests/ui/consts/issue-3521.stderr b/tests/ui/consts/issue-3521.stderr index 70ce9b2d6a08..c0e4cdc5a94c 100644 --- a/tests/ui/consts/issue-3521.stderr +++ b/tests/ui/consts/issue-3521.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521.rs:8:15 | -LL | let foo: isize = 100; - | ------- help: consider using `const` instead of `let`: `const foo` -... LL | Bar = foo | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: isize = 100; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-91560.stderr b/tests/ui/consts/issue-91560.stderr index e1b5d4cacf8e..37c8f50d4943 100644 --- a/tests/ui/consts/issue-91560.stderr +++ b/tests/ui/consts/issue-91560.stderr @@ -1,20 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:10:19 | -LL | let mut length: usize = 2; - | -------------- help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:17:19 | -LL | let length: usize = 2; - | ------------ help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index efb346f91aef..7e759a1a1e42 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -2,13 +2,20 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +#![allow(static_mut_refs)] #![deny(const_eval_mutable_ptr_in_final_value)] use std::cell::UnsafeCell; +use std::sync::atomic::*; + +// # Plain `&mut` in the final value // This requires walking nested statics. static FOO: &&mut u32 = &&mut 42; //~^ ERROR it is undefined behavior to use this value - +//~| pointing to read-only memory +static OH_YES: &mut i32 = &mut 42; +//~^ ERROR it is undefined behavior to use this value +//~| pointing to read-only memory static BAR: &mut () = &mut (); //~^ ERROR encountered mutable pointer in final value of static //~| WARNING this was previously accepted by the compiler @@ -19,15 +26,92 @@ static BOO: &mut Foo<()> = &mut Foo(()); //~^ ERROR encountered mutable pointer in final value of static //~| WARNING this was previously accepted by the compiler +const BLUNT: &mut i32 = &mut 42; +//~^ ERROR: it is undefined behavior to use this value +//~| pointing to read-only memory + +const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; +//~^ ERROR: it is undefined behavior to use this value +//~| static + +// # Interior mutability + struct Meh { x: &'static UnsafeCell, } unsafe impl Sync for Meh {} static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; //~^ ERROR it is undefined behavior to use this value +//~| `UnsafeCell` in read-only memory +// Same with a const: +// the following will never be ok! no interior mut behind consts, because +// all allocs interned here will be marked immutable. +const MUH: Meh = Meh { + //~^ ERROR it is undefined behavior to use this value + //~| `UnsafeCell` in read-only memory + x: &UnsafeCell::new(42), +}; + +struct Synced { + x: UnsafeCell, +} +unsafe impl Sync for Synced {} + +// Make sure we also catch this behind a type-erased `dyn Trait` reference. +const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; +//~^ ERROR: it is undefined behavior to use this value +//~| `UnsafeCell` in read-only memory + +// # Check for mutable references to read-only memory + +static READONLY: i32 = 0; +static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; +//~^ ERROR: it is undefined behavior to use this value +//~| pointing to read-only memory + +// # Check for consts pointing to mutable memory + +static mut MUTABLE: i32 = 42; +const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior +//~| encountered reference to mutable memory +static mut MUTABLE_REF: &mut i32 = &mut 42; +const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; +//~^ ERROR: evaluation of constant value failed +//~| accesses mutable global memory + +const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; +//~^ ERROR: mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +struct SyncPtr { + x: *const T, +} +unsafe impl Sync for SyncPtr {} + +// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. +// (This relies on `SyncPtr` being a curly brace struct.) +// However, we intern the inner memory as read-only, so this must be rejected. +// (Also see `static-no-inner-mut` for similar tests on `static`.) +const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler + +const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; +//~^ ERROR mutable pointer in final value +//~| WARNING this was previously accepted by the compiler -static OH_YES: &mut i32 = &mut 42; -//~^ ERROR it is undefined behavior to use this value fn main() { unsafe { diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index b207e3869ac8..620953ffa3e2 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:9:1 + --> $DIR/mutable_references.rs:13:1 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered mutable reference or box pointing to read-only memory @@ -9,8 +9,19 @@ LL | static FOO: &&mut u32 = &&mut 42; HEX_DUMP } +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:16:1 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:12:1 + --> $DIR/mutable_references.rs:19:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ @@ -18,13 +29,13 @@ LL | static BAR: &mut () = &mut (); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:18:1 + --> $DIR/mutable_references.rs:25:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +44,29 @@ LL | static BOO: &mut Foo<()> = &mut Foo(()); = note: for more information, see issue #122153 error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:26:1 + --> $DIR/mutable_references.rs:29:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:33:1 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:43:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -44,18 +77,111 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:29:1 + --> $DIR/mutable_references.rs:49:1 | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:61:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:68:1 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references.rs:75:1 + | +LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/mutable_references.rs:78:43 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^^^ constant accesses mutable global memory + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:82:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:86:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:90:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:103:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:107:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:111:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 + error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:36:5 + --> $DIR/mutable_references.rs:120:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -63,38 +189,113 @@ LL | *OH_YES = 99; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:9:26 + --> $DIR/mutable_references.rs:13:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:12:23 + --> $DIR/mutable_references.rs:16:27 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:19:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:18:28 + --> $DIR/mutable_references.rs:25:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:26:28 + --> $DIR/mutable_references.rs:29:25 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:33:68 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:33:63 + | +LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:43:28 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:29:27 + --> $DIR/mutable_references.rs:52:8 | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^ +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:61:27 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:68:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/mutable_references.rs:68:49 + | +LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:75:43 + | +LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; + | ^^^^^^^ +help: skipping check for `const_refs_to_static` feature + --> $DIR/mutable_references.rs:78:45 + | +LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; + | ^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:82:45 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:86:46 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:90:47 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:103:51 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:107:49 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:111:51 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 19 previous errors; 1 warning emitted Some errors have detailed explanations: E0080, E0594. For more information about an error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:12:1 + --> $DIR/mutable_references.rs:19:1 | LL | static BAR: &mut () = &mut (); | ^^^^^^^^^^^^^^^^^^^ @@ -102,14 +303,14 @@ LL | static BAR: &mut () = &mut (); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Future breakage diagnostic: error: encountered mutable pointer in final value of static - --> $DIR/mutable_references.rs:18:1 + --> $DIR/mutable_references.rs:25:1 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +318,97 @@ LL | static BOO: &mut Foo<()> = &mut Foo(()); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #122153 note: the lint level is defined here - --> $DIR/mutable_references.rs:5:9 + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:82:1 + | +LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:86:1 + | +LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:90:1 + | +LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:103:1 + | +LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:107:1 + | +LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 + | +LL | #![deny(const_eval_mutable_ptr_in_final_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: encountered mutable pointer in final value of constant + --> $DIR/mutable_references.rs:111:1 + | +LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #122153 +note: the lint level is defined here + --> $DIR/mutable_references.rs:6:9 | LL | #![deny(const_eval_mutable_ptr_in_final_value)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs deleted file mode 100644 index 8398b0758ddd..000000000000 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs +++ /dev/null @@ -1,95 +0,0 @@ -//@ compile-flags: -Zunleash-the-miri-inside-of-you -//@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -//@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![allow(invalid_reference_casting, static_mut_refs)] -#![deny(const_eval_mutable_ptr_in_final_value)] -use std::cell::UnsafeCell; -use std::sync::atomic::*; - -// this test ensures that our mutability story is sound - -struct Meh { - x: &'static UnsafeCell, -} -unsafe impl Sync for Meh {} - -// the following will never be ok! no interior mut behind consts, because -// all allocs interned here will be marked immutable. -const MUH: Meh = Meh { - //~^ ERROR it is undefined behavior to use this value - x: &UnsafeCell::new(42), -}; - -struct Synced { - x: UnsafeCell, -} -unsafe impl Sync for Synced {} - -// Make sure we also catch this behind a type-erased `dyn Trait` reference. -const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; -//~^ ERROR: it is undefined behavior to use this value - -// Make sure we also catch mutable references in values that shouldn't have them. -static mut FOO: i32 = 0; -const SUBTLE: &mut i32 = unsafe { &mut FOO }; -//~^ ERROR: it is undefined behavior to use this value -//~| static - -const BLUNT: &mut i32 = &mut 42; -//~^ ERROR: it is undefined behavior to use this value - -// Check for mutable references to read-only memory. -static READONLY: i32 = 0; -static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; -//~^ ERROR: it is undefined behavior to use this value -//~| pointing to read-only memory - -// Check for consts pointing to mutable memory. -// These are fine as long as they are not being read. -static mut MUTABLE: i32 = 42; -const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior -//~| encountered reference to mutable memory -const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1; -static mut MUTABLE_REF: &mut i32 = &mut 42; -const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; -//~^ ERROR: evaluation of constant value failed -//~| accesses mutable global memory - -const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; -//~^ ERROR: mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -struct SyncPtr { - x: *const T, -} -unsafe impl Sync for SyncPtr {} - -// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. -// (This relies on `SyncPtr` being a curly brace struct.) -// However, we intern the inner memory as read-only, so this must be rejected. -// (Also see `static-no-inner-mut` for similar tests on `static`.) -const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; -//~^ ERROR mutable pointer in final value -//~| WARNING this was previously accepted by the compiler - -fn main() { - unsafe { - *MUH.x.get() = 99; - } -} diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.stderr deleted file mode 100644 index d385b45a3df9..000000000000 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr +++ /dev/null @@ -1,308 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:18:1 - | -LL | const MUH: Meh = Meh { - | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:29:1 - | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:34:1 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:38:1 - | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:43:1 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references_err.rs:50:1 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -note: erroneous constant encountered - --> $DIR/mutable_references_err.rs:52:34 - | -LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1; - | ^^^^^^^^^^^^^^^^^^ - -error[E0080]: evaluation of constant value failed - --> $DIR/mutable_references_err.rs:54:43 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^^^ constant accesses mutable global memory - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:58:1 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:62:1 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:66:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:79:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:83:1 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 - -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:87:1 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 - -warning: skipping const checks - | -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:20:8 - | -LL | x: &UnsafeCell::new(42), - | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:29:27 - | -LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:34:40 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:34:35 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:38:25 - | -LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:43:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature - --> $DIR/mutable_references_err.rs:43:49 - | -LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:50:44 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:54:45 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:58:45 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:62:46 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:66:47 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:79:51 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:83:49 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/mutable_references_err.rs:87:51 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^ - -error: aborting due to 13 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0080`. -Future incompatibility report: Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:58:1 - | -LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:62:1 - | -LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:66:1 - | -LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:79:1 - | -LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:83:1 - | -LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references_err.rs:87:1 - | -LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #122153 -note: the lint level is defined here - --> $DIR/mutable_references_err.rs:5:9 - | -LL | #![deny(const_eval_mutable_ptr_in_final_value)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index 0ce4b4b70533..654b573544c2 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -2,18 +2,23 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:3:20 | LL | const Y: i32 = x; - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let Y` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let Y: i32 = x; + | ~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:6:17 | -LL | let x = 5; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | let _ = [0; x]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x: /* Type */ = 5; + | ~~~~~ ++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index e71f88b8d5fa..1506c212fbae 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -32,12 +32,6 @@ pub const NOT_MULTIPLE_OF_SIZE: isize = { //~| 1_isize cannot be divided by 2_isize without remainder }; -pub const OFFSET_FROM_NULL: isize = { - let ptr = 0 as *const u8; - // Null isn't special for zero-sized "accesses" (i.e., the range between the two pointers) - unsafe { ptr_offset_from(ptr, ptr) } -}; - pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; @@ -63,14 +57,6 @@ const OUT_OF_BOUNDS_2: isize = { //~| pointer to 10 bytes starting at offset 0 is out-of-bounds }; -const OUT_OF_BOUNDS_SAME: isize = { - let start_ptr = &4 as *const _ as *const u8; - let length = 10; - let end_ptr = (start_ptr).wrapping_add(length); - // Out-of-bounds is fine as long as the range between the pointers is empty. - unsafe { ptr_offset_from(end_ptr, end_ptr) } -}; - pub const DIFFERENT_ALLOC_UNSIGNED: usize = { let uninit = std::mem::MaybeUninit::::uninit(); let base_ptr: *const Struct = &uninit as *const _ as *const Struct; @@ -130,4 +116,23 @@ pub const OFFSET_VERY_FAR2: isize = { //~^ inside }; +// If the pointers are the same, OOB/null/UAF is fine. +pub const OFFSET_FROM_NULL_SAME: isize = { + let ptr = 0 as *const u8; + unsafe { ptr_offset_from(ptr, ptr) } +}; +const OUT_OF_BOUNDS_SAME: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + unsafe { ptr_offset_from(end_ptr, end_ptr) } +}; +const UAF_SAME: isize = { + let uaf_ptr = { + let x = 0; + &x as *const i32 + }; + unsafe { ptr_offset_from(uaf_ptr, uaf_ptr) } +}; + fn main() {} diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 7caf6247b9e9..7b623126d54f 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -24,55 +24,55 @@ LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:44:14 + --> $DIR/offset_from_ub.rs:38:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:53:14 + --> $DIR/offset_from_ub.rs:47:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC0 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:62:14 + --> $DIR/offset_from_ub.rs:56:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:79:14 + --> $DIR/offset_from_ub.rs:65:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:86:14 + --> $DIR/offset_from_ub.rs:72:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:92:14 + --> $DIR/offset_from_ub.rs:78:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:100:14 + --> $DIR/offset_from_ub.rs:86:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:107:14 + --> $DIR/offset_from_ub.rs:93:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:114:14 + --> $DIR/offset_from_ub.rs:100:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second @@ -85,7 +85,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` - --> $DIR/offset_from_ub.rs:123:14 + --> $DIR/offset_from_ub.rs:109:14 | LL | unsafe { ptr2.offset_from(ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` - --> $DIR/offset_from_ub.rs:129:14 + --> $DIR/offset_from_ub.rs:115:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index a5868fcf19cf..2bcf54860eb8 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -106,10 +106,13 @@ error: expected identifier, found `,` --> $DIR/bad-syntax.rs:42:12 | LL | #[coverage(,off)] - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - #[coverage(,off)] +LL + #[coverage(off)] + | error: multiple `coverage` attributes --> $DIR/bad-syntax.rs:7:1 diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr new file mode 100644 index 000000000000..629fc59361dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr new file mode 100644 index 000000000000..629fc59361dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/supress_suggestions_in_help.rs:23:11 + | +LL | check(()); + | ----- ^^ the trait `Foo` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `i32` +note: required by a bound in `check` + --> $DIR/supress_suggestions_in_help.rs:20:18 + | +LL | fn check(a: impl Foo) {} + | ^^^ required by this bound in `check` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs new file mode 100644 index 000000000000..ef6f255c3518 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(do_not_recommend)] + +trait Foo {} + +#[diagnostic::do_not_recommend] +impl Foo for (A,) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B) {} + +#[diagnostic::do_not_recommend] +impl Foo for (A, B, C) {} + +impl Foo for i32 {} + +fn check(a: impl Foo) {} + +fn main() { + check(()); + //~^ ERROR the trait bound `(): Foo` is not satisfied +} diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr index 58ac6e90823f..5f289da8a6c3 100644 --- a/tests/ui/did_you_mean/E0178.stderr +++ b/tests/ui/did_you_mean/E0178.stderr @@ -2,19 +2,34 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` --> $DIR/E0178.rs:6:8 | LL | w: &'a Foo + Copy, - | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)` + | ^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | w: &'a (Foo + Copy), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` --> $DIR/E0178.rs:7:8 | LL | x: &'a Foo + 'a, - | ^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + 'a)` + | ^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | x: &'a (Foo + 'a), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` --> $DIR/E0178.rs:8:8 | LL | y: &'a mut Foo + 'a, - | ^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'a mut (Foo + 'a)` + | ^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | y: &'a mut (Foo + 'a), + | + + error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` --> $DIR/E0178.rs:9:8 diff --git a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr index 2a3242abea49..952ac76a003d 100644 --- a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr +++ b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr @@ -2,39 +2,56 @@ error: `~` cannot be used as a unary operator --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:4:14 | LL | let _x = ~1; - | ^ help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let _x = !1; + | ~ error: unexpected `1` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:5:18 | LL | let _y = not 1; - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let _y = !1; + | ~ error: unexpected keyword `false` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:6:18 | LL | let _z = not false; - | ----^^^^^ - | | - | help: use `!` to perform logical negation + | ^^^^^ + | +help: use `!` to perform logical negation + | +LL | let _z = !false; + | ~ error: unexpected keyword `true` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:7:18 | LL | let _a = not true; - | ----^^^^ - | | - | help: use `!` to perform logical negation + | ^^^^ + | +help: use `!` to perform logical negation + | +LL | let _a = !true; + | ~ error: unexpected `v` after identifier --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:9:18 | LL | let _v = not v; - | ----^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | let _v = !v; + | ~ error: aborting due to 5 previous errors diff --git a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index 14918ba89532..6dea6a4fac8f 100644 --- a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -2,25 +2,34 @@ error: unexpected `for_you` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:3:12 | LL | if not for_you { - | ----^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | if !for_you { + | ~ error: unexpected `the_worst` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:11:15 | LL | while not the_worst { - | ----^^^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | while !the_worst { + | ~ error: unexpected `println` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:9 | -LL | if not // lack of braces is [sic] - | ----- help: use `!` to perform logical negation or bitwise not LL | println!("Then when?"); | ^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | if !// lack of braces is [sic] + | ~ error: expected `{`, found `;` --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31 @@ -40,17 +49,23 @@ error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 | LL | let resource = not 2; - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | let resource = !2; + | ~ error: unexpected `be_smothered_out_before` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:32:27 | LL | let young_souls = not be_smothered_out_before; - | ----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: use `!` to perform logical negation or bitwise not + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!` to perform logical negation or bitwise not + | +LL | let young_souls = !be_smothered_out_before; + | ~ error: aborting due to 6 previous errors diff --git a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr index cbe59e8e0af7..c52102e2631d 100644 --- a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr +++ b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr @@ -2,65 +2,97 @@ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15 | LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | let _ = a && b; + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10 | LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15 | LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | let _ = a || b; + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10 | LL | if a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if a || b { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11 | LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if (a && b) { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11 | LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if (a || b) { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13 | LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | while a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13 | LL | while a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | while a || b { + | ~~ error[E0308]: mismatched types --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33 diff --git a/tests/ui/did_you_mean/issue-54109-without-witness.stderr b/tests/ui/did_you_mean/issue-54109-without-witness.stderr index 6455b0863f8f..ee6d9901fcf6 100644 --- a/tests/ui/did_you_mean/issue-54109-without-witness.stderr +++ b/tests/ui/did_you_mean/issue-54109-without-witness.stderr @@ -2,65 +2,97 @@ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:13:15 | LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | let _ = a && b; + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:15:10 | LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:24:15 | LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | let _ = a || b; + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:26:10 | LL | if a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if a || b { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:34:11 | LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | if (a && b) { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:42:11 | LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | if (a || b) { + | ~~ error: `and` is not a logical operator --> $DIR/issue-54109-without-witness.rs:50:13 | LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction + | ^^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `&&` to perform logical conjunction + | +LL | while a && b { + | ~~ error: `or` is not a logical operator --> $DIR/issue-54109-without-witness.rs:58:13 | LL | while a or b { - | ^^ help: use `||` to perform logical disjunction + | ^^ | = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators +help: use `||` to perform logical disjunction + | +LL | while a || b { + | ~~ error: aborting due to 8 previous errors diff --git a/tests/ui/did_you_mean/pub-macro-rules.stderr b/tests/ui/did_you_mean/pub-macro-rules.stderr index ba9020460cea..fb9148748ca1 100644 --- a/tests/ui/did_you_mean/pub-macro-rules.stderr +++ b/tests/ui/did_you_mean/pub-macro-rules.stderr @@ -2,7 +2,12 @@ error: can't qualify macro_rules invocation with `pub` --> $DIR/pub-macro-rules.rs:2:5 | LL | pub macro_rules! foo { - | ^^^ help: try exporting the macro: `#[macro_export]` + | ^^^ + | +help: try exporting the macro + | +LL | #[macro_export] macro_rules! foo { + | ~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 68734cd4ccd6..a33a8c776c8e 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -2,13 +2,23 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^^^^^^^^^^^ help: try adding parentheses: `&(Copy + 'static)` + | ^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &(Copy + 'static); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12 | LL | let _: &'static Copy + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &'static (Copy + 'static); + | + + error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 diff --git a/tests/ui/did_you_mean/use_instead_of_import.stderr b/tests/ui/did_you_mean/use_instead_of_import.stderr index 2aac8f68c5eb..f8d6de8a1176 100644 --- a/tests/ui/did_you_mean/use_instead_of_import.stderr +++ b/tests/ui/did_you_mean/use_instead_of_import.stderr @@ -2,25 +2,45 @@ error: expected item, found `import` --> $DIR/use_instead_of_import.rs:3:1 | LL | import std::{ - | ^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::{ + | ~~~ error: expected item, found `require` --> $DIR/use_instead_of_import.rs:9:1 | LL | require std::time::Duration; - | ^^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::time::Duration; + | ~~~ error: expected item, found `include` --> $DIR/use_instead_of_import.rs:12:1 | LL | include std::time::Instant; - | ^^^^^^^ help: items are imported using the `use` keyword + | ^^^^^^^ + | +help: items are imported using the `use` keyword + | +LL | use std::time::Instant; + | ~~~ error: expected item, found `using` --> $DIR/use_instead_of_import.rs:15:5 | LL | pub using std::io; - | ^^^^^ help: items are imported using the `use` keyword + | ^^^^^ + | +help: items are imported using the `use` keyword + | +LL | pub use std::io; + | ~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/enum/nested-enum.rs b/tests/ui/enum/nested-enum.rs index 80957b8a14c2..ff39fdee6bc6 100644 --- a/tests/ui/enum/nested-enum.rs +++ b/tests/ui/enum/nested-enum.rs @@ -1,7 +1,10 @@ enum Foo { - enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum` - struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum` - union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum` + enum Bar { Baz }, + //~^ ERROR `enum` definition cannot be nested inside `enum` + struct Quux { field: u8 }, + //~^ ERROR `struct` definition cannot be nested inside `enum` + union Wibble { field: u8 }, + //~^ ERROR `union` definition cannot be nested inside `enum` Bat, } diff --git a/tests/ui/enum/nested-enum.stderr b/tests/ui/enum/nested-enum.stderr index 7d6f57e88a82..78df333abb31 100644 --- a/tests/ui/enum/nested-enum.stderr +++ b/tests/ui/enum/nested-enum.stderr @@ -2,25 +2,34 @@ error: `enum` definition cannot be nested inside `enum` --> $DIR/nested-enum.rs:2:5 | LL | enum Bar { Baz }, - | ^^^^------------ - | | - | help: consider creating a new `enum` definition instead of nesting + | ^^^^ + | +help: consider creating a new `enum` definition instead of nesting + | +LL - enum Bar { Baz }, + | error: `struct` definition cannot be nested inside `enum` - --> $DIR/nested-enum.rs:3:5 - | -LL | struct Quux { field: u8 }, - | ^^^^^^------------------- - | | - | help: consider creating a new `struct` definition instead of nesting - -error: `union` definition cannot be nested inside `enum` --> $DIR/nested-enum.rs:4:5 | +LL | struct Quux { field: u8 }, + | ^^^^^^ + | +help: consider creating a new `struct` definition instead of nesting + | +LL - struct Quux { field: u8 }, + | + +error: `union` definition cannot be nested inside `enum` + --> $DIR/nested-enum.rs:6:5 + | LL | union Wibble { field: u8 }, - | ^^^^^--------------------- - | | - | help: consider creating a new `union` definition instead of nesting + | ^^^^^ + | +help: consider creating a new `union` definition instead of nesting + | +LL - union Wibble { field: u8 }, + | error: aborting due to 3 previous errors diff --git a/tests/ui/error-codes/E0435.stderr b/tests/ui/error-codes/E0435.stderr index 68d6ddba2a10..1ebb99763944 100644 --- a/tests/ui/error-codes/E0435.stderr +++ b/tests/ui/error-codes/E0435.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/E0435.rs:5:17 | -LL | let foo: usize = 42; - | ------- help: consider using `const` instead of `let`: `const foo` LL | let _: [u8; foo]; | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: usize = 42; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0586.stderr b/tests/ui/error-codes/E0586.stderr index f562e358cba1..b3e07220d3d4 100644 --- a/tests/ui/error-codes/E0586.stderr +++ b/tests/ui/error-codes/E0586.stderr @@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end --> $DIR/E0586.rs:3:19 | LL | let x = &tmp[1..=]; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - let x = &tmp[1..=]; +LL + let x = &tmp[1..]; + | error: aborting due to 1 previous error diff --git a/tests/ui/expr/if/attrs/else-attrs.stderr b/tests/ui/expr/if/attrs/else-attrs.stderr index 2733377054d7..c4e51406d57b 100644 --- a/tests/ui/expr/if/attrs/else-attrs.stderr +++ b/tests/ui/expr/if/attrs/else-attrs.stderr @@ -9,12 +9,17 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | } else #[attr] if false { | _______----_^^^^^^^_- - | | | | - | | | help: remove the attributes + | | | | | the branch belongs to this `else` LL | | } else { LL | | } | |_____- the attributes are attached to this branch + | +help: remove the attributes + | +LL - } else #[attr] if false { +LL + } else if false { + | error: expected expression, found keyword `else` --> $DIR/else-attrs.rs:20:15 diff --git a/tests/ui/extern/extern-const.stderr b/tests/ui/extern/extern-const.stderr index 31954ca2c843..441495866cd9 100644 --- a/tests/ui/extern/extern-const.stderr +++ b/tests/ui/extern/extern-const.stderr @@ -2,11 +2,13 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:14:11 | LL | const rust_dbg_static_mut: c_int; - | ------^^^^^^^^^^^^^^^^^^^ - | | - | help: try using a static value: `static` + | ^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static rust_dbg_static_mut: c_int; + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.rs b/tests/ui/feature-gates/feature-gate-wasm_abi.rs deleted file mode 100644 index da1d9300a2bd..000000000000 --- a/tests/ui/feature-gates/feature-gate-wasm_abi.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ needs-llvm-components: webassembly -//@ compile-flags: --target=wasm32-unknown-unknown --crate-type=rlib -#![no_core] -#![feature(no_core, lang_items)] -#[lang="sized"] -trait Sized { } - -extern "wasm" fn fu() {} //~ ERROR wasm ABI is experimental - -trait T { - extern "wasm" fn mu(); //~ ERROR wasm ABI is experimental - extern "wasm" fn dmu() {} //~ ERROR wasm ABI is experimental -} - -struct S; -impl T for S { - extern "wasm" fn mu() {} //~ ERROR wasm ABI is experimental -} - -impl S { - extern "wasm" fn imu() {} //~ ERROR wasm ABI is experimental -} - -type TAU = extern "wasm" fn(); //~ ERROR wasm ABI is experimental - -extern "wasm" {} //~ ERROR wasm ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr b/tests/ui/feature-gates/feature-gate-wasm_abi.stderr deleted file mode 100644 index 973c42af19c5..000000000000 --- a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr +++ /dev/null @@ -1,73 +0,0 @@ -error[E0658]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:8:8 - | -LL | extern "wasm" fn fu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:11:12 - | -LL | extern "wasm" fn mu(); - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:12:12 - | -LL | extern "wasm" fn dmu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:17:12 - | -LL | extern "wasm" fn mu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:21:12 - | -LL | extern "wasm" fn imu() {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:24:19 - | -LL | type TAU = extern "wasm" fn(); - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change - --> $DIR/feature-gate-wasm_abi.rs:26:8 - | -LL | extern "wasm" {} - | ^^^^^^ - | - = note: see issue #83788 for more information - = help: add `#![feature(wasm_abi)]` 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: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs new file mode 100644 index 000000000000..ecbfc0bce5c5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "amx-tile")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr new file mode 100644 index 000000000000..58d577a37902 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `amx-tile` is currently unstable + --> $DIR/feature-gate-x86_amx_intrinsics.rs:2:18 + | +LL | #[target_feature(enable = "amx-tile")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #126622 for more information + = help: add `#![feature(x86_amx_intrinsics)]` 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: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-xop_target_feature.rs b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs new file mode 100644 index 000000000000..3032a6fbb475 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "xop")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr new file mode 100644 index 000000000000..58f7b0b3b002 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `xop` is currently unstable + --> $DIR/feature-gate-xop_target_feature.rs:2:18 + | +LL | #[target_feature(enable = "xop")] + | ^^^^^^^^^^^^^^ + | + = note: see issue #127208 for more information + = help: add `#![feature(xop_target_feature)]` 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: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr index dfd24bf60ad5..d5fe4081ac81 100644 --- a/tests/ui/fmt/format-string-error-2.stderr +++ b/tests/ui/fmt/format-string-error-2.stderr @@ -2,7 +2,12 @@ error: incorrect unicode escape sequence --> $DIR/format-string-error-2.rs:77:20 | LL | println!("\x7B}\u8 {", 1); - | ^^^ help: format of unicode escape sequences uses braces: `\u{8}` + | ^^^ + | +help: format of unicode escape sequences uses braces + | +LL | println!("\x7B}\u{8} {", 1); + | ~~~~~ error: invalid format string: expected `'}'`, found `'a'` --> $DIR/format-string-error-2.rs:5:5 diff --git a/tests/ui/fn/fn-recover-return-sign.fixed b/tests/ui/fn/fn-recover-return-sign.fixed index 20dca91fdf41..1da10a6d8fe2 100644 --- a/tests/ui/fn/fn-recover-return-sign.fixed +++ b/tests/ui/fn/fn-recover-return-sign.fixed @@ -3,7 +3,7 @@ fn a() -> usize { 0 } //~^ ERROR return types are denoted using `->` -fn b()-> usize { 0 } +fn b() -> usize { 0 } //~^ ERROR return types are denoted using `->` fn bar(_: u32) {} @@ -22,7 +22,7 @@ fn main() { //~^ ERROR return types are denoted using `->` dbg!(foo(false)); - let bar = |a: bool|-> bool { a }; + let bar = |a: bool| -> bool { a }; //~^ ERROR return types are denoted using `->` dbg!(bar(false)); } diff --git a/tests/ui/fn/fn-recover-return-sign.stderr b/tests/ui/fn/fn-recover-return-sign.stderr index 983109730ff3..e6012f3f9502 100644 --- a/tests/ui/fn/fn-recover-return-sign.stderr +++ b/tests/ui/fn/fn-recover-return-sign.stderr @@ -2,25 +2,45 @@ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:3:8 | LL | fn a() => usize { 0 } - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | fn a() -> usize { 0 } + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:6:7 | LL | fn b(): usize { 0 } - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn b() -> usize { 0 } + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:21:25 | LL | let foo = |a: bool| => bool { a }; - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | let foo = |a: bool| -> bool { a }; + | ~~ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign.rs:25:24 | LL | let bar = |a: bool|: bool { a }; - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | let bar = |a: bool| -> bool { a }; + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/fn/fn-recover-return-sign2.stderr b/tests/ui/fn/fn-recover-return-sign2.stderr index 25ee8dd0c5dc..fb88ff7b9504 100644 --- a/tests/ui/fn/fn-recover-return-sign2.stderr +++ b/tests/ui/fn/fn-recover-return-sign2.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/fn-recover-return-sign2.rs:4:10 | LL | fn foo() => impl Fn() => bool { - | ^^ help: use `->` instead + | ^^ + | +help: use `->` instead + | +LL | fn foo() -> impl Fn() => bool { + | ~~ error: expected one of `+`, `->`, `::`, `where`, or `{`, found `=>` --> $DIR/fn-recover-return-sign2.rs:4:23 diff --git a/tests/ui/generics/issue-95208-ignore-qself.stderr b/tests/ui/generics/issue-95208-ignore-qself.stderr index cf40e857d42b..7d91fbc14a18 100644 --- a/tests/ui/generics/issue-95208-ignore-qself.stderr +++ b/tests/ui/generics/issue-95208-ignore-qself.stderr @@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime --> $DIR/issue-95208-ignore-qself.rs:6:88 | LL | impl Struct where ::Item:: std::fmt::Display { - | --- ^ - | | - | help: use single colon: `:` + | ^ + | +help: use single colon + | +LL | impl Struct where ::Item: std::fmt::Display { + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/generics/issue-95208.stderr b/tests/ui/generics/issue-95208.stderr index 0d856d096aff..e047f1265e2e 100644 --- a/tests/ui/generics/issue-95208.stderr +++ b/tests/ui/generics/issue-95208.stderr @@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime --> $DIR/issue-95208.rs:6:46 | LL | impl Struct where T:: std::fmt::Display { - | --- ^ - | | - | help: use single colon: `:` + | ^ + | +help: use single colon + | +LL | impl Struct where T: std::fmt::Display { + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index d61562bb199f..4e695b2dcd6d 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -4,9 +4,13 @@ error: path separator must be a double colon LL | pub struct Foo { | --- while parsing this struct LL | a: Vec, - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | a: Vec, + | + error: aborting due to 1 previous error diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr index 0d2aae689f03..0f60cd397b99 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr @@ -2,36 +2,60 @@ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:15:9 | LL | ...X => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=X => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:16:9 | LL | ...0 => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=0 => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9 | LL | ...'a' => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..='a' => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9 | LL | ...0.0f32 => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | ..=0.0f32 => {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17 | LL | let ...$e; - | ^^^ help: use `..=` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..=` instead + | +LL | let ..=$e; + | ~~~ error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17 diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr index 9ba0e09e1540..204ee373bc53 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr @@ -2,57 +2,87 @@ error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:8:13 | LL | if let 0... = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0... = 1 {} +LL + if let 0.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:9:13 | LL | if let 0..= = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0..= = 1 {} +LL + if let 0.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13 | LL | if let X... = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X... = 1 {} +LL + if let X.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:12:13 | LL | if let X..= = 1 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X..= = 1 {} +LL + if let X.. = 1 {} + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:19 | LL | let $e...; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e...; +LL + let $e..; + | error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:19 | LL | let $e..=; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e..=; +LL + let $e..; + | error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:17 diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr index 111e81799625..83a374c3d65d 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr @@ -2,53 +2,93 @@ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:6:10 | LL | &0.. | _ => {} - | ^^^ help: add parentheses to clarify the precedence: `(0..)` + | ^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(0..) | _ => {} + | + + error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:11 | LL | &0..= | _ => {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - &0..= | _ => {} +LL + &0.. | _ => {} + | error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10 | LL | &0..= | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(0..=)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(0..=) | _ => {} + | + + error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:11:11 | LL | &0... | _ => {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - &0... | _ => {} +LL + &0.. | _ => {} + | error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:16:10 | LL | &..0 | _ => {} - | ^^^ help: add parentheses to clarify the precedence: `(..0)` + | ^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(..0) | _ => {} + | + + error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10 | LL | &..=0 | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(..=0)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(..=0) | _ => {} + | + + error: range-to patterns with `...` are not allowed --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10 | LL | &...0 | _ => {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | &..=0 | _ => {} + | ~~~ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10 | LL | &...0 | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(..=0)` + | ^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(...0) | _ => {} + | + + error: aborting due to 8 previous errors diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr index e0955faac7ca..94b6ffdd9123 100644 --- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr +++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr @@ -2,13 +2,23 @@ error: ambiguous `+` in a type --> $DIR/impl-fn-parsing-ambiguities.rs:4:27 | LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ { - | ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)` + | ^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) { + | + + error: ambiguous `+` in a type --> $DIR/impl-fn-parsing-ambiguities.rs:10:24 | LL | fn b() -> impl Fn() -> impl Debug + Send { - | ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)` + | ^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn b() -> impl Fn() -> (impl Debug + Send) { + | + + error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` --> $DIR/impl-fn-parsing-ambiguities.rs:4:40 diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr index 205d9b0b75ea..03e7910095a9 100644 --- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr +++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr @@ -2,19 +2,34 @@ error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:23:18 | LL | type A = fn() -> impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:25:18 | LL | type A = fn() -> impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:27:18 | LL | type A = fn() -> dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = fn() -> (dyn A + B); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A` --> $DIR/impl-trait-plus-priority.rs:29:10 @@ -26,43 +41,78 @@ error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:32:18 | LL | type A = Fn() -> impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:34:18 | LL | type A = Fn() -> impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:36:18 | LL | type A = Fn() -> dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = Fn() -> (dyn A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:40:11 | LL | type A = &impl A +; - | ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)` + | ^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(impl A +); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:42:11 | LL | type A = &impl A + B; - | ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)` + | ^^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(impl A + B); + | + + error: ambiguous `+` in a type --> $DIR/impl-trait-plus-priority.rs:44:11 | LL | type A = &dyn A + B; - | ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)` + | ^^^^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(dyn A + B); + | + + error[E0178]: expected a path on the left-hand side of `+`, not `&A` --> $DIR/impl-trait-plus-priority.rs:46:10 | LL | type A = &A + B; - | ^^^^^^ help: try adding parentheses: `&(A + B)` + | ^^^^^^ + | +help: try adding parentheses + | +LL | type A = &(A + B); + | + + error: aborting due to 11 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr index 6544837ba832..979c0ca6d7b6 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr @@ -16,10 +16,10 @@ LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } | | opaque type defined here | hidden type `&'a ()` captures the lifetime `'a` as defined here | -help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound +help: add `'a` to the `use<...>` bound to explicitly capture it | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x } - | ++++ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<'a> { x } + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs new file mode 100644 index 000000000000..e0b115b0ce41 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs @@ -0,0 +1,30 @@ +#![feature(precise_capturing)] + +fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn param<'a, T>(x: &'a ()) -> impl Sized + use { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn empty<'a>(x: &'a ()) -> impl Sized + use<> { +//~^ HELP add `'a` to the `use<...>` bound + x +//~^ ERROR hidden type for +} + +trait Captures<'a> {} +impl Captures<'_> for T {} + +fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> { +//~^ HELP add a `use<...>` bound + x +//~^ ERROR hidden type for +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr new file mode 100644 index 000000000000..391f16d012e4 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr @@ -0,0 +1,67 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:5:5 + | +LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { + | -- -------------------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b, 'a> { + | ++++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:11:5 + | +LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use { + | -- ------------------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<'a, T> { + | +++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:17:5 + | +LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<> { + | -- ------------------ opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add `'a` to the `use<...>` bound to explicitly capture it + | +LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<'a> { + | ++ + +error[E0700]: hidden type for `impl Captures<'captured>` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:26:5 + | +LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> { + | -- ------------------------ opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | x + | ^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> { + | ++++++++++++++++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/implied-bounds/dyn-erasure-no-tait.rs b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs new file mode 100644 index 000000000000..b5a8f421d3d6 --- /dev/null +++ b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs @@ -0,0 +1,53 @@ +//@ known-bug: #112905 +//@ check-pass + +// Classified as an issue with implied bounds: +// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 + +/// Note: this is sound! It's the "type witness" pattern (here, lt witness). +mod some_lib { + use super::T; + + /// Invariant in `'a` and `'b` for soundness. + pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>); + + impl<'a, 'b> LtEq<'a, 'b> { + pub fn new() -> LtEq<'a, 'a> { + LtEq(<_>::default()) + } + + pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> { + |a| unsafe { ::std::mem::transmute::, T<'b>>(a) } + } + } +} + +use some_lib::LtEq; +use std::{any::Any, cell::Cell}; + +/// Feel free to choose whatever you want, here. +type T<'lt> = Cell<&'lt str>; + +fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { + let f = LtEq::<'a, 'a>::new().eq(); + let any = Box::new(f) as Box; + + let new_f = None.map(LtEq::<'a, 'b>::eq); + + fn downcast_a_to_type_of_new_f(any: Box, _: Option) -> F { + *any.downcast().unwrap_or_else(|_| unreachable!()) + } + + let f = downcast_a_to_type_of_new_f(any, new_f); + + f(a) +} + +fn main() { + let r: T<'static> = { + let local = String::from("…"); + let a: T<'_> = Cell::new(&local[..]); + exploit(a) + }; + dbg!(r.get()); +} diff --git a/tests/ui/implied-bounds/dyn-erasure-tait.rs b/tests/ui/implied-bounds/dyn-erasure-tait.rs new file mode 100644 index 000000000000..4766d221d67c --- /dev/null +++ b/tests/ui/implied-bounds/dyn-erasure-tait.rs @@ -0,0 +1,39 @@ +//@ known-bug: #112905 +//@ check-pass + +// Classified as an issue with implied bounds: +// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 + +#![forbid(unsafe_code)] // No `unsafe!` +#![feature(type_alias_impl_trait)] + +use std::any::Any; + +/// Anything covariant will do, for this demo. +type T<'lt> = &'lt str; + +type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>; + +fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> { + |x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static` +} + +fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { + let f: F<'a, 'a> = helper([]); + let any = Box::new(f) as Box; + + let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!()); + + f(a) +} + +fn main() { + let r: T<'static> = { + let local = String::from("..."); + exploit(&local) + }; + // Since `r` now dangles, we can easily make the use-after-free + // point to newly allocated memory! + let _unrelated = String::from("UAF"); + dbg!(r); // may print `UAF`! Run with `miri` to see the UB. +} diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr new file mode 100644 index 000000000000..24574c8796b9 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr @@ -0,0 +1,41 @@ +error[E0583]: file not found for module `config` + --> $DIR/suggest-import-ice-issue-127302.rs:3:1 + | +LL | mod config; + | ^^^^^^^^^^^ + | + = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs" + = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead + +error: format argument must be a string literal + --> $DIR/suggest-import-ice-issue-127302.rs:10:14 + | +LL | println!(args.ctx.compiler.display()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", args.ctx.compiler.display()); + | +++++ + +error[E0425]: cannot find value `args` in this scope + --> $DIR/suggest-import-ice-issue-127302.rs:6:12 + | +LL | match &args.cmd { + | ^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::env::args; + | + +error[E0532]: expected unit struct, unit variant or constant, found module `crate::config` + --> $DIR/suggest-import-ice-issue-127302.rs:7:9 + | +LL | crate::config => {} + | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0532, E0583. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr new file mode 100644 index 000000000000..24574c8796b9 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr @@ -0,0 +1,41 @@ +error[E0583]: file not found for module `config` + --> $DIR/suggest-import-ice-issue-127302.rs:3:1 + | +LL | mod config; + | ^^^^^^^^^^^ + | + = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs" + = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead + +error: format argument must be a string literal + --> $DIR/suggest-import-ice-issue-127302.rs:10:14 + | +LL | println!(args.ctx.compiler.display()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", args.ctx.compiler.display()); + | +++++ + +error[E0425]: cannot find value `args` in this scope + --> $DIR/suggest-import-ice-issue-127302.rs:6:12 + | +LL | match &args.cmd { + | ^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::env::args; + | + +error[E0532]: expected unit struct, unit variant or constant, found module `crate::config` + --> $DIR/suggest-import-ice-issue-127302.rs:7:9 + | +LL | crate::config => {} + | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0532, E0583. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.rs b/tests/ui/imports/suggest-import-ice-issue-127302.rs new file mode 100644 index 000000000000..6b8d4c718310 --- /dev/null +++ b/tests/ui/imports/suggest-import-ice-issue-127302.rs @@ -0,0 +1,12 @@ +//@ revisions: edition2015 edition2021 + +mod config; //~ ERROR file not found for module + +fn main() { + match &args.cmd { //~ ERROR cannot find value `args` in this scope + crate::config => {} //~ ERROR expected unit struct, unit variant or constant, found module `crate::config` + } + + println!(args.ctx.compiler.display()); + //~^ ERROR format argument must be a string literal +} diff --git a/tests/ui/imports/suggest-import-issue-120074.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr similarity index 93% rename from tests/ui/imports/suggest-import-issue-120074.stderr rename to tests/ui/imports/suggest-import-issue-120074.edition2015.stderr index c1dff93bbdbf..414eeee0fedc 100644 --- a/tests/ui/imports/suggest-import-issue-120074.stderr +++ b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: unresolved import - --> $DIR/suggest-import-issue-120074.rs:10:35 + --> $DIR/suggest-import-issue-120074.rs:12:35 | LL | println!("Hello, {}!", crate::bar::do_the_thing); | ^^^ unresolved import diff --git a/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr new file mode 100644 index 000000000000..414eeee0fedc --- /dev/null +++ b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr @@ -0,0 +1,23 @@ +error[E0433]: failed to resolve: unresolved import + --> $DIR/suggest-import-issue-120074.rs:12:35 + | +LL | println!("Hello, {}!", crate::bar::do_the_thing); + | ^^^ unresolved import + | +help: a similar path exists + | +LL | println!("Hello, {}!", crate::foo::bar::do_the_thing); + | ~~~~~~~~ +help: consider importing this module + | +LL + use foo::bar; + | +help: if you import `bar`, refer to it directly + | +LL - println!("Hello, {}!", crate::bar::do_the_thing); +LL + println!("Hello, {}!", bar::do_the_thing); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs index a798e9eeeb80..7b6b5c73103a 100644 --- a/tests/ui/imports/suggest-import-issue-120074.rs +++ b/tests/ui/imports/suggest-import-issue-120074.rs @@ -1,3 +1,5 @@ +//@ revisions: edition2015 edition2021 + pub mod foo { pub mod bar { pub fn do_the_thing() -> usize { diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs index 3e401e99fb48..be9304e5829f 100644 --- a/tests/ui/issues/issue-22638.rs +++ b/tests/ui/issues/issue-22638.rs @@ -40,7 +40,6 @@ impl C { pub fn matches(&self, f: &F) { let &C(ref base) = self; base.matches(&|| { - //~^ ERROR reached the type-length limit C(base.clone()).matches(f) }) } @@ -53,6 +52,7 @@ impl D { pub fn matches(&self, f: &F) { let &D(ref a) = self; a.matches(f) + //~^ ERROR reached the recursion limit while instantiating } } diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr index 1344409c7704..96f179448683 100644 --- a/tests/ui/issues/issue-22638.stderr +++ b/tests/ui/issues/issue-22638.stderr @@ -1,13 +1,14 @@ -error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` - --> $DIR/issue-22638.rs:42:9 +error: reached the recursion limit while instantiating `A::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` + --> $DIR/issue-22638.rs:54:9 | -LL | / base.matches(&|| { -LL | | -LL | | C(base.clone()).matches(f) -LL | | }) - | |__________^ +LL | a.matches(f) + | ^^^^^^^^^^^^ | - = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate +note: `A::matches` defined here + --> $DIR/issue-22638.rs:13:5 + | +LL | pub fn matches(&self, f: &F) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27433.fixed b/tests/ui/issues/issue-27433.fixed index ff6704e393b5..f847b698976a 100644 --- a/tests/ui/issues/issue-27433.fixed +++ b/tests/ui/issues/issue-27433.fixed @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] let FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-27433.rs b/tests/ui/issues/issue-27433.rs index 2a34b43f58d2..9bbc5bcbb459 100644 --- a/tests/ui/issues/issue-27433.rs +++ b/tests/ui/issues/issue-27433.rs @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] const FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-27433.stderr b/tests/ui/issues/issue-27433.stderr index aba8e612858a..f6d5fc2b768f 100644 --- a/tests/ui/issues/issue-27433.stderr +++ b/tests/ui/issues/issue-27433.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-27433.rs:5:23 | LL | const FOO : u32 = foo; - | --------- ^^^ non-constant value - | | - | help: consider using `let` instead of `const`: `let FOO` + | ^^^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let FOO : u32 = foo; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/issues/issue-3521-2.stderr index 0be0e93c19e6..a12241cb1dfd 100644 --- a/tests/ui/issues/issue-3521-2.stderr +++ b/tests/ui/issues/issue-3521-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521-2.rs:5:23 | LL | static y: isize = foo + 1; - | -------- ^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let y` + | ^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let y: isize = foo + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr index 3676f388891e..9661dbf2f62f 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668-2.rs:4:27 | LL | static child: isize = x + 1; - | ------------ ^ non-constant value - | | - | help: consider using `let` instead of `static`: `let child` + | ^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let child: isize = x + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr index d761b2d87db4..7fad45f4b1a2 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668.rs:8:34 | LL | static childVal: Box

= self.child.get(); - | --------------- ^^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let childVal` + | ^^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let childVal: Box

= self.child.get(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs index 131c7535537f..96e2691164ba 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -15,7 +15,7 @@ impl Foo for T { #[allow(unconditional_recursion)] fn recurse(&self) { (self, self).recurse(); - //~^ ERROR reached the type-length limit + //~^ ERROR reached the recursion limit while instantiating } } diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index 2978ced52794..84ed97572b3a 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,10 +1,14 @@ -error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` +error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate +note: `::recurse` defined here + --> $DIR/issue-37311.rs:16:5 + | +LL | fn recurse(&self) { + | ^^^^^^^^^^^^^^^^^ = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-40782.stderr b/tests/ui/issues/issue-40782.stderr index 81f419bf687f..614980202385 100644 --- a/tests/ui/issues/issue-40782.stderr +++ b/tests/ui/issues/issue-40782.stderr @@ -2,13 +2,23 @@ error: missing `in` in `for` loop --> $DIR/issue-40782.rs:4:11 | LL | for _i 0..2 { - | ^ help: try adding `in` here + | ^ + | +help: try adding `in` here + | +LL | for _i in 0..2 { + | ++ error: missing `in` in `for` loop --> $DIR/issue-40782.rs:6:12 | LL | for _i of 0..2 { - | ^^ help: try using `in` here instead + | ^^ + | +help: try using `in` here instead + | +LL | for _i in 0..2 { + | ~~ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-44239.stderr b/tests/ui/issues/issue-44239.stderr index 633fb177b75d..1a047d4c63b6 100644 --- a/tests/ui/issues/issue-44239.stderr +++ b/tests/ui/issues/issue-44239.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-44239.rs:8:26 | -LL | let n: usize = 0; - | ----- help: consider using `const` instead of `let`: `const n` -... LL | const N: usize = n; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n: usize = 0; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index 4f3ddce69d82..6730865b6c7f 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,5 +1,4 @@ -//@ build-fail -//@ error-pattern: reached the type-length limit while instantiating +//@ build-pass //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr deleted file mode 100644 index 975fcd4afffe..000000000000 --- a/tests/ui/iterators/issue-58952-filter-type-length.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: reached the type-length limit while instantiating ` as Iterator>::try_fold::, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>` - --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL - | - = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt' - -error: aborting due to 1 previous error - diff --git a/tests/ui/label/label_misspelled_2.stderr b/tests/ui/label/label_misspelled_2.stderr index 960646d9894d..10b0e7b4e088 100644 --- a/tests/ui/label/label_misspelled_2.stderr +++ b/tests/ui/label/label_misspelled_2.stderr @@ -2,13 +2,23 @@ error: malformed loop label --> $DIR/label_misspelled_2.rs:10:5 | LL | c: for _ in 0..1 { - | ^ help: use the correct loop label format: `'c` + | ^ + | +help: use the correct loop label format + | +LL | 'c: for _ in 0..1 { + | + error: malformed loop label --> $DIR/label_misspelled_2.rs:13:5 | LL | d: for _ in 0..1 { - | ^ help: use the correct loop label format: `'d` + | ^ + | +help: use the correct loop label format + | +LL | 'd: for _ in 0..1 { + | + error[E0425]: cannot find value `b` in this scope --> $DIR/label_misspelled_2.rs:8:15 diff --git a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr index 1a21fed63bde..da80991c727f 100644 --- a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr +++ b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr @@ -26,7 +26,12 @@ error: bare CR not allowed in string, use `\r` instead --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18 | LL | let _s = "foo bar"; - | ^ help: escape the character: `\r` + | ^ + | +help: escape the character + | +LL | let _s = "foo\rbar"; + | ++ error: bare CR not allowed in raw string --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19 diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs new file mode 100644 index 000000000000..6f2ead70db80 --- /dev/null +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs @@ -0,0 +1,14 @@ +#![feature(unsafe_extern_blocks)] +#![deny(unsafe_code)] + +#[allow(unsafe_code)] +unsafe extern "C" { + fn foo(); +} + +unsafe extern "C" { + //~^ ERROR usage of an `unsafe extern` block [unsafe_code] + fn bar(); +} + +fn main() {} diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr new file mode 100644 index 000000000000..5439a3112560 --- /dev/null +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr @@ -0,0 +1,17 @@ +error: usage of an `unsafe extern` block + --> $DIR/unsafe-extern-blocks.rs:9:1 + | +LL | / unsafe extern "C" { +LL | | +LL | | fn bar(); +LL | | } + | |_^ + | +note: the lint level is defined here + --> $DIR/unsafe-extern-blocks.rs:2:9 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/recovery-allowed.stderr b/tests/ui/macros/recovery-allowed.stderr index 44689853dabc..825f7a8faf8e 100644 --- a/tests/ui/macros/recovery-allowed.stderr +++ b/tests/ui/macros/recovery-allowed.stderr @@ -2,9 +2,12 @@ error: unexpected `1` after identifier --> $DIR/recovery-allowed.rs:5:23 | LL | please_recover! { not 1 } - | ----^ - | | - | help: use `!` to perform bitwise not + | ^ + | +help: use `!` to perform bitwise not + | +LL | please_recover! { !1 } + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/malformed/malformed-special-attrs.stderr b/tests/ui/malformed/malformed-special-attrs.stderr index 1764c3969cfe..8f2ce20593f5 100644 --- a/tests/ui/malformed/malformed-special-attrs.stderr +++ b/tests/ui/malformed/malformed-special-attrs.stderr @@ -2,17 +2,25 @@ error: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:1:1 | LL | #[cfg_attr] - | ^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:4:1 | LL | #[cfg_attr = ""] - | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | ^^^^^^^^^^^^^^^^ | = note: for more information, visit +help: missing condition and attribute + | +LL | #[cfg_attr(condition, attribute, other_attribute, ...)] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs new file mode 100644 index 000000000000..76ececf7baa7 --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -0,0 +1,23 @@ +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(self, _: F) + //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + where + F: for<'a> FnOnce(>::Type), + //~^ ERROR the trait bound `F: Output<'_>` is not satisfied + //~| ERROR the trait bound `F: Output<'_>` is not satisfied + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); + //~^ ERROR expected a `FnOnce +} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr new file mode 100644 index 000000000000..b737c0ab11fd --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -0,0 +1,74 @@ +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:5 + | +LL | / fn do_something_wrapper(self, _: F) +LL | | +LL | | +LL | | where +LL | | F: for<'a> FnOnce(>::Type), + | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:8 + | +LL | fn do_something_wrapper(self, _: F) + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:20 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + --> $DIR/filter-relevant-fn-bounds.rs:21:34 + | +LL | wrapper.do_something_wrapper(|value| ()); + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` +help: this trait has no implementations, consider adding one + --> $DIR/filter-relevant-fn-bounds.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | fn do_something_wrapper(self, _: F) + | -------------------- required by a bound in this associated function +... +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs new file mode 100644 index 000000000000..f589e88f68e4 --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -0,0 +1,18 @@ +// Regression test for . +#![crate_type = "lib"] + +pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + arg //~ ERROR 5:5: 5:8: mismatched types [E0308] +} + +pub fn bar(arg: Option<&Vec>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308] +} + +pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] +} + +pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr new file mode 100644 index 000000000000..ad423f86ef9e --- /dev/null +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -0,0 +1,90 @@ +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:5:5 + | +LL | pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { + | -------------- expected `Option<&[i32]>` because of return type +LL | arg + | ^^^ expected `Option<&[i32]>`, found `Option<&Vec>` + | + = note: expected enum `Option<&[i32]>` + found enum `Option<&Vec>` +help: try using `.map(|v| &**v)` to convert `Option<&Vec>` to `Option<&[i32]>` + | +LL | arg.map(|v| &**v) + | ++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:9:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:9:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~ +++++++ + +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:13:19 + | +LL | arg.unwrap_or(v) + | --------- ^ expected `&Vec`, found `&[i32]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&'a [i32]` +help: the return type of this call is `&'a [i32]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:13:5 + | +LL | arg.unwrap_or(v) + | ^^^^^^^^^^^^^^-^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(v, |v| v) + | ~~~~~~ +++++++ + +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:17:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:17:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/result.rs:LL:COL +help: use `Result::map_or` to deref inner value of `Result` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~ +++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.fixed b/tests/ui/moves/moved-value-on-as-ref-arg.fixed new file mode 100644 index 000000000000..292fa98a3f71 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.fixed @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(unused_mut)] +use std::borrow::{Borrow, BorrowMut}; +use std::convert::{AsMut, AsRef}; +struct Bar; + +impl AsRef for Bar { + fn as_ref(&self) -> &Bar { + self + } +} + +impl AsMut for Bar { + fn as_mut(&mut self) -> &mut Bar { + self + } +} + +fn foo>(_: T) {} +fn qux>(_: T) {} +fn bat>(_: T) {} +fn baz>(_: T) {} + +pub fn main() { + let bar = Bar; + foo(&bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + qux(&mut bar); + let _baa = bar; //~ ERROR use of moved value + let bar = Bar; + bat(&bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + baz(&mut bar); + let _baa = bar; //~ ERROR use of moved value +} diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.rs b/tests/ui/moves/moved-value-on-as-ref-arg.rs new file mode 100644 index 000000000000..632af9efcda3 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.rs @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(unused_mut)] +use std::borrow::{Borrow, BorrowMut}; +use std::convert::{AsMut, AsRef}; +struct Bar; + +impl AsRef for Bar { + fn as_ref(&self) -> &Bar { + self + } +} + +impl AsMut for Bar { + fn as_mut(&mut self) -> &mut Bar { + self + } +} + +fn foo>(_: T) {} +fn qux>(_: T) {} +fn bat>(_: T) {} +fn baz>(_: T) {} + +pub fn main() { + let bar = Bar; + foo(bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + qux(bar); + let _baa = bar; //~ ERROR use of moved value + let bar = Bar; + bat(bar); + let _baa = bar; //~ ERROR use of moved value + let mut bar = Bar; + baz(bar); + let _baa = bar; //~ ERROR use of moved value +} diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.stderr b/tests/ui/moves/moved-value-on-as-ref-arg.stderr new file mode 100644 index 000000000000..4004b7a43bc0 --- /dev/null +++ b/tests/ui/moves/moved-value-on-as-ref-arg.stderr @@ -0,0 +1,79 @@ +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:27:16 + | +LL | let bar = Bar; + | --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | foo(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +help: borrow the value to avoid moving it + | +LL | foo(&bar); + | + + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:30:16 + | +LL | let mut bar = Bar; + | ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | qux(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +note: if `Bar` implemented `Clone`, you could clone the value + --> $DIR/moved-value-on-as-ref-arg.rs:5:1 + | +LL | struct Bar; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | qux(bar); + | --- you could clone this value +help: borrow the value to avoid moving it + | +LL | qux(&mut bar); + | ++++ + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:33:16 + | +LL | let bar = Bar; + | --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | bat(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +help: borrow the value to avoid moving it + | +LL | bat(&bar); + | + + +error[E0382]: use of moved value: `bar` + --> $DIR/moved-value-on-as-ref-arg.rs:36:16 + | +LL | let mut bar = Bar; + | ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait +LL | baz(bar); + | --- value moved here +LL | let _baa = bar; + | ^^^ value used here after move + | +note: if `Bar` implemented `Clone`, you could clone the value + --> $DIR/moved-value-on-as-ref-arg.rs:5:1 + | +LL | struct Bar; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | baz(bar); + | --- you could clone this value +help: borrow the value to avoid moving it + | +LL | baz(&mut bar); + | ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr index 517f910080de..4ff45d7a8485 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/avoid-ice-on-warning.rs:4:23 | LL | fn call_this(f: F) : Fn(&str) + call_that {} - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn call_this(f: F) -> Fn(&str) + call_that {} + | ~~ error[E0405]: cannot find trait `call_that` in this scope --> $DIR/avoid-ice-on-warning.rs:4:36 diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr index 3939c06eabe5..de45ec8c405a 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/avoid-ice-on-warning.rs:4:23 | LL | fn call_this(f: F) : Fn(&str) + call_that {} - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn call_this(f: F) -> Fn(&str) + call_that {} + | ~~ error[E0405]: cannot find trait `call_that` in this scope --> $DIR/avoid-ice-on-warning.rs:4:36 diff --git a/tests/ui/operator-recovery/less-than-greater-than.stderr b/tests/ui/operator-recovery/less-than-greater-than.stderr index 21b2e77db9aa..36a4a81035f1 100644 --- a/tests/ui/operator-recovery/less-than-greater-than.stderr +++ b/tests/ui/operator-recovery/less-than-greater-than.stderr @@ -2,7 +2,12 @@ error: invalid comparison operator `<>` --> $DIR/less-than-greater-than.rs:2:22 | LL | println!("{}", 1 <> 2); - | ^^ help: `<>` is not a valid comparison operator, use `!=` + | ^^ + | +help: `<>` is not a valid comparison operator, use `!=` + | +LL | println!("{}", 1 != 2); + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.stderr b/tests/ui/or-patterns/fn-param-wrap-parens.stderr index 1b9614a13782..da2832ef1ae4 100644 --- a/tests/ui/or-patterns/fn-param-wrap-parens.stderr +++ b/tests/ui/or-patterns/fn-param-wrap-parens.stderr @@ -2,7 +2,12 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/fn-param-wrap-parens.rs:13:9 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun1((A | B): E) {} + | + + error: aborting due to 1 previous error diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr index 9b827794f5be..91db3d049f62 100644 --- a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr +++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr @@ -4,7 +4,13 @@ error: a trailing `|` is not allowed in an or-pattern LL | E::A | | ---- while parsing this or-pattern starting here LL | E::B | - | ^ help: remove the `|` + | ^ + | +help: remove the `|` + | +LL - E::B | +LL + E::B + | error[E0308]: mismatched types --> $DIR/issue-64879-trailing-before-guard.rs:12:42 diff --git a/tests/ui/or-patterns/multiple-pattern-typo.stderr b/tests/ui/or-patterns/multiple-pattern-typo.stderr index b0a82b3673b8..2e66f54979b0 100644 --- a/tests/ui/or-patterns/multiple-pattern-typo.stderr +++ b/tests/ui/or-patterns/multiple-pattern-typo.stderr @@ -2,55 +2,90 @@ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:7:15 | LL | 1 | 2 || 3 => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | 1 | 2 | 3 => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:12:16 | LL | (1 | 2 || 3) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | (1 | 2 | 3) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:17:16 | LL | (1 | 2 || 3,) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | (1 | 2 | 3,) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:24:18 | LL | TS(1 | 2 || 3) => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | TS(1 | 2 | 3) => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:31:23 | LL | NS { f: 1 | 2 || 3 } => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | NS { f: 1 | 2 | 3 } => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:36:16 | LL | [1 | 2 || 3] => (), - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | [1 | 2 | 3] => (), + | ~ error: unexpected token `||` in pattern --> $DIR/multiple-pattern-typo.rs:41:9 | LL | || 1 | 2 | 3 => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | | 1 | 2 | 3 => (), + | ~ error: aborting due to 7 previous errors diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr index 5a63e621f4a3..f16d83ecaea9 100644 --- a/tests/ui/or-patterns/nested-undelimited-precedence.stderr +++ b/tests/ui/or-patterns/nested-undelimited-precedence.stderr @@ -2,31 +2,56 @@ error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:19:9 | LL | let b @ A | B: E = A; - | ^^^^^^^^^ help: wrap the pattern in parentheses: `(b @ A | B)` + | ^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (b @ A | B): E = A; + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:34:9 | LL | let &A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&A(_) | B(_))` + | ^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:36:9 | LL | let &&A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&A(_) | B(_))` + | ^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&&A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:38:9 | LL | let &mut A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&mut A(_) | B(_))` + | ^^^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&mut A(_) | B(_)): F = A(3); + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/nested-undelimited-precedence.rs:40:9 | LL | let &&mut A(_) | B(_): F = A(3); - | ^^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&mut A(_) | B(_))` + | ^^^^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (&&mut A(_) | B(_)): F = A(3); + | + + error[E0408]: variable `b` is not bound in all patterns --> $DIR/nested-undelimited-precedence.rs:19:17 diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr index e09194d5d397..5608138078fb 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -16,25 +16,45 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/or-patterns-syntactic-fail.rs:18:13 | LL | fn fun1(A | B: E) {} - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun1((A | B): E) {} + | + + error: top-level or-patterns are not allowed in function parameters --> $DIR/or-patterns-syntactic-fail.rs:21:13 | LL | fn fun2(| A | B: E) {} - | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | fn fun2((| A | B): E) {} + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/or-patterns-syntactic-fail.rs:26:9 | LL | let A | B: E = A; - | ^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (A | B): E = A; + | + + error: top-level or-patterns are not allowed in `let` bindings --> $DIR/or-patterns-syntactic-fail.rs:29:9 | LL | let | A | B: E = A; - | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)` + | ^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (| A | B): E = A; + | + + error: aborting due to 5 previous errors diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed index 8f7aab6a4991..3ec815c84684 100644 --- a/tests/ui/or-patterns/remove-leading-vert.fixed +++ b/tests/ui/or-patterns/remove-leading-vert.fixed @@ -8,7 +8,7 @@ fn main() {} #[cfg(FALSE)] fn leading() { - fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed + fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter let ( | A): E; let ( | A): (E); //~ ERROR unexpected token `||` in pattern diff --git a/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr index af51c67e1c8b..5177e98f0d90 100644 --- a/tests/ui/or-patterns/remove-leading-vert.stderr +++ b/tests/ui/or-patterns/remove-leading-vert.stderr @@ -2,161 +2,279 @@ error: top-level or-patterns are not allowed in function parameters --> $DIR/remove-leading-vert.rs:11:14 | LL | fn fun1( | A: E) {} - | ^^^ help: remove the `|`: `A` + | ^^^ + | +help: remove the `|` + | +LL - fn fun1( | A: E) {} +LL + fn fun1( A: E) {} + | error: unexpected `||` before function parameter --> $DIR/remove-leading-vert.rs:12:14 | LL | fn fun2( || A: E) {} - | ^^ help: remove the `||` + | ^^ | = note: alternatives in or-patterns are separated with `|`, not `||` +help: remove the `||` + | +LL - fn fun2( || A: E) {} +LL + fn fun2( A: E) {} + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:14:11 | LL | let ( || A): (E); - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let ( | A): (E); + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:17:11 | LL | let [ || A ]: [E; 1]; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let [ | A ]: [E; 1]; + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:19:13 | LL | let TS( || A ): TS; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let TS( | A ): TS; + | ~ error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:21:17 | LL | let NS { f: || A }: NS; - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | ^^ + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let NS { f: | A }: NS; + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:26:13 | LL | let ( A | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A | ): E; +LL + let ( A ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:27:12 | LL | let (a |,): (E,); - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let (a |,): (E,); +LL + let (a ,): (E,); + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:28:17 | LL | let ( A | B | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A | B | ): E; +LL + let ( A | B ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:29:17 | LL | let [ A | B | ]: [E; 1]; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let [ A | B | ]: [E; 1]; +LL + let [ A | B ]: [E; 1]; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:30:18 | LL | let S { f: B | }; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let S { f: B | }; +LL + let S { f: B }; + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:31:13 | LL | let ( A || B | ): E; - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | let ( A | B | ): E; + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:31:18 | LL | let ( A || B | ): E; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let ( A || B | ): E; +LL + let ( A || B ): E; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:34:11 | LL | A | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - A | => {} +LL + A => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:35:11 | LL | A || => {} - | - ^^ help: remove the `||` + | - ^^ | | | while parsing this or-pattern starting here | = note: alternatives in or-patterns are separated with `|`, not `||` +help: remove the `||` + | +LL - A || => {} +LL + A => {} + | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:36:11 | LL | A || B | => {} - | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ | | | while parsing this or-pattern starting here + | +help: use a single `|` to separate multiple alternative patterns + | +LL | A | B | => {} + | ~ error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:36:16 | LL | A || B | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - A || B | => {} +LL + A || B => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:38:17 | LL | | A | B | => {} - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - | A | B | => {} +LL + | A | B => {} + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:45:11 | LL | let a | : u8 = 0; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | : u8 = 0; +LL + let a : u8 = 0; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:46:11 | LL | let a | = 0; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | = 0; +LL + let a = 0; + | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:47:11 | LL | let a | ; - | - ^ help: remove the `|` + | - ^ | | | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - let a | ; +LL + let a ; + | error: aborting due to 21 previous errors diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index 3593c5182ce9..1ba130e20b57 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -154,9 +154,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:40:38 @@ -178,9 +183,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:46:46 @@ -196,18 +206,28 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } | ---- ^^^^^^^ ------- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } + | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:50:50 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:52:51 @@ -223,9 +243,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:56:46 @@ -247,9 +272,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } | ---- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:62:54 @@ -265,18 +295,28 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } | ---- ^^^^^^^ --------------- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `else` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } + | error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:66:66 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } | -- ^^^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } +LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; } + | error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:68:67 @@ -361,9 +401,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:85:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:85:38 @@ -375,9 +420,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 @@ -395,9 +445,14 @@ error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:93:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } +LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } } + | error: expected one of `=>`, `if`, or `|`, found `#` --> $DIR/attr-stmt-expr-attr-bad.rs:93:38 diff --git a/tests/ui/parser/bad-char-literals.stderr b/tests/ui/parser/bad-char-literals.stderr index a22ddbac1b93..89253d7d4aac 100644 --- a/tests/ui/parser/bad-char-literals.stderr +++ b/tests/ui/parser/bad-char-literals.stderr @@ -2,7 +2,12 @@ error: character constant must be escaped: `'` --> $DIR/bad-char-literals.rs:6:6 | LL | '''; - | ^ help: escape the character: `\'` + | ^ + | +help: escape the character + | +LL | '\''; + | ~~ error: character constant must be escaped: `\n` --> $DIR/bad-char-literals.rs:10:6 @@ -10,19 +15,34 @@ error: character constant must be escaped: `\n` LL | ' | ______^ LL | | '; - | |_ help: escape the character: `\n` + | |_ + | +help: escape the character + | +LL | '\n'; + | ++ error: character constant must be escaped: `\r` --> $DIR/bad-char-literals.rs:15:6 | LL | ' '; - | ^ help: escape the character: `\r` + | ^ + | +help: escape the character + | +LL | '\r'; + | ++ error: character constant must be escaped: `\t` --> $DIR/bad-char-literals.rs:18:6 | LL | ' '; - | ^^^^ help: escape the character: `\t` + | ^^^^ + | +help: escape the character + | +LL | '\t'; + | ++ error: aborting due to 4 previous errors diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr index 265e31329ca5..523ee47b0c94 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr @@ -5,7 +5,12 @@ LL | pub type T0 = const fn(); | -----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T0 = const fn(); +LL + pub type T0 = fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:6:15 @@ -14,7 +19,12 @@ LL | pub type T1 = const extern "C" fn(); | -----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T1 = const extern "C" fn(); +LL + pub type T1 = extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:7:15 @@ -23,7 +33,12 @@ LL | pub type T2 = const unsafe extern fn(); | -----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T2 = const unsafe extern fn(); +LL + pub type T2 = unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:8:15 @@ -32,7 +47,12 @@ LL | pub type T3 = async fn(); | -----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T3 = async fn(); +LL + pub type T3 = fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:9:15 @@ -41,7 +61,12 @@ LL | pub type T4 = async extern fn(); | -----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T4 = async extern fn(); +LL + pub type T4 = extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:10:15 @@ -50,7 +75,12 @@ LL | pub type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T5 = async unsafe extern "C" fn(); +LL + pub type T5 = unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:11:15 @@ -59,7 +89,12 @@ LL | pub type T6 = const async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type T6 = const async unsafe extern "C" fn(); +LL + pub type T6 = async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:11:15 @@ -68,7 +103,12 @@ LL | pub type T6 = const async unsafe extern "C" fn(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type T6 = const async unsafe extern "C" fn(); +LL + pub type T6 = const unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:15:17 @@ -77,7 +117,12 @@ LL | pub type FTT0 = for<'a> const fn(); | ^^^^^^^^-----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT0 = for<'a> const fn(); +LL + pub type FTT0 = for<'a> fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:16:17 @@ -86,7 +131,12 @@ LL | pub type FTT1 = for<'a> const extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT1 = for<'a> const extern "C" fn(); +LL + pub type FTT1 = for<'a> extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:17:17 @@ -95,7 +145,12 @@ LL | pub type FTT2 = for<'a> const unsafe extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT2 = for<'a> const unsafe extern fn(); +LL + pub type FTT2 = for<'a> unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:18:17 @@ -104,7 +159,12 @@ LL | pub type FTT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT3 = for<'a> async fn(); +LL + pub type FTT3 = for<'a> fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:19:17 @@ -113,7 +173,12 @@ LL | pub type FTT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT4 = for<'a> async extern fn(); +LL + pub type FTT4 = for<'a> extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:20:17 @@ -122,7 +187,12 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT5 = for<'a> async unsafe extern "C" fn(); +LL + pub type FTT5 = for<'a> unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:22:17 @@ -131,7 +201,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:22:17 @@ -140,7 +215,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); +LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); + | error: aborting due to 16 previous errors diff --git a/tests/ui/parser/byte-literals.stderr b/tests/ui/parser/byte-literals.stderr index 5b414c8927e2..25e319954418 100644 --- a/tests/ui/parser/byte-literals.stderr +++ b/tests/ui/parser/byte-literals.stderr @@ -24,13 +24,23 @@ error: byte constant must be escaped: `\t` --> $DIR/byte-literals.rs:8:7 | LL | b' '; - | ^^^^ help: escape the character: `\t` + | ^^^^ + | +help: escape the character + | +LL | b'\t'; + | ++ error: byte constant must be escaped: `'` --> $DIR/byte-literals.rs:9:7 | LL | b'''; - | ^ help: escape the character: `\'` + | ^ + | +help: escape the character + | +LL | b'\''; + | ~~ error: non-ASCII character in byte literal --> $DIR/byte-literals.rs:10:7 diff --git a/tests/ui/parser/char/whitespace-character-literal.stderr b/tests/ui/parser/char/whitespace-character-literal.stderr index 3bd048f8f622..f273b5d61d57 100644 --- a/tests/ui/parser/char/whitespace-character-literal.stderr +++ b/tests/ui/parser/char/whitespace-character-literal.stderr @@ -2,15 +2,17 @@ error: character literal may only contain one codepoint --> $DIR/whitespace-character-literal.rs:5:30 | LL | let _hair_space_around = ' x​'; - | ^--^ - | | - | help: consider removing the non-printing characters: `x` + | ^^^^ | note: there are non-printing characters, the full sequence is `\u{200a}x\u{200b}` --> $DIR/whitespace-character-literal.rs:5:31 | LL | let _hair_space_around = ' x​'; | ^^ +help: consider removing the non-printing characters + | +LL | let _hair_space_around = 'x​'; + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/default-on-wrong-item-kind.stderr b/tests/ui/parser/default-on-wrong-item-kind.stderr index af513f7617b0..392c85e0c43d 100644 --- a/tests/ui/parser/default-on-wrong-item-kind.stderr +++ b/tests/ui/parser/default-on-wrong-item-kind.stderr @@ -154,11 +154,13 @@ error: extern items cannot be `const` --> $DIR/default-on-wrong-item-kind.rs:38:19 | LL | default const foo: u8; - | --------------^^^ - | | - | help: try using a static value: `static` + | ^^^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static foo: u8; + | ~~~~~~ error: a module cannot be `default` --> $DIR/default-on-wrong-item-kind.rs:41:5 diff --git a/tests/ui/parser/do-catch-suggests-try.stderr b/tests/ui/parser/do-catch-suggests-try.stderr index cd8907b7eac9..fd3406ae29f8 100644 --- a/tests/ui/parser/do-catch-suggests-try.stderr +++ b/tests/ui/parser/do-catch-suggests-try.stderr @@ -2,9 +2,13 @@ error: found removed `do catch` syntax --> $DIR/do-catch-suggests-try.rs:4:25 | LL | let _: Option<()> = do catch {}; - | ^^^^^^^^ help: replace with the new syntax: `try` + | ^^^^^^^^ | = note: following RFC #2388, the new non-placeholder syntax is `try` +help: replace with the new syntax + | +LL | let _: Option<()> = try {}; + | ~~~ error[E0308]: mismatched types --> $DIR/do-catch-suggests-try.rs:9:33 diff --git a/tests/ui/parser/doc-comment-in-if-statement.stderr b/tests/ui/parser/doc-comment-in-if-statement.stderr index fc0bc507370a..37e0c398a61a 100644 --- a/tests/ui/parser/doc-comment-in-if-statement.stderr +++ b/tests/ui/parser/doc-comment-in-if-statement.stderr @@ -16,9 +16,14 @@ error: outer attributes are not allowed on `if` and `else` branches | LL | if true /*!*/ {} | -- ^^^^^ -- the attributes are attached to this branch - | | | - | | help: remove the attributes + | | | the branch belongs to this `if` + | +help: remove the attributes + | +LL - if true /*!*/ {} +LL + if true {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr index 90082f98cb5f..221e3a74d79f 100644 --- a/tests/ui/parser/expr-rarrow-call.stderr +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -2,41 +2,61 @@ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:14:10 | LL | named->foo; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | named.foo; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:18:12 | LL | unnamed->0; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | unnamed.0; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:22:6 | LL | t->0; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | t.0; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:23:6 | LL | t->1; - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | t.1; + | ~ error: `->` used for field access or method call --> $DIR/expr-rarrow-call.rs:30:8 | LL | foo->clone(); - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | foo.clone(); + | ~ error: aborting due to 5 previous errors diff --git a/tests/ui/parser/fn-colon-return-type.stderr b/tests/ui/parser/fn-colon-return-type.stderr index b61a62a17f7e..c1cdf4d4975a 100644 --- a/tests/ui/parser/fn-colon-return-type.stderr +++ b/tests/ui/parser/fn-colon-return-type.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/fn-colon-return-type.rs:1:15 | LL | fn foo(x: i32): i32 { - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn foo(x: i32) -> i32 { + | ~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/foreign-const-semantic-fail.stderr b/tests/ui/parser/foreign-const-semantic-fail.stderr index 8dc66c0d012c..d317847f98ad 100644 --- a/tests/ui/parser/foreign-const-semantic-fail.stderr +++ b/tests/ui/parser/foreign-const-semantic-fail.stderr @@ -2,21 +2,25 @@ error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:4:11 | LL | const A: isize; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static A: isize; + | ~~~~~~ error: extern items cannot be `const` --> $DIR/foreign-const-semantic-fail.rs:6:11 | LL | const B: isize = 42; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static B: isize = 42; + | ~~~~~~ error: incorrect `static` inside `extern` block --> $DIR/foreign-const-semantic-fail.rs:6:11 diff --git a/tests/ui/parser/foreign-const-syntactic-fail.stderr b/tests/ui/parser/foreign-const-syntactic-fail.stderr index 9cf58fa95fb2..7da2c0190228 100644 --- a/tests/ui/parser/foreign-const-syntactic-fail.stderr +++ b/tests/ui/parser/foreign-const-syntactic-fail.stderr @@ -2,21 +2,25 @@ error: extern items cannot be `const` --> $DIR/foreign-const-syntactic-fail.rs:7:11 | LL | const A: isize; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static A: isize; + | ~~~~~~ error: extern items cannot be `const` --> $DIR/foreign-const-syntactic-fail.rs:8:11 | LL | const B: isize = 42; - | ------^ - | | - | help: try using a static value: `static` + | ^ | = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html +help: try using a static value + | +LL | static B: isize = 42; + | ~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/ice-issue-127600.rs b/tests/ui/parser/ice-issue-127600.rs new file mode 100644 index 000000000000..709c10253266 --- /dev/null +++ b/tests/ui/parser/ice-issue-127600.rs @@ -0,0 +1,2 @@ +const!(&raw mut a); +//~^ ERROR expected identifier, found `!` diff --git a/tests/ui/parser/ice-issue-127600.stderr b/tests/ui/parser/ice-issue-127600.stderr new file mode 100644 index 000000000000..629fc4ae40b6 --- /dev/null +++ b/tests/ui/parser/ice-issue-127600.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `!` + --> $DIR/ice-issue-127600.rs:1:6 + | +LL | const!(&raw mut a); + | ^ expected identifier + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr index e9a55026d124..83666014eb25 100644 --- a/tests/ui/parser/ident-recovery.stderr +++ b/tests/ui/parser/ident-recovery.stderr @@ -2,19 +2,25 @@ error: expected identifier, found `,` --> $DIR/ident-recovery.rs:1:4 | LL | fn ,comma() { - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - fn ,comma() { +LL + fn comma() { + | error: expected identifier, found `,` --> $DIR/ident-recovery.rs:4:16 | LL | x: i32,, - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - x: i32,, +LL + x: i32, + | error: expected identifier, found keyword `break` --> $DIR/ident-recovery.rs:10:4 diff --git a/tests/ui/parser/if-in-in.stderr b/tests/ui/parser/if-in-in.stderr index 6117370c0ce6..d8def76792e2 100644 --- a/tests/ui/parser/if-in-in.stderr +++ b/tests/ui/parser/if-in-in.stderr @@ -2,9 +2,13 @@ error: expected iterable, found keyword `in` --> $DIR/if-in-in.rs:4:14 | LL | for i in in 1..2 { - | ---^^ - | | - | help: remove the duplicated `in` + | ^^ + | +help: remove the duplicated `in` + | +LL - for i in in 1..2 { +LL + for i in 1..2 { + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr index a57cc075ccc9..6a24a9453e63 100644 --- a/tests/ui/parser/impl-parsing.stderr +++ b/tests/ui/parser/impl-parsing.stderr @@ -2,13 +2,23 @@ error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:4:11 | LL | impl Trait Type {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl Trait for Type {} + | +++ error: missing `for` in a trait impl --> $DIR/impl-parsing.rs:5:11 | LL | impl Trait .. {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl Trait for .. {} + | +++ error: expected a trait, found type --> $DIR/impl-parsing.rs:6:6 diff --git a/tests/ui/parser/intersection-patterns-1.stderr b/tests/ui/parser/intersection-patterns-1.stderr index dc968656c91f..ed2466b21a75 100644 --- a/tests/ui/parser/intersection-patterns-1.stderr +++ b/tests/ui/parser/intersection-patterns-1.stderr @@ -6,7 +6,11 @@ LL | Some(x) @ y => {} | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `y @ Some(x)` + | +help: switch the order + | +LL | y @ Some(x) => {} + | ~~~~~~~~~~~ error: pattern on wrong side of `@` --> $DIR/intersection-patterns-1.rs:27:9 @@ -16,7 +20,11 @@ LL | 1 ..= 5 @ e => {} | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `e @ 1..=5` + | +help: switch the order + | +LL | e @ 1..=5 => {} + | ~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs index 3c0059ba3e3e..c9fb08506ddb 100644 --- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs @@ -2,5 +2,6 @@ // Tests that we do not erroneously emit an error about // missing main function when the mod starts with a `;` -; //~ ERROR expected item, found `;` +; +//~^ ERROR expected item, found `;` fn main() { } diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr index 9776677589f5..002dc028cf55 100644 --- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr @@ -2,7 +2,12 @@ error: expected item, found `;` --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1 | LL | ; - | ^ help: remove this semicolon + | ^ + | +help: remove this semicolon + | +LL - ; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-100197-mut-let.stderr b/tests/ui/parser/issues/issue-100197-mut-let.stderr index 07d136881408..252ed7d0715d 100644 --- a/tests/ui/parser/issues/issue-100197-mut-let.stderr +++ b/tests/ui/parser/issues/issue-100197-mut-let.stderr @@ -2,7 +2,12 @@ error: invalid variable declaration --> $DIR/issue-100197-mut-let.rs:4:5 | LL | mut let _x = 123; - | ^^^^^^^ help: switch the order of `mut` and `let`: `let mut` + | ^^^^^^^ + | +help: switch the order of `mut` and `let` + | +LL | let mut _x = 123; + | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-101477-enum.stderr b/tests/ui/parser/issues/issue-101477-enum.stderr index 94130671f1c9..c6dadeab8b33 100644 --- a/tests/ui/parser/issues/issue-101477-enum.stderr +++ b/tests/ui/parser/issues/issue-101477-enum.stderr @@ -2,9 +2,14 @@ error: unexpected `==` --> $DIR/issue-101477-enum.rs:6:7 | LL | B == 2 - | ^^ help: try using `=` instead + | ^^ | = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` +help: try using `=` instead + | +LL - B == 2 +LL + B = 2 + | error: expected item, found `==` --> $DIR/issue-101477-enum.rs:6:7 diff --git a/tests/ui/parser/issues/issue-101477-let.stderr b/tests/ui/parser/issues/issue-101477-let.stderr index 56348357397f..59e90c8102f7 100644 --- a/tests/ui/parser/issues/issue-101477-let.stderr +++ b/tests/ui/parser/issues/issue-101477-let.stderr @@ -2,7 +2,13 @@ error: unexpected `==` --> $DIR/issue-101477-let.rs:4:11 | LL | let x == 2; - | ^^ help: try using `=` instead + | ^^ + | +help: try using `=` instead + | +LL - let x == 2; +LL + let x = 2; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr index 86d3449cc33b..e5c6ba27755e 100644 --- a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr +++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr @@ -2,13 +2,23 @@ error: missing parameters for function definition --> $DIR/issue-108109-fn-missing-params.rs:3:15 | LL | pub fn missing -> () {} - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | pub fn missing() -> () {} + | ++ error: missing parameters for function definition --> $DIR/issue-108109-fn-missing-params.rs:6:16 | LL | pub fn missing2 {} - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | pub fn missing2() {} + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-113203.stderr b/tests/ui/parser/issues/issue-113203.stderr index 5db628d59776..1ef20ddf7261 100644 --- a/tests/ui/parser/issues/issue-113203.stderr +++ b/tests/ui/parser/issues/issue-113203.stderr @@ -2,7 +2,13 @@ error: incorrect use of `await` --> $DIR/issue-113203.rs:5:5 | LL | await {}() - | ^^^^^^^^ help: `await` is a postfix operation: `{}.await` + | ^^^^^^^^ + | +help: `await` is a postfix operation + | +LL - await {}() +LL + {}.await() + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index 75c6a40c7445..3519fb8777f4 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -37,9 +37,13 @@ error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ help: try using `.` instead + | ^^ | = help: the `.` operator will dereference the value if needed +help: try using `.` instead + | +LL | attr::fn bar() . String { + | ~ error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` --> $DIR/issue-118530-ice.rs:5:30 diff --git a/tests/ui/parser/issues/issue-17718-const-mut.stderr b/tests/ui/parser/issues/issue-17718-const-mut.stderr index a27f517086ef..54b819c3cfb8 100644 --- a/tests/ui/parser/issues/issue-17718-const-mut.stderr +++ b/tests/ui/parser/issues/issue-17718-const-mut.stderr @@ -1,10 +1,13 @@ error: const globals cannot be mutable --> $DIR/issue-17718-const-mut.rs:2:1 | -LL | const - | ----- help: you might want to declare a static instead: `static` LL | mut | ^^^ cannot be mutable + | +help: you might want to declare a static instead + | +LL | static + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr index 88d97c795fc2..4a3743579e7a 100644 --- a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr +++ b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr @@ -86,9 +86,12 @@ error: incorrect unicode escape sequence --> $DIR/issue-23620-invalid-escapes.rs:32:14 | LL | let _ = "\u8f"; - | ^^^- - | | - | help: format of unicode escape sequences uses braces: `\u{8f}` + | ^^^ + | +help: format of unicode escape sequences uses braces + | +LL | let _ = "\u{8f}"; + | ~~~~~~ error: aborting due to 13 previous errors diff --git a/tests/ui/parser/issues/issue-27255.stderr b/tests/ui/parser/issues/issue-27255.stderr index 391a23556c4e..2cd7ebd60b14 100644 --- a/tests/ui/parser/issues/issue-27255.stderr +++ b/tests/ui/parser/issues/issue-27255.stderr @@ -2,13 +2,23 @@ error: missing `for` in a trait impl --> $DIR/issue-27255.rs:3:7 | LL | impl A .. {} - | ^ help: add `for` here + | ^ + | +help: add `for` here + | +LL | impl A for .. {} + | +++ error: missing `for` in a trait impl --> $DIR/issue-27255.rs:7:7 | LL | impl A usize {} - | ^^^^^^ help: add `for` here + | ^^^^^^ + | +help: add `for` here + | +LL | impl A for usize {} + | +++ error: `impl Trait for .. {}` is an obsolete syntax --> $DIR/issue-27255.rs:3:1 diff --git a/tests/ui/parser/issues/issue-32501.stderr b/tests/ui/parser/issues/issue-32501.stderr index c0513a64039e..b0ec135b784a 100644 --- a/tests/ui/parser/issues/issue-32501.stderr +++ b/tests/ui/parser/issues/issue-32501.stderr @@ -2,9 +2,14 @@ error: `mut` must be followed by a named binding --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut _ = 0; +LL + let _ = 0; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-46186.stderr b/tests/ui/parser/issues/issue-46186.stderr index c67c271e19ae..5ea3e1f49838 100644 --- a/tests/ui/parser/issues/issue-46186.stderr +++ b/tests/ui/parser/issues/issue-46186.stderr @@ -2,9 +2,14 @@ error: expected item, found `;` --> $DIR/issue-46186.rs:5:2 | LL | }; - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - }; +LL + } + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-48636.stderr b/tests/ui/parser/issues/issue-48636.stderr index 488a046a5490..c17a8ec2f899 100644 --- a/tests/ui/parser/issues/issue-48636.stderr +++ b/tests/ui/parser/issues/issue-48636.stderr @@ -4,11 +4,14 @@ error[E0585]: found a documentation comment that doesn't document anything LL | struct S { | - while parsing this struct LL | x: u8 - | - help: missing comma here: `,` LL | /// The ID of the parent core | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: doc comments must come before what they document, if a comment was intended use `//` +help: missing comma here + | +LL | x: u8, + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr index 11ef5e1aadfd..c25d5683ecfc 100644 --- a/tests/ui/parser/issues/issue-49040.stderr +++ b/tests/ui/parser/issues/issue-49040.stderr @@ -2,7 +2,13 @@ error: expected item, found `;` --> $DIR/issue-49040.rs:1:28 | LL | #![allow(unused_variables)]; - | ^ help: remove this semicolon + | ^ + | +help: remove this semicolon + | +LL - #![allow(unused_variables)]; +LL + #![allow(unused_variables)] + | error[E0601]: `main` function not found in crate `issue_49040` --> $DIR/issue-49040.rs:2:12 diff --git a/tests/ui/parser/issues/issue-52496.stderr b/tests/ui/parser/issues/issue-52496.stderr index 78c81bf5b0df..a97effb4e0cd 100644 --- a/tests/ui/parser/issues/issue-52496.stderr +++ b/tests/ui/parser/issues/issue-52496.stderr @@ -2,7 +2,12 @@ error: float literals must have an integer part --> $DIR/issue-52496.rs:4:24 | LL | let _ = Foo { bar: .5, baz: 42 }; - | ^^ help: must have an integer part: `0.5` + | ^^ + | +help: must have an integer part + | +LL | let _ = Foo { bar: 0.5, baz: 42 }; + | + error: expected one of `,`, `:`, or `}`, found `.` --> $DIR/issue-52496.rs:8:22 diff --git a/tests/ui/parser/issues/issue-54521-2.stderr b/tests/ui/parser/issues/issue-54521-2.stderr index 9556b83b730a..ad662ef1cca5 100644 --- a/tests/ui/parser/issues/issue-54521-2.stderr +++ b/tests/ui/parser/issues/issue-54521-2.stderr @@ -2,25 +2,49 @@ error: unmatched angle brackets --> $DIR/issue-54521-2.rs:11:25 | LL | let _ = Vec::>>>>::new(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle brackets --> $DIR/issue-54521-2.rs:14:25 | LL | let _ = Vec::>>>::new(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle brackets --> $DIR/issue-54521-2.rs:17:25 | LL | let _ = Vec::>>::new(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = Vec::>>::new(); +LL + let _ = Vec::::new(); + | error: unmatched angle bracket --> $DIR/issue-54521-2.rs:20:25 | LL | let _ = Vec::>::new(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = Vec::>::new(); +LL + let _ = Vec::::new(); + | error: aborting due to 4 previous errors diff --git a/tests/ui/parser/issues/issue-54521-3.stderr b/tests/ui/parser/issues/issue-54521-3.stderr index 0f23dd621075..bd468869b066 100644 --- a/tests/ui/parser/issues/issue-54521-3.stderr +++ b/tests/ui/parser/issues/issue-54521-3.stderr @@ -2,25 +2,49 @@ error: unmatched angle brackets --> $DIR/issue-54521-3.rs:11:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>>>(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-54521-3.rs:14:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-54521-3.rs:17:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle bracket --> $DIR/issue-54521-3.rs:20:60 | LL | let _ = vec![1, 2, 3].into_iter().collect::>>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = vec![1, 2, 3].into_iter().collect::>>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: aborting due to 4 previous errors diff --git a/tests/ui/parser/issues/issue-57684.stderr b/tests/ui/parser/issues/issue-57684.stderr index 514bbffde6b1..39e1c8cd7cc7 100644 --- a/tests/ui/parser/issues/issue-57684.stderr +++ b/tests/ui/parser/issues/issue-57684.stderr @@ -2,17 +2,23 @@ error: expected `:`, found `=` --> $DIR/issue-57684.rs:27:20 | LL | let _ = X { f1 = 5 }; - | -^ - | | - | help: replace equals symbol with a colon: `:` + | ^ + | +help: replace equals symbol with a colon + | +LL | let _ = X { f1: 5 }; + | ~ error: expected `:`, found `=` --> $DIR/issue-57684.rs:32:12 | LL | f1 = 5, - | -^ - | | - | help: replace equals symbol with a colon: `:` + | ^ + | +help: replace equals symbol with a colon + | +LL | f1: 5, + | ~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-57819.stderr b/tests/ui/parser/issues/issue-57819.stderr index 493e9835b1ca..a01625d9c4c3 100644 --- a/tests/ui/parser/issues/issue-57819.stderr +++ b/tests/ui/parser/issues/issue-57819.stderr @@ -2,43 +2,85 @@ error: unmatched angle brackets --> $DIR/issue-57819.rs:19:10 | LL | bar::<<<<::Output>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - bar::<<<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:22:10 | LL | bar::<<<::Output>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - bar::<<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle bracket --> $DIR/issue-57819.rs:25:10 | LL | bar::<<::Output>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - bar::<<::Output>(); +LL + bar::<::Output>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:34:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); - | ^^^^ help: remove extra angle brackets + | ^^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:37:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<<>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle brackets --> $DIR/issue-57819.rs:40:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<<>(); - | ^^ help: remove extra angle brackets + | ^^ + | +help: remove extra angle brackets + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: unmatched angle bracket --> $DIR/issue-57819.rs:43:48 | LL | let _ = vec![1, 2, 3].into_iter().collect::<>(); - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - let _ = vec![1, 2, 3].into_iter().collect::<>(); +LL + let _ = vec![1, 2, 3].into_iter().collect::>(); + | error: aborting due to 7 previous errors diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr index 2bd87ee0c38f..76259b40a933 100644 --- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -2,13 +2,18 @@ error: `mut` must be followed by a named binding --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:6:13 | LL | let mut $eval = (); - | ^^^^ help: remove the `mut` prefix + | ^^^^ ... LL | mac1! { does_not_exist!() } | --------------------------- in this macro invocation | = note: `mut` may be followed by `variable` and `variable @ pattern` = note: this error originates in the macro `mac1` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the `mut` prefix + | +LL - let mut $eval = (); +LL + let $eval = (); + | error: expected identifier, found `does_not_exist!()` --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17 @@ -25,13 +30,18 @@ error: `mut` must be followed by a named binding --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13 | LL | let mut $eval = (); - | ^^^ help: remove the `mut` prefix + | ^^^ ... LL | mac2! { does_not_exist!() } | --------------------------- in this macro invocation | = note: `mut` may be followed by `variable` and `variable @ pattern` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the `mut` prefix + | +LL - let mut $eval = (); +LL + let $eval = (); + | error: cannot find macro `does_not_exist` in this scope --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 diff --git a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr index 0a88dd2c4d31..49d091cf3914 100644 --- a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr +++ b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr @@ -46,13 +46,23 @@ error: invalid variable declaration --> $DIR/issue-65257-invalid-var-decl-recovery.rs:14:5 | LL | mut n = 0; - | ^^^ help: missing keyword: `let mut` + | ^^^ + | +help: missing keyword + | +LL | let mut n = 0; + | ~~~~~~~ error: invalid variable declaration --> $DIR/issue-65257-invalid-var-decl-recovery.rs:16:5 | LL | mut var; - | ^^^ help: missing keyword: `let mut` + | ^^^ + | +help: missing keyword + | +LL | let mut var; + | ~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-65257-invalid-var-decl-recovery.rs:20:33 diff --git a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr index 4961e8fc0492..63131b474f00 100644 --- a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr +++ b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr @@ -2,19 +2,25 @@ error: unexpected `...` --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:4:13 | LL | let Foo(...) = Foo(0); - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let Foo(...) = Foo(0); +LL + let Foo(..) = Foo(0); + | error: unexpected `...` --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:5:13 | LL | let [_, ..., _] = [0, 1]; - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let [_, ..., _] = [0, 1]; +LL + let [_, .., _] = [0, 1]; + | error[E0308]: mismatched types --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:6:33 diff --git a/tests/ui/parser/issues/issue-70388-without-witness.stderr b/tests/ui/parser/issues/issue-70388-without-witness.stderr index b750ad4c626d..ed78377607d2 100644 --- a/tests/ui/parser/issues/issue-70388-without-witness.stderr +++ b/tests/ui/parser/issues/issue-70388-without-witness.stderr @@ -2,19 +2,25 @@ error: unexpected `...` --> $DIR/issue-70388-without-witness.rs:7:13 | LL | let Foo(...) = Foo(0); - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let Foo(...) = Foo(0); +LL + let Foo(..) = Foo(0); + | error: unexpected `...` --> $DIR/issue-70388-without-witness.rs:8:13 | LL | let [_, ..., _] = [0, 1]; - | ^^^ - | | - | not a valid pattern - | help: for a rest pattern, use `..` instead of `...` + | ^^^ not a valid pattern + | +help: for a rest pattern, use `..` instead of `...` + | +LL - let [_, ..., _] = [0, 1]; +LL + let [_, .., _] = [0, 1]; + | error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr index ec0af9a6caf1..79c574ead61c 100644 --- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr +++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr @@ -17,7 +17,13 @@ error: unexpected lifetime `'static` in pattern --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13 | LL | fn bar(&'static mur Self) {} - | ^^^^^^^ help: remove the lifetime + | ^^^^^^^ + | +help: remove the lifetime + | +LL - fn bar(&'static mur Self) {} +LL + fn bar(&mur Self) {} + | error: expected identifier, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25 diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr index 652aeff5dd44..2f8728bd78b4 100644 --- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr +++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr @@ -2,24 +2,38 @@ error: lifetime must precede `mut` --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 | LL | fn x<'a>(x: &mut 'a i32){} - | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + | ^^^^^^^ + | +help: place the lifetime before `mut` + | +LL | fn x<'a>(x: &'a mut i32){} + | ~~~~~~~ error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 | LL | fn y<'a>(y: &mut 'a + Send) { - | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + | ^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn y<'a>(y: &mut ('a + Send)) { + | + + error: lifetime must precede `mut` --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 | LL | fn w<$lt>(w: &mut $lt i32) {} - | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` + | ^^^^^^^^ ... LL | mac!('a); | -------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: place the lifetime before `mut` + | +LL | fn w<$lt>(w: &$lt mut i32) {} + | ~~~~~~~~ error[E0423]: expected value, found trait `Send` --> $DIR/issue-73568-lifetime-after-mut.rs:17:28 diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/parser/issues/issue-89574.stderr index a0586d41e2e5..aa5e66b18a92 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/parser/issues/issue-89574.stderr @@ -8,7 +8,12 @@ error: missing type for `const` item --> $DIR/issue-89574.rs:2:22 | LL | const EMPTY_ARRAY = []; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const EMPTY_ARRAY: = []; + | ++++++++ error[E0282]: type annotations needed --> $DIR/issue-89574.rs:2:25 diff --git a/tests/ui/parser/issues/issue-90993.stderr b/tests/ui/parser/issues/issue-90993.stderr index ab6bce410e6c..a18e93f1f1a9 100644 --- a/tests/ui/parser/issues/issue-90993.stderr +++ b/tests/ui/parser/issues/issue-90993.stderr @@ -17,9 +17,13 @@ error: unexpected `=` after inclusive range --> $DIR/issue-90993.rs:2:5 | LL | ...=. - | ^^^^ help: use `..=` instead + | ^^^^ | = note: inclusive ranges end with a single equals sign (`..=`) +help: use `..=` instead + | +LL | ..=. + | ~~~ error: expected one of `-`, `;`, `}`, or path, found `.` --> $DIR/issue-90993.rs:2:9 diff --git a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr index c503bc3ccfcb..c98b8fa1f1ee 100644 --- a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr @@ -2,7 +2,12 @@ error: `enum` and `struct` are mutually exclusive --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5 | LL | pub enum struct Range { - | ^^^^^^^^^^^ help: replace `enum struct` with: `enum` + | ^^^^^^^^^^^ + | +help: replace `enum struct` with + | +LL | pub enum Range { + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr index 72377fc379ca..1ccf44a350d9 100644 --- a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr @@ -2,13 +2,23 @@ error: `const` and `let` are mutually exclusive --> $DIR/issue-99910-const-let-mutually-exclusive.rs:4:5 | LL | const let _FOO: i32 = 123; - | ^^^^^^^^^ help: remove `let`: `const` + | ^^^^^^^^^ + | +help: remove `let` + | +LL | const _FOO: i32 = 123; + | ~~~~~ error: `const` and `let` are mutually exclusive --> $DIR/issue-99910-const-let-mutually-exclusive.rs:6:5 | LL | let const _BAR: i32 = 123; - | ^^^^^^^^^ help: remove `let`: `const` + | ^^^^^^^^^ + | +help: remove `let` + | +LL | const _BAR: i32 = 123; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs index 3fbac5fae232..a8a608c191a8 100644 --- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs @@ -2,4 +2,5 @@ // Tests that we still emit an error after an item. fn main() { } -; //~ ERROR expected item, found `;` +; +//~^ ERROR expected item, found `;` diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr index 2d7f540443d2..aae5c1e1b22f 100644 --- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr +++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr @@ -2,9 +2,13 @@ error: expected item, found `;` --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1 | LL | ; - | ^ help: remove this semicolon + | ^ | = help: function declarations are not followed by a semicolon +help: remove this semicolon + | +LL - ; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr index 5365b0a1f824..1ecf9912e9b1 100644 --- a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr +++ b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -18,7 +18,12 @@ error: missing type for `const` item --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8 | LL | const B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const B: ; + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr index 1b61e430546e..3af7c642468d 100644 --- a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr +++ b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -34,13 +34,23 @@ error: missing type for `static` item --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9 | LL | static B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static B: ; + | ++++++++ error: missing type for `static mut` item --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13 | LL | static mut D; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static mut D: ; + | ++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index ba59ea853633..0abc59e064a0 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -2,85 +2,155 @@ error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:7:1 | LL | Use std::ptr::read; - | ^^^ help: write it in the correct case (notice the capitalization): `use` + | ^^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | use std::ptr::read; + | ~~~ error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:8:1 | LL | USE std::ptr::write; - | ^^^ help: write it in the correct case: `use` + | ^^^ + | +help: write it in the correct case + | +LL | use std::ptr::write; + | ~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:10:7 | LL | async Fn _a() {} - | ^^ help: write it in the correct case (notice the capitalization): `fn` + | ^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | async fn _a() {} + | ~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:13:1 | LL | Fn _b() {} - | ^^ help: write it in the correct case (notice the capitalization): `fn` + | ^^ + | +help: write it in the correct case (notice the capitalization difference) + | +LL | fn _b() {} + | ~~ error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:1 | LL | aSYNC fN _c() {} - | ^^^^^ help: write it in the correct case: `async` + | ^^^^^ + | +help: write it in the correct case + | +LL | async fN _c() {} + | ~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:7 | LL | aSYNC fN _c() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | aSYNC fn _c() {} + | ~~ error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:20:1 | LL | Async fn _d() {} - | ^^^^^ help: write it in the correct case: `async` + | ^^^^^ + | +help: write it in the correct case + | +LL | async fn _d() {} + | ~~~~~ error: keyword `const` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:1 | LL | CONST UNSAFE FN _e() {} - | ^^^^^ help: write it in the correct case: `const` + | ^^^^^ + | +help: write it in the correct case + | +LL | const UNSAFE FN _e() {} + | ~~~~~ error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:7 | LL | CONST UNSAFE FN _e() {} - | ^^^^^^ help: write it in the correct case: `unsafe` + | ^^^^^^ + | +help: write it in the correct case + | +LL | CONST unsafe FN _e() {} + | ~~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:14 | LL | CONST UNSAFE FN _e() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | CONST UNSAFE fn _e() {} + | ~~ error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:1 | LL | unSAFE EXTern fn _f() {} - | ^^^^^^ help: write it in the correct case: `unsafe` + | ^^^^^^ + | +help: write it in the correct case + | +LL | unsafe EXTern fn _f() {} + | ~~~~~~ error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:8 | LL | unSAFE EXTern fn _f() {} - | ^^^^^^ help: write it in the correct case: `extern` + | ^^^^^^ + | +help: write it in the correct case + | +LL | unSAFE extern fn _f() {} + | ~~~~~~ error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:1 | LL | EXTERN "C" FN _g() {} - | ^^^^^^ help: write it in the correct case: `extern` + | ^^^^^^ + | +help: write it in the correct case + | +LL | extern "C" FN _g() {} + | ~~~~~~ error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:12 | LL | EXTERN "C" FN _g() {} - | ^^ help: write it in the correct case: `fn` + | ^^ + | +help: write it in the correct case + | +LL | EXTERN "C" fn _g() {} + | ~~ error: aborting due to 14 previous errors diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr index 8ff50b124b32..be8c679d8ce3 100644 --- a/tests/ui/parser/label-after-block-like.stderr +++ b/tests/ui/parser/label-after-block-like.stderr @@ -2,12 +2,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:2:20 | LL | if let () = () 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | if let () = () 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:2:20 @@ -29,12 +32,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:8:13 | LL | if true 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | if true 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:8:13 @@ -56,12 +62,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:14:10 | LL | loop 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | loop 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:14:10 @@ -80,12 +89,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:20:16 | LL | while true 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | while true 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:20:16 @@ -105,12 +117,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:26:23 | LL | while let () = () 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | while let () = () 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:26:23 @@ -130,12 +145,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:32:19 | LL | for _ in 0..0 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | for _ in 0..0 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:32:19 @@ -152,12 +170,15 @@ error: labeled expression must be followed by `:` --> $DIR/label-after-block-like.rs:38:12 | LL | unsafe 'a {} - | ---^^ - | | | - | | help: add `:` after the label + | --^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | unsafe 'a: {} + | + error: expected `{`, found `'a` --> $DIR/label-after-block-like.rs:38:12 diff --git a/tests/ui/parser/labeled-no-colon-expr.stderr b/tests/ui/parser/labeled-no-colon-expr.stderr index 4d61d9c14034..247831928156 100644 --- a/tests/ui/parser/labeled-no-colon-expr.stderr +++ b/tests/ui/parser/labeled-no-colon-expr.stderr @@ -2,45 +2,57 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:2:5 | LL | 'l0 while false {} - | ----^^^^^^^^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l0: while false {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:3:5 | LL | 'l1 for _ in 0..1 {} - | ----^^^^^^^^^^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^^^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l1: for _ in 0..1 {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:4:5 | LL | 'l2 loop {} - | ----^^^^^^^ - | | | - | | help: add `:` after the label + | ---^^^^^^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l2: loop {} + | + error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:5:5 | LL | 'l3 {} - | ----^^ - | | | - | | help: add `:` after the label + | ---^^^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l3: {} + | + error: expected `while`, `for`, `loop` or `{` after a label --> $DIR/labeled-no-colon-expr.rs:6:9 @@ -58,12 +70,15 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:6:9 | LL | 'l4 0; - | ----^ - | | | - | | help: add `:` after the label + | --- ^ + | | | the label | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l4: 0; + | + error: cannot use a `block` macro fragment here --> $DIR/labeled-no-colon-expr.rs:11:17 @@ -86,14 +101,16 @@ error: labeled expression must be followed by `:` --> $DIR/labeled-no-colon-expr.rs:14:8 | LL | 'l5 $b; - | ---- help: add `:` after the label - | | - | the label + | --- the label ... LL | m!({}); | ^^ | = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them +help: add `:` after the label + | +LL | 'l5: $b; + | + error: aborting due to 8 previous errors diff --git a/tests/ui/parser/let-binop.stderr b/tests/ui/parser/let-binop.stderr index dd33e9157cfd..50ef14793cde 100644 --- a/tests/ui/parser/let-binop.stderr +++ b/tests/ui/parser/let-binop.stderr @@ -2,25 +2,40 @@ error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:4:15 | LL | let a: i8 *= 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let a: i8 *= 1; +LL + let a: i8 = 1; + | error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:6:11 | LL | let b += 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let b += 1; +LL + let b = 1; + | error: can't reassign to an uninitialized variable --> $DIR/let-binop.rs:8:11 | LL | let c *= 1; - | ^^ help: initialize the variable + | ^^ | = help: if you meant to overwrite, remove the `let` binding +help: initialize the variable + | +LL - let c *= 1; +LL + let c = 1; + | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/lifetime-in-pattern-recover.stderr b/tests/ui/parser/lifetime-in-pattern-recover.stderr index 4bf7f57bfb59..d0644da1dd18 100644 --- a/tests/ui/parser/lifetime-in-pattern-recover.stderr +++ b/tests/ui/parser/lifetime-in-pattern-recover.stderr @@ -2,13 +2,25 @@ error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern-recover.rs:2:10 | LL | let &'a x = &0; - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - let &'a x = &0; +LL + let &x = &0; + | error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern-recover.rs:3:10 | LL | let &'a mut y = &mut 0; - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - let &'a mut y = &mut 0; +LL + let &mut y = &mut 0; + | error[E0308]: mismatched types --> $DIR/lifetime-in-pattern-recover.rs:5:33 diff --git a/tests/ui/parser/lifetime-in-pattern.stderr b/tests/ui/parser/lifetime-in-pattern.stderr index a1d721e746ad..55f9e56a4292 100644 --- a/tests/ui/parser/lifetime-in-pattern.stderr +++ b/tests/ui/parser/lifetime-in-pattern.stderr @@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern.rs:1:10 | LL | fn test(&'a str) { - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - fn test(&'a str) { +LL + fn test(&str) { + | error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/lifetime-in-pattern.rs:1:16 diff --git a/tests/ui/parser/macro/pub-item-macro.stderr b/tests/ui/parser/macro/pub-item-macro.stderr index 9a2fffcced55..14f0b0908d1c 100644 --- a/tests/ui/parser/macro/pub-item-macro.stderr +++ b/tests/ui/parser/macro/pub-item-macro.stderr @@ -2,13 +2,18 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-item-macro.rs:10:5 | LL | pub priv_x!(); - | ^^^ help: remove the visibility + | ^^^ ... LL | pub_x!(); | -------- in this macro invocation | = help: try adjusting the macro to put `pub` inside the invocation = note: this error originates in the macro `pub_x` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the visibility + | +LL - pub priv_x!(); +LL + priv_x!(); + | error[E0603]: static `x` is private --> $DIR/pub-item-macro.rs:20:23 diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index a3f7e32c1773..53cf3480dbf9 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -56,7 +56,12 @@ error: expected `,` following `match` arm --> $DIR/match-arm-without-body.rs:66:15 | LL | pat!() - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | pat!(), + | + error: `match` arm with no body --> $DIR/match-arm-without-body.rs:7:9 diff --git a/tests/ui/parser/match-arm-without-braces.stderr b/tests/ui/parser/match-arm-without-braces.stderr index ee1c8e562fc3..4a4a154d8609 100644 --- a/tests/ui/parser/match-arm-without-braces.stderr +++ b/tests/ui/parser/match-arm-without-braces.stderr @@ -60,7 +60,12 @@ error: expected `,` following `match` arm --> $DIR/match-arm-without-braces.rs:48:29 | LL | Some(Val::Foo) => 17 - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(Val::Foo) => 17, + | + error: `match` arm body without braces --> $DIR/match-arm-without-braces.rs:53:11 diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr index 6559cf09cdfc..f4f11b88d361 100644 --- a/tests/ui/parser/mut-patterns.stderr +++ b/tests/ui/parser/mut-patterns.stderr @@ -2,53 +2,87 @@ error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:9:9 | LL | let mut _ = 0; - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut _ = 0; +LL + let _ = 0; + | error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:10:9 | LL | let mut (_, _) = (0, 0); - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut (_, _) = (0, 0); +LL + let (_, _) = (0, 0); + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:12:9 | LL | let mut (x @ y) = 0; - | ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)` + | ^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let (mut x @ mut y) = 0; + | ~~~~~~~~~~~~~~~ error: `mut` on a binding may not be repeated --> $DIR/mut-patterns.rs:14:13 | LL | let mut mut x = 0; - | ^^^ help: remove the additional `mut`s + | ^^^ + | +help: remove the additional `mut`s + | +LL - let mut mut x = 0; +LL + let mut x = 0; + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:19:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + | ^^^^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let Foo { x: mut x } = Foo { x: 3 }; + | ~~~~~~~~~~~~~~~~ error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:23:9 | LL | let mut Foo { x } = Foo { x: 3 }; - | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + | ^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let Foo { mut x } = Foo { x: 3 }; + | ~~~~~~~~~~~~~ error: `mut` on a binding may not be repeated --> $DIR/mut-patterns.rs:28:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); - | ^^^ help: remove the additional `mut`s + | ^^^ + | +help: remove the additional `mut`s + | +LL - let mut mut yield(become, await) = r#yield(0, 0); +LL + let mut yield(become, await) = r#yield(0, 0); + | error: expected identifier, found reserved keyword `yield` --> $DIR/mut-patterns.rs:28:17 @@ -87,17 +121,26 @@ error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:28:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); - | ^^^^^^^^ help: remove the `mut` prefix + | ^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - let mut mut yield(become, await) = r#yield(0, 0); +LL + let yield(become, await) = r#yield(0, 0); + | error: `mut` must be attached to each individual binding --> $DIR/mut-patterns.rs:37:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f })))) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: expected identifier, found `x` --> $DIR/mut-patterns.rs:44:21 diff --git a/tests/ui/parser/not-a-pred.stderr b/tests/ui/parser/not-a-pred.stderr index bcc64a687fd0..6f6a332cb815 100644 --- a/tests/ui/parser/not-a-pred.stderr +++ b/tests/ui/parser/not-a-pred.stderr @@ -2,7 +2,12 @@ error: return types are denoted using `->` --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ help: use `->` instead + | ^ + | +help: use `->` instead + | +LL | fn f(a: isize, b: isize) -> lt(a, b) { } + | ~~ error[E0573]: expected type, found function `lt` --> $DIR/not-a-pred.rs:1:28 diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr index 2b0c9bbc5be8..e36ff237bb00 100644 --- a/tests/ui/parser/pat-recover-wildcards.stderr +++ b/tests/ui/parser/pat-recover-wildcards.stderr @@ -32,9 +32,14 @@ error[E0586]: inclusive range with no end --> $DIR/pat-recover-wildcards.rs:35:10 | LL | 0..._ => () - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - 0..._ => () +LL + 0.._ => () + | error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` --> $DIR/pat-recover-wildcards.rs:35:13 diff --git a/tests/ui/parser/pub-method-macro.stderr b/tests/ui/parser/pub-method-macro.stderr index 35cbf4230791..2e2c30dc6ad2 100644 --- a/tests/ui/parser/pub-method-macro.stderr +++ b/tests/ui/parser/pub-method-macro.stderr @@ -2,9 +2,14 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-method-macro.rs:17:9 | LL | pub defn!(f); - | ^^^ help: remove the visibility + | ^^^ | = help: try adjusting the macro to put `pub` inside the invocation +help: remove the visibility + | +LL - pub defn!(f); +LL + defn!(f); + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/range-inclusive-extra-equals.stderr b/tests/ui/parser/range-inclusive-extra-equals.stderr index 83df719dd3cc..a573cdf950cd 100644 --- a/tests/ui/parser/range-inclusive-extra-equals.stderr +++ b/tests/ui/parser/range-inclusive-extra-equals.stderr @@ -2,9 +2,13 @@ error: unexpected `=` after inclusive range --> $DIR/range-inclusive-extra-equals.rs:7:13 | LL | if let 1..==3 = 1 {} - | ^^^^ help: use `..=` instead + | ^^^^ | = note: inclusive ranges end with a single equals sign (`..=`) +help: use `..=` instead + | +LL | if let 1..=3 = 1 {} + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/range_inclusive.stderr b/tests/ui/parser/range_inclusive.stderr index 0fd7f28db317..014f95bcd84a 100644 --- a/tests/ui/parser/range_inclusive.stderr +++ b/tests/ui/parser/range_inclusive.stderr @@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end --> $DIR/range_inclusive.rs:5:15 | LL | for _ in 1..= {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - for _ in 1..= {} +LL + for _ in 1.. {} + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr index 7012096b6445..8e5b76163ade 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr @@ -5,7 +5,12 @@ LL | type T0 = const fn(); | -----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T0 = const fn(); +LL + type T0 = fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:4:11 @@ -14,7 +19,12 @@ LL | type T1 = const extern "C" fn(); | -----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T1 = const extern "C" fn(); +LL + type T1 = extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:5:11 @@ -23,7 +33,12 @@ LL | type T2 = const unsafe extern fn(); | -----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T2 = const unsafe extern fn(); +LL + type T2 = unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:6:11 @@ -32,7 +47,12 @@ LL | type T3 = async fn(); | -----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T3 = async fn(); +LL + type T3 = fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:7:11 @@ -41,7 +61,12 @@ LL | type T4 = async extern fn(); | -----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T4 = async extern fn(); +LL + type T4 = extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:8:11 @@ -50,7 +75,12 @@ LL | type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T5 = async unsafe extern "C" fn(); +LL + type T5 = unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:9:11 @@ -59,7 +89,12 @@ LL | type T6 = const async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type T6 = const async unsafe extern "C" fn(); +LL + type T6 = async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:9:11 @@ -68,7 +103,12 @@ LL | type T6 = const async unsafe extern "C" fn(); | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type T6 = const async unsafe extern "C" fn(); +LL + type T6 = const unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:13:12 @@ -77,7 +117,12 @@ LL | type FT0 = for<'a> const fn(); | ^^^^^^^^-----^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT0 = for<'a> const fn(); +LL + type FT0 = for<'a> fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:14:12 @@ -86,7 +131,12 @@ LL | type FT1 = for<'a> const extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT1 = for<'a> const extern "C" fn(); +LL + type FT1 = for<'a> extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:15:12 @@ -95,7 +145,12 @@ LL | type FT2 = for<'a> const unsafe extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT2 = for<'a> const unsafe extern fn(); +LL + type FT2 = for<'a> unsafe extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:16:12 @@ -104,7 +159,12 @@ LL | type FT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT3 = for<'a> async fn(); +LL + type FT3 = for<'a> fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:17:12 @@ -113,7 +173,12 @@ LL | type FT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT4 = for<'a> async extern fn(); +LL + type FT4 = for<'a> extern fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:18:12 @@ -122,7 +187,12 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT5 = for<'a> async unsafe extern "C" fn(); +LL + type FT5 = for<'a> unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:19:12 @@ -131,7 +201,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `const` because of this - | help: remove the `const` qualifier + | +help: remove the `const` qualifier + | +LL - type FT6 = for<'a> const async unsafe extern "C" fn(); +LL + type FT6 = for<'a> async unsafe extern "C" fn(); + | error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:19:12 @@ -140,7 +215,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn(); | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ | | | `async` because of this - | help: remove the `async` qualifier + | +help: remove the `async` qualifier + | +LL - type FT6 = for<'a> const async unsafe extern "C" fn(); +LL + type FT6 = for<'a> const unsafe extern "C" fn(); + | error[E0308]: mismatched types --> $DIR/recover-const-async-fn-ptr.rs:24:33 diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr index 2b56498c50d3..68d57f20bd77 100644 --- a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr +++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr @@ -1,11 +1,14 @@ error: unmatched angle bracket --> $DIR/recover-field-extra-angle-brackets-in-struct-with-a-field.rs:2:25 | -LL | next: Option> - | _________________________^ -LL | | -LL | | } - | |_ help: remove extra angle bracket +LL | next: Option> + | ^ + | +help: remove extra angle bracket + | +LL - next: Option> +LL + next: Option + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr index 628626926a78..45af63133918 100644 --- a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr +++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr @@ -2,7 +2,13 @@ error: unmatched angle bracket --> $DIR/recover-field-extra-angle-brackets.rs:5:19 | LL | first: Vec>, - | ^ help: remove extra angle bracket + | ^ + | +help: remove extra angle bracket + | +LL - first: Vec>, +LL + first: Vec, + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr index e29b6c1c666b..b8e91c2344af 100644 --- a/tests/ui/parser/recover/recover-range-pats.stderr +++ b/tests/ui/parser/recover/recover-range-pats.stderr @@ -2,196 +2,330 @@ error: float literals must have an integer part --> $DIR/recover-range-pats.rs:20:12 | LL | if let .0..Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:22:16 | LL | if let X.. .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X.. 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:33:12 | LL | if let .0..=Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..=Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:35:16 | LL | if let X..=.0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X..=0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:58:12 | LL | if let .0...Y = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0...Y = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:62:17 | LL | if let X... .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let X... 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:73:12 | LL | if let .0.. = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0.. = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:79:13 | LL | if let 0..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0..= = 0 {} +LL + if let 0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:80:13 | LL | if let X..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X..= = 0 {} +LL + if let X.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:81:16 | LL | if let true..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let true..= = 0 {} +LL + if let true.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:83:12 | LL | if let .0..= = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0..= = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:83:14 | LL | if let .0..= = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let .0..= = 0 {} +LL + if let .0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:89:13 | LL | if let 0... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let 0... = 0 {} +LL + if let 0.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:90:13 | LL | if let X... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let X... = 0 {} +LL + if let X.. = 0 {} + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:91:16 | LL | if let true... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let true... = 0 {} +LL + if let true.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:93:12 | LL | if let .0... = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let 0.0... = 0 {} + | + error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:93:14 | LL | if let .0... = 0 {} - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - if let .0... = 0 {} +LL + if let .0.. = 0 {} + | error: float literals must have an integer part --> $DIR/recover-range-pats.rs:103:15 | LL | if let .. .0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let .. 0.0 = 0 {} + | + error: float literals must have an integer part --> $DIR/recover-range-pats.rs:113:15 | LL | if let ..=.0 = 0 {} - | ^^ help: must have an integer part: `0.0` + | ^^ + | +help: must have an integer part + | +LL | if let ..=0.0 = 0 {} + | + error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:119:12 | LL | if let ...3 = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=3 = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:121:12 | LL | if let ...Y = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=Y = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:123:12 | LL | if let ...true = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=true = 0 {} + | ~~~ error: float literals must have an integer part --> $DIR/recover-range-pats.rs:126:15 | LL | if let ....3 = 0 {} - | ^^ help: must have an integer part: `0.3` + | ^^ + | +help: must have an integer part + | +LL | if let ...0.3 = 0 {} + | + error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:126:12 | LL | if let ....3 = 0 {} - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | if let ..=.3 = 0 {} + | ~~~ error: range-to patterns with `...` are not allowed --> $DIR/recover-range-pats.rs:152:17 | LL | let ...$e; - | ^^^ help: use `..=` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..=` instead + | +LL | let ..=$e; + | ~~~ error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:159:19 | LL | let $e...; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e...; +LL + let $e..; + | error[E0586]: inclusive range with no end --> $DIR/recover-range-pats.rs:161:19 | LL | let $e..=; - | ^^^ help: use `..` instead + | ^^^ ... LL | mac!(0); | ------- in this macro invocation | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use `..` instead + | +LL - let $e..=; +LL + let $e..; + | error: `...` range patterns are deprecated --> $DIR/recover-range-pats.rs:40:13 diff --git a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr index c048c8ea1b0d..bb0f0b0214c4 100644 --- a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr +++ b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr @@ -2,7 +2,12 @@ error: `mut` must precede `dyn` --> $DIR/recover-ref-dyn-mut.rs:5:12 | LL | let r: &dyn mut Trait; - | ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn` + | ^^^^^^^^ + | +help: place `mut` before `dyn` + | +LL | let r: &mut dyn Trait; + | ~~~~~~~~ error[E0405]: cannot find trait `Trait` in this scope --> $DIR/recover-ref-dyn-mut.rs:5:21 diff --git a/tests/ui/parser/recover/recover-unticked-labels.stderr b/tests/ui/parser/recover/recover-unticked-labels.stderr index fbd108ca613c..5cf463677af1 100644 --- a/tests/ui/parser/recover/recover-unticked-labels.stderr +++ b/tests/ui/parser/recover/recover-unticked-labels.stderr @@ -2,17 +2,23 @@ error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:5:26 | LL | 'label: loop { break label 0 }; - | -^^^^ - | | - | help: labels start with a tick + | ^^^^^ + | +help: labels start with a tick + | +LL | 'label: loop { break 'label 0 }; + | + error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:6:29 | LL | 'label: loop { continue label }; - | -^^^^ - | | - | help: labels start with a tick + | ^^^^^ + | +help: labels start with a tick + | +LL | 'label: loop { continue 'label }; + | + error[E0425]: cannot find value `label` in this scope --> $DIR/recover-unticked-labels.rs:4:26 diff --git a/tests/ui/parser/regions-out-of-scope-slice.stderr b/tests/ui/parser/regions-out-of-scope-slice.stderr index 5d8f6af166bd..838dcde2850c 100644 --- a/tests/ui/parser/regions-out-of-scope-slice.stderr +++ b/tests/ui/parser/regions-out-of-scope-slice.stderr @@ -2,10 +2,15 @@ error: borrow expressions cannot be annotated with lifetimes --> $DIR/regions-out-of-scope-slice.rs:7:13 | LL | x = &'blk [1,2,3]; - | ^----^^^^^^^^ + | ^-----^^^^^^^ | | | annotated with lifetime here - | help: remove the lifetime annotation + | +help: remove the lifetime annotation + | +LL - x = &'blk [1,2,3]; +LL + x = &[1,2,3]; + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr index c089e0ba9693..0cdee1d51eac 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr @@ -2,7 +2,12 @@ error: missing parameters for function definition --> $DIR/removed-syntax-fn-sigil.rs:2:14 | LL | let x: fn~() = || (); - | ^ help: add a parameter list + | ^ + | +help: add a parameter list + | +LL | let x: fn()~() = || (); + | ++ error: expected one of `->`, `;`, or `=`, found `~` --> $DIR/removed-syntax-fn-sigil.rs:2:14 diff --git a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr index 52e0658949d3..d3ed7fc6376d 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr @@ -19,7 +19,12 @@ error: missing type for `static` item --> $DIR/removed-syntax-static-fn.rs:4:14 | LL | static fn f() {} - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static fn: f() {} + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr index 7f16ebcfc3ac..1fb57ab11f9f 100644 --- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr +++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr @@ -2,37 +2,73 @@ error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16 | LL | field1: i32 = 42, - | ^^^^^ help: remove this unsupported default value + | ^^^^^ + | +help: remove this unsupported default value + | +LL - field1: i32 = 42, +LL + field1: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14 | LL | field2: E = E::A, - | ^^^^^^^ help: remove this unsupported default value + | ^^^^^^^ + | +help: remove this unsupported default value + | +LL - field2: E = E::A, +LL + field2: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16 | LL | field3: i32 = 1 + 2, - | ^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field3: i32 = 1 + 2, +LL + field3: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16 | LL | field4: i32 = { 1 + 2 }, - | ^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field4: i32 = { 1 + 2 }, +LL + field4: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14 | LL | field5: E = foo(42), - | ^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field5: E = foo(42), +LL + field5: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14 | LL | field6: E = { foo(42) }, - | ^^^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field6: E = { foo(42) }, +LL + field6: E, + | error: expected `,`, or `}`, found `field2` --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16 @@ -50,25 +86,49 @@ error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16 | LL | field3: i32 = 1 + 2, - | ^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field3: i32 = 1 + 2, +LL + field3: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16 | LL | field4: i32 = { 1 + 2 }, - | ^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field4: i32 = { 1 + 2 }, +LL + field4: i32, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14 | LL | field5: E = foo(42), - | ^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field5: E = foo(42), +LL + field5: E, + | error: default values on `struct` fields aren't supported --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14 | LL | field6: E = { foo(42) }, - | ^^^^^^^^^^^^^^ help: remove this unsupported default value + | ^^^^^^^^^^^^^^ + | +help: remove this unsupported default value + | +LL - field6: E = { foo(42) }, +LL + field6: E, + | error: expected `:`, found `=` --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12 diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr index 6e29fad98d46..70ebeded3137 100644 --- a/tests/ui/parser/suggest-assoc-const.stderr +++ b/tests/ui/parser/suggest-assoc-const.stderr @@ -2,7 +2,12 @@ error: non-item in item list --> $DIR/suggest-assoc-const.rs:5:5 | LL | let _X: i32; - | ^^^ help: consider using `const` instead of `let` for associated const: `const` + | ^^^ + | +help: consider using `const` instead of `let` for associated const + | +LL | const _X: i32; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 5f175e86545a..be130ac7ab23 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -2,7 +2,12 @@ error: ambiguous `+` in a type --> $DIR/trait-object-delimiters.rs:3:13 | LL | fn foo1(_: &dyn Drop + AsRef) {} - | ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | fn foo1(_: &(dyn Drop + AsRef)) {} + | + + error: incorrect parentheses around trait bounds --> $DIR/trait-object-delimiters.rs:6:17 @@ -52,9 +57,14 @@ error: invalid `dyn` keyword --> $DIR/trait-object-delimiters.rs:16:25 | LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} - | ^^^ help: remove this keyword + | ^^^ | = help: `dyn` is only needed at the start of a trait `+`-separated list +help: remove this keyword + | +LL - fn foo5(_: &(dyn Drop + dyn AsRef)) {} +LL + fn foo5(_: &(dyn Drop + AsRef)) {} + | error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-object-delimiters.rs:3:24 diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.stderr index 9c7a9662c402..280c0e40c640 100644 --- a/tests/ui/parser/trait-object-lifetime-parens.stderr +++ b/tests/ui/parser/trait-object-lifetime-parens.stderr @@ -2,13 +2,25 @@ error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:5:21 | LL | fn f<'a, T: Trait + ('a)>() {} - | ^^^^ help: remove the parentheses + | ^^^^ + | +help: remove the parentheses + | +LL - fn f<'a, T: Trait + ('a)>() {} +LL + fn f<'a, T: Trait + 'a>() {} + | error: parenthesized lifetime bounds are not supported --> $DIR/trait-object-lifetime-parens.rs:8:24 | LL | let _: Box; - | ^^^^ help: remove the parentheses + | ^^^^ + | +help: remove the parentheses + | +LL - let _: Box; +LL + let _: Box; + | error: lifetime in trait object type must be followed by `+` --> $DIR/trait-object-lifetime-parens.rs:10:17 diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs index 63425f3e2018..e7f085104ae9 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.rs +++ b/tests/ui/parser/trait-object-polytrait-priority.rs @@ -6,5 +6,4 @@ fn main() { let _: &for<'a> Trait<'a> + 'static; //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>` //~| HELP try adding parentheses - //~| SUGGESTION &(for<'a> Trait<'a> + 'static) } diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr index 23ec1e9cf3d4..8cb564e79300 100644 --- a/tests/ui/parser/trait-object-polytrait-priority.stderr +++ b/tests/ui/parser/trait-object-polytrait-priority.stderr @@ -2,7 +2,12 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait< --> $DIR/trait-object-polytrait-priority.rs:6:12 | LL | let _: &for<'a> Trait<'a> + 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&(for<'a> Trait<'a> + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding parentheses + | +LL | let _: &(for<'a> Trait<'a> + 'static); + | + + error: aborting due to 1 previous error diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 726cde2b413e..a1561e7f04b0 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -34,15 +34,17 @@ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:17:14 | LL | let _a = 'Å'; - | ^-^ - | | - | help: consider using the normalized form `\u{c5}` of this character: `Å` + | ^^^ | note: this `A` is followed by the combining mark `\u{30a}` --> $DIR/unicode-character-literal.rs:17:15 | LL | let _a = 'Å'; | ^ +help: consider using the normalized form `\u{c5}` of this character + | +LL | let _a = 'Å'; + | ~ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unmatched-langle-1.stderr b/tests/ui/parser/unmatched-langle-1.stderr index cdf74bdedc2e..3411a05fb589 100644 --- a/tests/ui/parser/unmatched-langle-1.stderr +++ b/tests/ui/parser/unmatched-langle-1.stderr @@ -2,7 +2,13 @@ error: unmatched angle brackets --> $DIR/unmatched-langle-1.rs:5:10 | LL | foo::<<<>(); - | ^^^ help: remove extra angle brackets + | ^^^ + | +help: remove extra angle brackets + | +LL - foo::<<<>(); +LL + foo::>(); + | error[E0412]: cannot find type `Ty` in this scope --> $DIR/unmatched-langle-1.rs:5:14 diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr index 952119cae3e2..c6ac0d562f82 100644 --- a/tests/ui/parser/unnecessary-let.stderr +++ b/tests/ui/parser/unnecessary-let.stderr @@ -2,19 +2,36 @@ error: expected pattern, found `let` --> $DIR/unnecessary-let.rs:2:9 | LL | for let x of [1, 2, 3] {} - | ^^^ help: remove the unnecessary `let` keyword + | ^^^ + | +help: remove the unnecessary `let` keyword + | +LL - for let x of [1, 2, 3] {} +LL + for x of [1, 2, 3] {} + | error: missing `in` in `for` loop --> $DIR/unnecessary-let.rs:2:15 | LL | for let x of [1, 2, 3] {} - | ^^ help: try using `in` here instead + | ^^ + | +help: try using `in` here instead + | +LL | for let x in [1, 2, 3] {} + | ~~ error: expected pattern, found `let` --> $DIR/unnecessary-let.rs:7:9 | LL | let 1 => {} - | ^^^ help: remove the unnecessary `let` keyword + | ^^^ + | +help: remove the unnecessary `let` keyword + | +LL - let 1 => {} +LL + 1 => {} + | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/use-colon-as-mod-sep.stderr b/tests/ui/parser/use-colon-as-mod-sep.stderr index bfc5374ef9d2..347b271df990 100644 --- a/tests/ui/parser/use-colon-as-mod-sep.stderr +++ b/tests/ui/parser/use-colon-as-mod-sep.stderr @@ -2,33 +2,49 @@ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:3:17 | LL | use std::process:Command; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::process::Command; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:5:8 | LL | use std:fs::File; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::fs::File; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:8 | LL | use std:collections:HashMap; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std::collections:HashMap; + | ~~ error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:20 | LL | use std:collections:HashMap; - | ^ help: use double colon + | ^ | = note: import paths are delimited using `::` +help: use double colon + | +LL | use std:collections::HashMap; + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr index 2f45415844d8..1599edd7a992 100644 --- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr +++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr @@ -6,7 +6,11 @@ LL | let _ @ a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `a @ _` + | +help: switch the order + | +LL | let a @ _ = 0; + | ~~~~~ error: pattern on wrong side of `@` --> $DIR/wild-before-at-syntactically-rejected.rs:10:9 @@ -16,7 +20,11 @@ LL | let _ @ ref a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `ref a @ _` + | +help: switch the order + | +LL | let ref a @ _ = 0; + | ~~~~~~~~~ error: pattern on wrong side of `@` --> $DIR/wild-before-at-syntactically-rejected.rs:12:9 @@ -26,7 +34,11 @@ LL | let _ @ ref mut a = 0; | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `ref mut a @ _` + | +help: switch the order + | +LL | let ref mut a @ _ = 0; + | ~~~~~~~~~~~~~ error: left-hand side of `@` must be a binding --> $DIR/wild-before-at-syntactically-rejected.rs:14:9 diff --git a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr index 167016397d21..622358126b09 100644 --- a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr +++ b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr @@ -2,9 +2,13 @@ error: `mut` must be attached to each individual binding --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9 | LL | let mut &x = &0; - | ^^^^^^ help: add `mut` to each binding: `&(mut x)` + | ^^^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: add `mut` to each binding + | +LL | let &(mut x) = &0; + | ~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.stderr b/tests/ui/pattern/pattern-bad-ref-box-order.stderr index a49f05c1028d..a89d3ed21b62 100644 --- a/tests/ui/pattern/pattern-bad-ref-box-order.stderr +++ b/tests/ui/pattern/pattern-bad-ref-box-order.stderr @@ -2,7 +2,12 @@ error: switch the order of `ref` and `box` --> $DIR/pattern-bad-ref-box-order.rs:8:14 | LL | Some(ref box _i) => {}, - | ^^^^^^^ help: swap them: `box ref` + | ^^^^^^^ + | +help: swap them + | +LL | Some(box ref _i) => {}, + | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr index 37c02eb6ada9..9d642b9245a2 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr @@ -2,7 +2,12 @@ error: range-to patterns with `...` are not allowed --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:13 | LL | [_, ...tail] => println!("{tail}"), - | ^^^ help: use `..=` instead + | ^^^ + | +help: use `..=` instead + | +LL | [_, ..=tail] => println!("{tail}"), + | ~~~ error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13 diff --git a/tests/ui/pub/pub-restricted.stderr b/tests/ui/pub/pub-restricted.stderr index 4694530e5486..fc177aa2033e 100644 --- a/tests/ui/pub/pub-restricted.stderr +++ b/tests/ui/pub/pub-restricted.stderr @@ -2,56 +2,76 @@ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:3:6 | LL | pub (a) fn afn() {} - | ^ help: make this visible only to module `a` with `in`: `in a` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `a` with `in` + | +LL | pub (in a) fn afn() {} + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:4:6 | LL | pub (b) fn bfn() {} - | ^ help: make this visible only to module `b` with `in`: `in b` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `b` with `in` + | +LL | pub (in b) fn bfn() {} + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:5:6 | LL | pub (crate::a) fn cfn() {} - | ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a` + | ^^^^^^^^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `crate::a` with `in` + | +LL | pub (in crate::a) fn cfn() {} + | ~~~~~~~~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:22:14 | LL | pub (a) invalid: usize, - | ^ help: make this visible only to module `a` with `in`: `in a` + | ^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `a` with `in` + | +LL | pub (in a) invalid: usize, + | ~~~~ error[E0704]: incorrect visibility restriction --> $DIR/pub-restricted.rs:31:6 | LL | pub (xyz) fn xyz() {} - | ^^^ help: make this visible only to module `xyz` with `in`: `in xyz` + | ^^^ | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path +help: make this visible only to module `xyz` with `in` + | +LL | pub (in xyz) fn xyz() {} + | ~~~~~~ error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/pub-restricted.rs:23:17 diff --git a/tests/ui/range/impossible_range.stderr b/tests/ui/range/impossible_range.stderr index 53c56065c2a3..17dd264e3660 100644 --- a/tests/ui/range/impossible_range.stderr +++ b/tests/ui/range/impossible_range.stderr @@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:11:5 | LL | ..=; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - ..=; +LL + ..; + | error[E0586]: inclusive range with no end --> $DIR/impossible_range.rs:18:6 | LL | 0..=; - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - 0..=; +LL + 0..; + | error: aborting due to 2 previous errors diff --git a/tests/ui/range/range-inclusive-pattern-precedence.stderr b/tests/ui/range/range-inclusive-pattern-precedence.stderr index 2e2d7983c03a..9df20fc45456 100644 --- a/tests/ui/range/range-inclusive-pattern-precedence.stderr +++ b/tests/ui/range/range-inclusive-pattern-precedence.stderr @@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence.rs:15:10 | LL | &10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` + | ^^^^^^^ + | +help: add parentheses to clarify the precedence + | +LL | &(10..=15) => {} + | + + warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence.rs:11:9 diff --git a/tests/ui/range/range-inclusive-pattern-precedence2.stderr b/tests/ui/range/range-inclusive-pattern-precedence2.stderr index 84294604c80f..fd2fa78e92b5 100644 --- a/tests/ui/range/range-inclusive-pattern-precedence2.stderr +++ b/tests/ui/range/range-inclusive-pattern-precedence2.stderr @@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence2.rs:14:13 | LL | box 10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` + | ^^^^^^^ + | +help: add parentheses to clarify the precedence + | +LL | box (10..=15) => {} + | + + warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence2.rs:10:14 diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs index b3ddf88c4493..f91698d06372 100644 --- a/tests/ui/recursion/issue-83150.rs +++ b/tests/ui/recursion/issue-83150.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator` //@ build-fail //@ compile-flags: -Copt-level=0 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" @@ -11,5 +12,4 @@ fn main() { fn func>(iter: &mut T) { //~^ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) - //~^ ERROR reached the type-length limit } diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr index 127de98ddc5b..fb66436dbbdd 100644 --- a/tests/ui/recursion/issue-83150.stderr +++ b/tests/ui/recursion/issue-83150.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-83150.rs:11:1 + --> $DIR/issue-83150.rs:12:1 | LL | fn func>(iter: &mut T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -10,14 +10,13 @@ LL | func(&mut iter.map(|x| x + 1)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>` - --> $DIR/issue-83150.rs:13:15 +error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator` | -LL | func(&mut iter.map(|x| x + 1)) - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt' + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) + = note: required for `&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator` + = note: 65 redundant requirements hidden + = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator` error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 8a1ed8f3b9c7..350ac287507a 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/repeat_count.rs:5:17 | -LL | let n = 1; - | ----- help: consider using `const` instead of `let`: `const n` LL | let a = [0; n]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0308]: mismatched types --> $DIR/repeat_count.rs:7:17 diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr index 17d1b7e0d43b..05980510f1cd 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr @@ -2,13 +2,23 @@ error: expected `,` following `match` arm --> $DIR/parse.rs:26:16 | LL | Some(!) - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(!), + | + error: expected `,` following `match` arm --> $DIR/parse.rs:31:24 | LL | Some(!) if true - | ^ help: missing a comma here to end this `match` arm: `,` + | ^ + | +help: missing a comma here to end this `match` arm + | +LL | Some(!) if true, + | + error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=` --> $DIR/parse.rs:42:17 @@ -20,7 +30,12 @@ error: top-level or-patterns are not allowed in `let` bindings --> $DIR/parse.rs:67:9 | LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048. - | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))` + | ^^^^^^^^^^^^^^ + | +help: wrap the pattern in parentheses + | +LL | let (Ok(_) | Err(!)) = &res; // Disallowed; see #82048. + | + + error: never patterns cannot contain variable bindings --> $DIR/parse.rs:73:9 diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index c2b9899e20db..f515cb62c7cd 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -9,6 +9,10 @@ LL | let _ = dbg!(a); | ^^^^^^^ value used here after move | = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing instead of transferring ownership + | +LL | let _ = dbg!(&a); + | + error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs new file mode 100644 index 000000000000..21e91c731b36 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs @@ -0,0 +1,24 @@ +#![feature(generic_const_exprs)] +//~^ WARN: the feature `generic_const_exprs` is incomplete + +// Regression test for #125770 which would ICE under the old effects desugaring that +// created a const generic parameter for constness on `Add`. + +use std::ops::Add; + +pub struct Dimension; + +pub struct Quantity(S); +//~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + +impl Add for Quantity {} +//~^ ERROR: trait takes at most 1 generic argument +//~| ERROR: `Dimension` is forbidden as the type of a const generic parameter + +pub fn add(x: Quantity) -> Quantity { + //~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + x + y + //~^ ERROR: cannot find value `y` in this scope +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr new file mode 100644 index 000000000000..8c814295de46 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr @@ -0,0 +1,64 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/mismatched_generic_args.rs:20:9 + | +LL | pub fn add(x: Quantity) -> Quantity { + | - similarly named const parameter `U` defined here +LL | +LL | x + y + | ^ help: a const parameter with a similar name exists: `U` + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mismatched_generic_args.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:11:33 + | +LL | pub struct Quantity(S); + | ^^^^^^^^^ + | + = 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)] + | + +error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied + --> $DIR/mismatched_generic_args.rs:14:36 + | +LL | impl Add for Quantity {} + | ^^^ expected at most 1 generic argument + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:14:15 + | +LL | impl Add for Quantity {} + | ^^^^^^^^^ + | + = 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)] + | + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:18:21 + | +LL | pub fn add(x: Quantity) -> Quantity { + | ^^^^^^^^^ + | + = 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)] + | + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0107, E0425. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/self/self-vs-path-ambiguity.stderr b/tests/ui/self/self-vs-path-ambiguity.stderr index 9e140e21023f..557a63a2af16 100644 --- a/tests/ui/self/self-vs-path-ambiguity.stderr +++ b/tests/ui/self/self-vs-path-ambiguity.stderr @@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern --> $DIR/self-vs-path-ambiguity.rs:9:11 | LL | fn i(&'a self::S: &S) {} - | ^^ help: remove the lifetime + | ^^ + | +help: remove the lifetime + | +LL - fn i(&'a self::S: &S) {} +LL + fn i(&self::S: &S) {} + | error: aborting due to 1 previous error diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index 4909a9cdc7f5..8298293a8cbb 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -14,9 +14,14 @@ error: `mut` must be followed by a named binding --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^ help: remove the `mut` prefix + | ^^^^ | = note: `mut` may be followed by `variable` and `variable @ pattern` +help: remove the `mut` prefix + | +LL - mut Self => (), +LL + Self => (), + | error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:19:17 diff --git a/tests/ui/structs/struct-duplicate-comma.stderr b/tests/ui/structs/struct-duplicate-comma.stderr index 4ac3fc9fe6b2..dc1c6ae87165 100644 --- a/tests/ui/structs/struct-duplicate-comma.stderr +++ b/tests/ui/structs/struct-duplicate-comma.stderr @@ -4,10 +4,13 @@ error: expected identifier, found `,` LL | let _ = Foo { | --- while parsing this struct LL | a: 0,, - | ^ - | | - | expected identifier - | help: remove this comma + | ^ expected identifier + | +help: remove this comma + | +LL - a: 0,, +LL + a: 0, + | error: aborting due to 1 previous error diff --git a/tests/ui/structs/struct-field-init-syntax.stderr b/tests/ui/structs/struct-field-init-syntax.stderr index 0b72c5cf734c..66098d5f610e 100644 --- a/tests/ui/structs/struct-field-init-syntax.stderr +++ b/tests/ui/structs/struct-field-init-syntax.stderr @@ -2,17 +2,27 @@ error: cannot use a comma after the base struct --> $DIR/struct-field-init-syntax.rs:11:9 | LL | ..Foo::default(), - | ^^^^^^^^^^^^^^^^- help: remove this comma + | ^^^^^^^^^^^^^^^^ | = note: the base struct must always be the last field +help: remove this comma + | +LL - ..Foo::default(), +LL + ..Foo::default() + | error: cannot use a comma after the base struct --> $DIR/struct-field-init-syntax.rs:16:9 | LL | ..Foo::default(), - | ^^^^^^^^^^^^^^^^- help: remove this comma + | ^^^^^^^^^^^^^^^^ | = note: the base struct must always be the last field +help: remove this comma + | +LL - ..Foo::default(), +LL + ..Foo::default() + | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/const-no-type.stderr b/tests/ui/suggestions/const-no-type.stderr index bd703992fd4a..c85c58989073 100644 --- a/tests/ui/suggestions/const-no-type.stderr +++ b/tests/ui/suggestions/const-no-type.stderr @@ -26,19 +26,34 @@ error: missing type for `const` item --> $DIR/const-no-type.rs:14:9 | LL | const C2 = 42; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const C2: = 42; + | ++++++++ error: missing type for `static` item --> $DIR/const-no-type.rs:20:10 | LL | static S2 = "abc"; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static S2: = "abc"; + | ++++++++ error: missing type for `static mut` item --> $DIR/const-no-type.rs:26:15 | LL | static mut SM2 = "abc"; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static mut SM2: = "abc"; + | ++++++++ error: aborting due to 7 previous errors diff --git a/tests/ui/suggestions/js-style-comparison-op.stderr b/tests/ui/suggestions/js-style-comparison-op.stderr index 33f7a0844fd2..58b1fddd3ddd 100644 --- a/tests/ui/suggestions/js-style-comparison-op.stderr +++ b/tests/ui/suggestions/js-style-comparison-op.stderr @@ -2,13 +2,23 @@ error: invalid comparison operator `===` --> $DIR/js-style-comparison-op.rs:3:10 | LL | if 1 === 1 { - | ^^^ help: `===` is not a valid comparison operator, use `==` + | ^^^ + | +help: `===` is not a valid comparison operator, use `==` + | +LL | if 1 == 1 { + | ~~ error: invalid comparison operator `!==` --> $DIR/js-style-comparison-op.rs:5:17 | LL | } else if 1 !== 1 { - | ^^^ help: `!==` is not a valid comparison operator, use `!=` + | ^^^ + | +help: `!==` is not a valid comparison operator, use `!=` + | +LL | } else if 1 != 1 { + | ~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr index e068fdb5abac..dd8f896d88e7 100644 --- a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr +++ b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr @@ -2,25 +2,40 @@ error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:2:9 | LL | mod M {}; - | ^ help: remove this semicolon + | ^ | = help: module declarations are not followed by a semicolon +help: remove this semicolon + | +LL - mod M {}; +LL + mod M {} + | error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:4:12 | LL | struct S {}; - | ^ help: remove this semicolon + | ^ | = help: braced struct declarations are not followed by a semicolon +help: remove this semicolon + | +LL - struct S {}; +LL + struct S {} + | error: expected item, found `;` --> $DIR/recover-from-semicolon-trailing-item.rs:6:20 | LL | fn foo(a: usize) {}; - | ^ help: remove this semicolon + | ^ | = help: function declarations are not followed by a semicolon +help: remove this semicolon + | +LL - fn foo(a: usize) {}; +LL + fn foo(a: usize) {} + | error[E0308]: mismatched types --> $DIR/recover-from-semicolon-trailing-item.rs:10:20 diff --git a/tests/ui/suggestions/recover-invalid-float.stderr b/tests/ui/suggestions/recover-invalid-float.stderr index dd24746eab80..9e4ea6d3089a 100644 --- a/tests/ui/suggestions/recover-invalid-float.stderr +++ b/tests/ui/suggestions/recover-invalid-float.stderr @@ -2,19 +2,34 @@ error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:4:18 | LL | let _: f32 = .3; - | ^^ help: must have an integer part: `0.3` + | ^^ + | +help: must have an integer part + | +LL | let _: f32 = 0.3; + | + error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:6:18 | LL | let _: f32 = .42f32; - | ^^^^^^ help: must have an integer part: `0.42f32` + | ^^^^^^ + | +help: must have an integer part + | +LL | let _: f32 = 0.42f32; + | + error: float literals must have an integer part --> $DIR/recover-invalid-float.rs:8:18 | LL | let _: f64 = .5f64; - | ^^^^^ help: must have an integer part: `0.5f64` + | ^^^^^ + | +help: must have an integer part + | +LL | let _: f64 = 0.5f64; + | + error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr index 3242b028d5d3..0bef1c185db6 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-method.rs:3:16 | LL | let _ = Box:new("foo".to_string()); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Box::new("foo".to_string()); + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr index 566b036e53e4..8c16acff7994 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-path.rs:2:8 | LL | std:io::stdin(); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | std::io::stdin(); + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr index 6fea7f940523..f0b31722e40e 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/type-ascription-instead-of-variant.rs:3:19 | LL | let _ = Option:Some(""); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Option::Some(""); + | + error: aborting due to 1 previous error diff --git a/tests/ui/tool-attributes/invalid-tool.rs b/tests/ui/tool-attributes/invalid-tool.rs new file mode 100644 index 000000000000..125333231d21 --- /dev/null +++ b/tests/ui/tool-attributes/invalid-tool.rs @@ -0,0 +1,6 @@ +#![feature(register_tool)] + +#![register_tool(1)] +//~^ ERROR `register_tool` only accepts identifiers + +fn main() {} diff --git a/tests/ui/tool-attributes/invalid-tool.stderr b/tests/ui/tool-attributes/invalid-tool.stderr new file mode 100644 index 000000000000..deafa6d167c2 --- /dev/null +++ b/tests/ui/tool-attributes/invalid-tool.stderr @@ -0,0 +1,8 @@ +error: `register_tool` only accepts identifiers + --> $DIR/invalid-tool.rs:3:18 + | +LL | #![register_tool(1)] + | ^ not an identifier + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index d9c422e6f709..7c9ae09349aa 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,3 +1,4 @@ +//~ ERROR overflow evaluating the requirement ` as Iterator>::Item == ()` //@ build-fail //@ compile-flags: -Zinline-mir=no @@ -23,7 +24,6 @@ where T: Iterator, { recurse(IteratorOfWrapped(elements).map(|t| t.0)) - //~^ ERROR reached the type-length limit } fn main() { diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index c46c78609d2c..c2f09371cf7f 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:20:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:21:1 | LL | / fn recurse(elements: T) -> Vec LL | | @@ -13,14 +13,19 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error: reached the type-length limit while instantiating `, ...>> as Iterator>::map::<..., ...>` - --> $DIR/issue-91949-hangs-on-recursion.rs:25:13 +error[E0275]: overflow evaluating the requirement ` as Iterator>::Item == ()` | -LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) +note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` + --> $DIR/issue-91949-hangs-on-recursion.rs:14:32 | - = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt' +LL | impl> Iterator for IteratorOfWrapped { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 256 redundant requirements hidden + = note: required for `IteratorOfWrapped<(), Map>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>` to implement `Iterator` error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr index 562ce53052bd..fd825e86675d 100644 --- a/tests/ui/type/ascription/issue-47666.stderr +++ b/tests/ui/type/ascription/issue-47666.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-47666.rs:3:19 | LL | let _ = Option:Some(vec![0, 1]); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _ = Option::Some(vec![0, 1]); + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr index 2c567a1a0ff6..64fdc1fa24a6 100644 --- a/tests/ui/type/ascription/issue-54516.stderr +++ b/tests/ui/type/ascription/issue-54516.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-54516.rs:5:28 | LL | println!("{}", std::mem:size_of::>()); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | println!("{}", std::mem::size_of::>()); + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr index cd184ceba331..c68394d0504a 100644 --- a/tests/ui/type/ascription/issue-60933.stderr +++ b/tests/ui/type/ascription/issue-60933.stderr @@ -2,9 +2,13 @@ error: path separator must be a double colon --> $DIR/issue-60933.rs:3:28 | LL | let _: usize = std::mem:size_of::(); - | ^ help: use a double colon instead: `::` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | let _: usize = std::mem::size_of::(); + | + error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr index 2abf27100c1d..f5cf7930c832 100644 --- a/tests/ui/type/pattern_types/bad_pat.stderr +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end --> $DIR/bad_pat.rs:7:43 | LL | type NonNullU32_2 = pattern_type!(u32 is 1..=); - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - type NonNullU32_2 = pattern_type!(u32 is 1..=); +LL + type NonNullU32_2 = pattern_type!(u32 is 1..); + | error[E0586]: inclusive range with no end --> $DIR/bad_pat.rs:9:40 | LL | type Positive2 = pattern_type!(i32 is 0..=); - | ^^^ help: use `..` instead + | ^^^ | = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) +help: use `..` instead + | +LL - type Positive2 = pattern_type!(i32 is 0..=); +LL + type Positive2 = pattern_type!(i32 is 0..); + | error: wildcard patterns are not permitted for pattern types --> $DIR/bad_pat.rs:11:33 diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr index 8c09e78bc5fb..34c886423239 100644 --- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr +++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr @@ -2,9 +2,13 @@ error: statements are terminated with a semicolon --> $DIR/type-ascription-instead-of-statement-end.rs:2:21 | LL | println!("test"): - | ^ help: use a semicolon instead: `;` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a semicolon instead + | +LL | println!("test"); + | ~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` --> $DIR/type-ascription-instead-of-statement-end.rs:7:21 diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr index 2ae5873c8242..2691f10cf3ed 100644 --- a/tests/ui/type/type-ascription-with-fn-call.stderr +++ b/tests/ui/type/type-ascription-with-fn-call.stderr @@ -2,9 +2,13 @@ error: statements are terminated with a semicolon --> $DIR/type-ascription-with-fn-call.rs:3:10 | LL | f() : - | ^ help: use a semicolon instead: `;` + | ^ | = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a semicolon instead + | +LL | f() ; + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr index 15d47cca3d20..cf372dc59681 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.stderr +++ b/tests/ui/type/type-dependent-def-issue-49241.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-dependent-def-issue-49241.rs:3:22 | LL | const l: usize = v.count(); - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let l` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let l: usize = v.count(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs index d6937481a155..87f5ffd76d7a 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/type_length_limit.rs @@ -1,5 +1,5 @@ //@ build-fail -//@ compile-flags: -Copt-level=0 +//@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit //~^^ ERROR reached the type-length limit // Test that the type length limit can be changed. diff --git a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr index 8982d6285617..4450aa66c132 100644 --- a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr +++ b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr @@ -8,13 +8,23 @@ error: missing type for `const` item --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:2:12 | LL | const A; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const A: ; + | ++++++++ error: missing type for `static` item --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:3:13 | LL | static B; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | static B: ; + | ++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/typeck/issue-79040.stderr index ce6a4b362170..39636db85a78 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/typeck/issue-79040.stderr @@ -10,7 +10,12 @@ error: missing type for `const` item --> $DIR/issue-79040.rs:2:14 | LL | const FOO = "hello" + 1; - | ^ help: provide a type for the item: `: ` + | ^ + | +help: provide a type for the item + | +LL | const FOO: = "hello" + 1; + | ++++++++ error[E0369]: cannot add `{integer}` to `&str` --> $DIR/issue-79040.rs:2:25 diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr index effcbe4d7f3e..86ba9432384b 100644 --- a/tests/ui/typeof/issue-42060.stderr +++ b/tests/ui/typeof/issue-42060.stderr @@ -1,18 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:3:23 | -LL | let thing = (); - | --------- help: consider using `const` instead of `let`: `const thing` LL | let other: typeof(thing) = thing; | ^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const thing: /* Type */ = (); + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 | -LL | let q = 1; - | ----- help: consider using `const` instead of `let`: `const q` LL | ::N | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const q: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 diff --git a/triagebot.toml b/triagebot.toml index 77b3db8a0109..d47d54d45c0b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -221,6 +221,13 @@ trigger_files = [ "library/std/src/os/android" ] +[autolabel."O-apple"] +trigger_files = [ + "library/std/src/os/darwin", + "library/std/src/sys/pal/unix/thread_parking/darwin.rs", + "compiler/rustc_target/src/spec/base/apple", +] + [autolabel."O-fuchsia"] trigger_files = [ "library/std/src/os/fuchsia" @@ -250,8 +257,6 @@ trigger_files = [ [autolabel."O-macos"] trigger_files = [ "library/std/src/os/macos", - "library/std/src/sys/pal/unix/thread_parking/darwin.rs", - "compiler/rustc_target/src/spec/base/apple", ] [autolabel."O-netbsd"] @@ -299,22 +304,12 @@ trigger_files = [ "library/std/src/os/wasm" ] -[autolabel."O-watchos"] -trigger_files = [ - "library/std/src/os/watchos" -] - [autolabel."O-windows"] trigger_files = [ "library/std/src/sys/pal/windows", "library/std/src/os/windows" ] -[autolabel."O-visionos"] -trigger_files = [ - "library/std/src/os/visionos" -] - [autolabel."T-bootstrap"] trigger_files = [ "x.py", @@ -946,6 +941,7 @@ libs = [ "@workingjubilee", "@joboet", "@jhpratt", + "@tgross35", ] bootstrap = [ "@Mark-Simulacrum",