diff options
493 files changed, 8652 insertions, 4352 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caf97abf78d..853f43e15e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ name: CI - "**" permissions: contents: read + packages: write defaults: run: shell: bash @@ -42,6 +43,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" CACHE_DOMAIN: ci-caches.rust-lang.org @@ -172,6 +174,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 DEPLOY_BUCKET: rust-lang-ci2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" @@ -554,6 +557,7 @@ jobs: CI_JOB_NAME: "${{ matrix.name }}" CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}" + DOCKER_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SCCACHE_BUCKET: rust-lang-ci-sccache2 DEPLOY_BUCKET: rust-lang-ci2 TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" diff --git a/Cargo.lock b/Cargo.lock index 74f96983b31..d645957da96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,9 +382,9 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -596,11 +596,11 @@ dependencies = [ name = "clippy_dev" version = "0.0.1" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick 1.0.2", "clap", "indoc", "itertools", - "opener 0.5.2", + "opener", "shell-escape", "walkdir", ] @@ -610,7 +610,7 @@ name = "clippy_lints" version = "0.1.77" dependencies = [ "arrayvec", - "cargo_metadata 0.15.4", + "cargo_metadata 0.18.0", "clippy_config", "clippy_utils", "declare_clippy_lint", @@ -1268,7 +1268,6 @@ name = "error_index_generator" version = "0.0.0" dependencies = [ "mdbook", - "rustc_error_codes", ] [[package]] @@ -2351,7 +2350,7 @@ dependencies = [ "log", "memchr", "once_cell", - "opener 0.6.1", + "opener", "pathdiff", "pulldown-cmark", "regex", @@ -2596,9 +2595,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "compiler_builtins", "crc32fast", @@ -2628,16 +2627,6 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opener" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" -dependencies = [ - "bstr", - "winapi", -] - -[[package]] -name = "opener" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" @@ -3711,7 +3700,6 @@ dependencies = [ "rustc_codegen_ssa", "rustc_const_eval", "rustc_data_structures", - "rustc_error_codes", "rustc_errors", "rustc_expand", "rustc_feature", @@ -3784,9 +3772,11 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", + "rustc_error_codes", "rustc_error_messages", "rustc_fluent_macro", "rustc_hir", + "rustc_index", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -4797,12 +4787,12 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ruzstd" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" dependencies = [ "byteorder", - "thiserror-core", + "derive_more", "twox-hash", ] @@ -5366,26 +5356,6 @@ dependencies = [ ] [[package]] -name = "thiserror-core" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" -dependencies = [ - "thiserror-core-impl", -] - -[[package]] -name = "thiserror-core-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] name = "thiserror-impl" version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5757,9 +5727,9 @@ dependencies = [ [[package]] name = "unic-langid" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" +checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516" dependencies = [ "unic-langid-impl", "unic-langid-macros", @@ -5767,18 +5737,18 @@ dependencies = [ [[package]] name = "unic-langid-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" +checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6" dependencies = [ "tinystr", ] [[package]] name = "unic-langid-macros" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe" +checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec" dependencies = [ "proc-macro-hack", "tinystr", @@ -5788,13 +5758,13 @@ dependencies = [ [[package]] name = "unic-langid-macros-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8" +checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 1.0.109", + "syn 2.0.32", "unic-langid-impl", ] diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 7b781ba1e11..aaeb1bb9bff 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -3,8 +3,7 @@ use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; use crate::token::{self, Token}; use rustc_lexer::unescape::{ - byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, - Mode, + byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, }; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -48,6 +47,9 @@ impl LitKind { return Err(LitError::InvalidSuffix); } + // For byte/char/string literals, chars and escapes have already been + // checked in the lexer (in `cook_lexer_literal`). So we can assume all + // chars and escapes are valid here. Ok(match kind { token::Bool => { assert!(symbol.is_bool_lit()); @@ -56,12 +58,12 @@ impl LitKind { token::Byte => { return unescape_byte(symbol.as_str()) .map(LitKind::Byte) - .map_err(|_| LitError::LexerError); + .map_err(|_| panic!("failed to unescape byte literal")); } token::Char => { return unescape_char(symbol.as_str()) .map(LitKind::Char) - .map_err(|_| LitError::LexerError); + .map_err(|_| panic!("failed to unescape char literal")); } // There are some valid suffixes for integer and float literals, @@ -77,26 +79,22 @@ impl LitKind { let s = symbol.as_str(); // Vanilla strings are so common we optimize for the common case where no chars // requiring special behaviour are present. - let symbol = if s.contains(['\\', '\r']) { + let symbol = if s.contains('\\') { let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); // Force-inlining here is aggressive but the closure is - // called on every char in the string, so it can be - // hot in programs with many long strings. - unescape_literal( + // called on every char in the string, so it can be hot in + // programs with many long strings containing escapes. + unescape_unicode( s, Mode::Str, &mut #[inline(always)] - |_, unescaped_char| match unescaped_char { + |_, c| match c { Ok(c) => buf.push(c), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape string literal") } }, ); - error?; Symbol::intern(&buf) } else { symbol @@ -104,86 +102,46 @@ impl LitKind { LitKind::Str(symbol, ast::StrStyle::Cooked) } token::StrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can reuse the symbol on success. - let mut error = Ok(()); - unescape_literal(symbol.as_str(), Mode::RawStr, &mut |_, unescaped_char| { - match unescaped_char { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - } - }); - error?; + // Raw strings have no escapes so no work is needed here. LitKind::Str(symbol, ast::StrStyle::Raw(n)) } token::ByteStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(s, Mode::ByteStr, &mut |_, c| match c { + unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c { Ok(c) => buf.push(byte_from_char(c)), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape string literal") } }); - error?; LitKind::ByteStr(buf.into(), StrStyle::Cooked) } token::ByteStrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can convert the symbol directly to a `Lrc<u8>` on success. - let s = symbol.as_str(); - let mut error = Ok(()); - unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - }); - LitKind::ByteStr(s.to_owned().into_bytes().into(), StrStyle::Raw(n)) + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc<u8>`. + let buf = symbol.as_str().to_owned().into_bytes(); + LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) } token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_c_string(s, Mode::CStr, &mut |_span, c| match c { - Ok(CStrUnit::Byte(b)) => buf.push(b), - Ok(CStrUnit::Char(c)) => { + unescape_mixed(s, Mode::CStr, &mut |_span, c| match c { + Ok(MixedUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } + Ok(MixedUnit::HighByte(b)) => buf.push(b), Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + assert!(!err.is_fatal(), "failed to unescape C string literal") } }); - error?; buf.push(0); LitKind::CStr(buf.into(), StrStyle::Cooked) } token::CStrRaw(n) => { - // Raw strings have no escapes, so we only need to check for invalid chars, and we - // can convert the symbol directly to a `Lrc<u8>` on success. - let s = symbol.as_str(); - let mut error = Ok(()); - unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c { - Ok(_) => {} - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } - }); - error?; - let mut buf = s.to_owned().into_bytes(); + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc<u8>` after appending the terminating NUL + // char. + let mut buf = symbol.as_str().to_owned().into_bytes(); buf.push(0); LitKind::CStr(buf.into(), StrStyle::Raw(n)) } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 4843d36372d..51bb8a96fad 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,9 +1,9 @@ -use rustc_errors::DiagnosticArgFromDisplay; +use rustc_errors::{codes::*, DiagnosticArgFromDisplay}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")] +#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)] pub struct GenericTypeWithParentheses { #[primary_span] #[label] @@ -22,7 +22,7 @@ pub struct UseAngleBrackets { } #[derive(Diagnostic)] -#[diag(ast_lowering_invalid_abi, code = "E0703")] +#[diag(ast_lowering_invalid_abi, code = E0703)] #[note] pub struct InvalidAbi { #[primary_span] @@ -89,7 +89,7 @@ pub enum AssocTyParenthesesSub { } #[derive(Diagnostic)] -#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] +#[diag(ast_lowering_misplaced_impl_trait, code = E0562)] #[note] pub struct MisplacedImplTrait<'a> { #[primary_span] @@ -114,7 +114,7 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_base_expression_double_dot, code = "E0797")] +#[diag(ast_lowering_base_expression_double_dot, code = E0797)] pub struct BaseExpressionDoubleDot { #[primary_span] #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] @@ -122,7 +122,7 @@ pub struct BaseExpressionDoubleDot { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")] +#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)] pub struct AwaitOnlyInAsyncFnAndBlocks { #[primary_span] #[label] @@ -132,14 +132,14 @@ pub struct AwaitOnlyInAsyncFnAndBlocks { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_coroutine_too_many_parameters, code = "E0628")] +#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)] pub struct CoroutineTooManyParameters { #[primary_span] pub fn_decl_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")] +#[diag(ast_lowering_closure_cannot_be_static, code = E0697)] pub struct ClosureCannotBeStatic { #[primary_span] pub fn_decl_span: Span, @@ -154,14 +154,14 @@ pub struct FunctionalRecordUpdateDestructuringAssignment { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_async_coroutines_not_supported, code = "E0727")] +#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)] pub struct AsyncCoroutinesNotSupported { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")] +#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)] pub struct InlineAsmUnsupportedTarget { #[primary_span] pub span: Span, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index e2b8e64b115..5f54a0ddf8c 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::{AddToDiagnostic, Applicability}; +use rustc_errors::{codes::*, AddToDiagnostic, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -23,7 +23,7 @@ pub struct InvalidLabel { } #[derive(Diagnostic)] -#[diag(ast_passes_visibility_not_permitted, code = "E0449")] +#[diag(ast_passes_visibility_not_permitted, code = E0449)] pub struct VisibilityNotPermitted { #[primary_span] pub span: Span, @@ -44,7 +44,7 @@ pub enum VisibilityNotPermittedNote { } #[derive(Diagnostic)] -#[diag(ast_passes_trait_fn_const, code = "E0379")] +#[diag(ast_passes_trait_fn_const, code = E0379)] pub struct TraitFnConst { #[primary_span] #[label] @@ -302,14 +302,14 @@ pub struct ItemUnderscore<'a> { } #[derive(Diagnostic)] -#[diag(ast_passes_nomangle_ascii, code = "E0754")] +#[diag(ast_passes_nomangle_ascii, code = E0754)] pub struct NoMangleAscii { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_module_nonascii, code = "E0754")] +#[diag(ast_passes_module_nonascii, code = E0754)] #[help] pub struct ModuleNonAscii { #[primary_span] @@ -318,7 +318,7 @@ pub struct ModuleNonAscii { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_generic, code = "E0567")] +#[diag(ast_passes_auto_generic, code = E0567)] pub struct AutoTraitGeneric { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -328,7 +328,7 @@ pub struct AutoTraitGeneric { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_super_lifetime, code = "E0568")] +#[diag(ast_passes_auto_super_lifetime, code = E0568)] pub struct AutoTraitBounds { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -338,7 +338,7 @@ pub struct AutoTraitBounds { } #[derive(Diagnostic)] -#[diag(ast_passes_auto_items, code = "E0380")] +#[diag(ast_passes_auto_items, code = E0380)] pub struct AutoTraitItems { #[primary_span] pub spans: Vec<Span>, @@ -384,28 +384,28 @@ impl AddToDiagnostic for EmptyLabelManySpans { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")] +#[diag(ast_passes_pattern_in_fn_pointer, code = E0561)] pub struct PatternFnPointer { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_trait_object_single_bound, code = "E0226")] +#[diag(ast_passes_trait_object_single_bound, code = E0226)] pub struct TraitObjectBound { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = "E0667")] +#[diag(ast_passes_impl_trait_path, code = E0667)] pub struct ImplTraitPath { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_nested_impl_trait, code = "E0666")] +#[diag(ast_passes_nested_impl_trait, code = E0666)] pub struct NestedImplTrait { #[primary_span] pub span: Span, @@ -443,7 +443,7 @@ pub struct ObsoleteAuto { } #[derive(Diagnostic)] -#[diag(ast_passes_unsafe_negative_impl, code = "E0198")] +#[diag(ast_passes_unsafe_negative_impl, code = E0198)] pub struct UnsafeNegativeImpl { #[primary_span] pub span: Span, @@ -468,7 +468,7 @@ pub struct InherentImplCannot<'a> { } #[derive(Diagnostic)] -#[diag(ast_passes_inherent_cannot_be, code = "E0197")] +#[diag(ast_passes_inherent_cannot_be, code = E0197)] pub struct InherentImplCannotUnsafe<'a> { #[primary_span] pub span: Span, @@ -536,7 +536,7 @@ pub struct GenericDefaultTrailing { } #[derive(Diagnostic)] -#[diag(ast_passes_nested_lifetimes, code = "E0316")] +#[diag(ast_passes_nested_lifetimes, code = E0316)] pub struct NestedLifetimes { #[primary_span] pub span: Span, @@ -655,7 +655,7 @@ pub struct ConstAndCVariadic { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_foreign, code = "E0130")] +#[diag(ast_passes_pattern_in_foreign, code = E0130)] pub struct PatternInForeign { #[primary_span] #[label] @@ -663,7 +663,7 @@ pub struct PatternInForeign { } #[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_bodiless, code = "E0642")] +#[diag(ast_passes_pattern_in_bodiless, code = E0642)] pub struct PatternInBodiless { #[primary_span] #[label] @@ -711,14 +711,14 @@ pub struct AssociatedSuggestion2 { } #[derive(Diagnostic)] -#[diag(ast_passes_stability_outside_std, code = "E0734")] +#[diag(ast_passes_stability_outside_std, code = E0734)] pub struct StabilityOutsideStd { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes_feature_on_non_nightly, code = "E0554")] +#[diag(ast_passes_feature_on_non_nightly, code = E0554)] pub struct FeatureOnNonNightly { #[primary_span] pub span: Span, diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 315a00c8d2f..79370602842 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -2,8 +2,7 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - Level, + codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -12,14 +11,14 @@ use crate::fluent_generated as fluent; use crate::UnsupportedLiteralReason; #[derive(Diagnostic)] -#[diag(attr_expected_one_cfg_pattern, code = "E0536")] +#[diag(attr_expected_one_cfg_pattern, code = E0536)] pub(crate) struct ExpectedOneCfgPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_predicate, code = "E0537")] +#[diag(attr_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { #[primary_span] pub span: Span, @@ -28,7 +27,7 @@ pub(crate) struct InvalidPredicate { } #[derive(Diagnostic)] -#[diag(attr_multiple_item, code = "E0538")] +#[diag(attr_multiple_item, code = E0538)] pub(crate) struct MultipleItem { #[primary_span] pub span: Span, @@ -37,7 +36,7 @@ pub(crate) struct MultipleItem { } #[derive(Diagnostic)] -#[diag(attr_incorrect_meta_item, code = "E0539")] +#[diag(attr_incorrect_meta_item, code = E0539)] pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, @@ -56,7 +55,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item) .with_span(self.span) - .with_code(error_code!(E0541)) + .with_code(E0541) .with_arg("item", self.item) .with_arg("expected", expected.join(", ")) .with_span_label(self.span, fluent::attr_label) @@ -64,28 +63,28 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { } #[derive(Diagnostic)] -#[diag(attr_missing_since, code = "E0542")] +#[diag(attr_missing_since, code = E0542)] pub(crate) struct MissingSince { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_missing_note, code = "E0543")] +#[diag(attr_missing_note, code = E0543)] pub(crate) struct MissingNote { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_multiple_stability_levels, code = "E0544")] +#[diag(attr_multiple_stability_levels, code = E0544)] pub(crate) struct MultipleStabilityLevels { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_issue_string, code = "E0545")] +#[diag(attr_invalid_issue_string, code = E0545)] pub(crate) struct InvalidIssueString { #[primary_span] pub span: Span, @@ -143,21 +142,21 @@ impl InvalidIssueStringCause { } #[derive(Diagnostic)] -#[diag(attr_missing_feature, code = "E0546")] +#[diag(attr_missing_feature, code = E0546)] pub(crate) struct MissingFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_non_ident_feature, code = "E0546")] +#[diag(attr_non_ident_feature, code = E0546)] pub(crate) struct NonIdentFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_missing_issue, code = "E0547")] +#[diag(attr_missing_issue, code = E0547)] pub(crate) struct MissingIssue { #[primary_span] pub span: Span, @@ -166,14 +165,14 @@ pub(crate) struct MissingIssue { // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? // It is more similar to `IncorrectReprFormatGeneric`. #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] +#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)] pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_paren, code = E0552)] pub(crate) struct InvalidReprHintNoParen { #[primary_span] pub span: Span, @@ -182,7 +181,7 @@ pub(crate) struct InvalidReprHintNoParen { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_value, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_value, code = E0552)] pub(crate) struct InvalidReprHintNoValue { #[primary_span] pub span: Span, @@ -215,7 +214,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { }, ); diag.span(self.span); - diag.code(error_code!(E0565)); + diag.code(E0565); if self.is_bytestr { diag.span_suggestion( self.start_point_span, @@ -229,7 +228,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_align_need_arg, code = "E0589")] +#[diag(attr_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { #[primary_span] #[suggestion(code = "align(...)", applicability = "has-placeholders")] @@ -237,7 +236,7 @@ pub(crate) struct InvalidReprAlignNeedArg { } #[derive(Diagnostic)] -#[diag(attr_invalid_repr_generic, code = "E0589")] +#[diag(attr_invalid_repr_generic, code = E0589)] pub(crate) struct InvalidReprGeneric<'a> { #[primary_span] pub span: Span, @@ -247,14 +246,14 @@ pub(crate) struct InvalidReprGeneric<'a> { } #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")] +#[diag(attr_incorrect_repr_format_align_one_arg, code = E0693)] pub(crate) struct IncorrectReprFormatAlignOneArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_generic, code = "E0693")] +#[diag(attr_incorrect_repr_format_generic, code = E0693)] pub(crate) struct IncorrectReprFormatGeneric<'a> { #[primary_span] pub span: Span, @@ -305,14 +304,14 @@ impl<'a> IncorrectReprFormatGenericCause<'a> { } #[derive(Diagnostic)] -#[diag(attr_rustc_promotable_pairing, code = "E0717")] +#[diag(attr_rustc_promotable_pairing, code = E0717)] pub(crate) struct RustcPromotablePairing { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")] +#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { #[primary_span] pub span: Span, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 351976cdaea..8a275a83630 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{struct_span_code_err, DiagCtxt, DiagnosticBuilder}; +use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index da67862a48d..2e83072b8d1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3,7 +3,9 @@ use either::Either; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index e321b92603d..1685624f247 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,4 +1,4 @@ -use rustc_errors::MultiSpan; +use rustc_errors::{codes::*, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -6,7 +6,7 @@ use rustc_span::Span; use crate::diagnostics::RegionName; #[derive(Diagnostic)] -#[diag(borrowck_move_unsized, code = "E0161")] +#[diag(borrowck_move_unsized, code = E0161)] pub(crate) struct MoveUnsized<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -281,7 +281,7 @@ pub(crate) enum CaptureVarCause { } #[derive(Diagnostic)] -#[diag(borrowck_cannot_move_when_borrowed, code = "E0505")] +#[diag(borrowck_cannot_move_when_borrowed, code = E0505)] pub(crate) struct MoveBorrow<'a> { pub place: &'a str, pub borrow_place: &'a str, @@ -294,7 +294,7 @@ pub(crate) struct MoveBorrow<'a> { } #[derive(Diagnostic)] -#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")] +#[diag(borrowck_opaque_type_non_generic_param, code = E0792)] pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { pub ty: GenericArg<'tcx>, pub kind: &'a str, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d6dfd0efaf9..eadb48ddd36 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, - MultiSpan, SingleLabelManySpans, + codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + Level, MultiSpan, SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -269,7 +269,7 @@ pub(crate) struct ConcatIdentsIdentArgs { } #[derive(Diagnostic)] -#[diag(builtin_macros_bad_derive_target, code = "E0774")] +#[diag(builtin_macros_bad_derive_target, code = E0774)] pub(crate) struct BadDeriveTarget { #[primary_span] #[label] @@ -283,7 +283,7 @@ pub(crate) struct BadDeriveTarget { pub(crate) struct TestsNotSupport {} #[derive(Diagnostic)] -#[diag(builtin_macros_unexpected_lit, code = "E0777")] +#[diag(builtin_macros_unexpected_lit, code = E0777)] pub(crate) struct BadDeriveLit { #[primary_span] #[label] diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml index bd3b051185b..e6bf944f552 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml @@ -33,14 +33,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml index 3efdec41559..b4f8ce0f532 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml @@ -10,7 +10,7 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | sed -i 's/components.*/components = []/' rust-toolchain echo 'profile = "minimal"' >> rust-toolchain diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 9bbb18fc37f..cf9a105538d 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Avoid installing rustc-dev run: | @@ -64,14 +64,14 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features if: matrix.os == 'ubuntu-latest' run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -138,7 +138,7 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo @@ -164,13 +164,13 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -221,10 +221,10 @@ jobs: TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -276,7 +276,7 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Download all built artifacts uses: actions/download-artifact@v4 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index 8085dc58263..930d025b73e 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -9,13 +9,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} @@ -32,13 +32,13 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CPU features run: cat /proc/cpuinfo - name: Cache cargo target dir - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index 834a1362caf..491646ce59b 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,8 +1,9 @@ { "editor.formatOnSave": true, - // source for rustc_* is not included in the rust-src component; disable the errors about this + // in case rustc.source is disabled for performance reasons; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 6d6a1200f50..86bc7d0f067 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c22542c0b95bd3302f7ed6839869c561f2324bac2fd5e7e99f5cfa65fdc8b92" +checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3db903ef2e9c8a4de2ea6db5db052c7857282952f9df604aa55d169e6000d8" +checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c" dependencies = [ "bumpalo", "cranelift-bforest", @@ -75,39 +75,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6590feb5a1d6438f974bf6a5ac4dddf69fca14e1f07f3265d880f69e61a94463" +checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7239038c56fafe77fddc8788fc8533dd6c474dc5bdc5637216404f41ba807330" +checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36" [[package]] name = "cranelift-control" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dc9c595341404d381d27a3d950160856b35b402275f0c3990cd1ad683c8053" +checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7" +checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d" [[package]] name = "cranelift-frontend" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a612c94d09e653662ec37681dc2d6fd2b9856e6df7147be0afc9aabb0abf19df" +checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd" dependencies = [ "cranelift-codegen", "log", @@ -117,15 +117,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85db9830abeb1170b7d29b536ffd55af1d4d26ac8a77570b5d1aca003bf225cc" +checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96" [[package]] name = "cranelift-jit" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4946271f1055e26544ef8c90fa24776f201566419dfac4b3962c39d5a804ff67" +checksum = "2f61e236d7622c3c43016e8b0f3ba27136e21ac7de328c7fda902e61db1de851" dependencies = [ "anyhow", "cranelift-codegen", @@ -138,14 +138,14 @@ dependencies = [ "region", "target-lexicon", "wasmtime-jit-icache-coherence", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "cranelift-module" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7e3bdae2597556e59edeb8ecb62eb32c7e054c4f042d393732902979db69c3" +checksum = "f30c6820342015c5009070e3e48d1da7b13521399de904663f1c84f5ee839657" dependencies = [ "anyhow", "cranelift-codegen", @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301ef0edafeaeda5771a5d2db64ac53e1818ae3111220a185677025fe91db4a1" +checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b" dependencies = [ "cranelift-codegen", "libc", @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e0ee3d013728903e0c513c31afa389b559bfd4fe8a44f80335c799e3132a41" +checksum = "24425a329b4343177d5f1852243841dcec17f929d72c0e7f41262140155e55e7" dependencies = [ "anyhow", "cranelift-codegen", @@ -251,7 +251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -374,13 +374,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b6d197fcc34ad32ed440e1f9552fd57d1f377d9699d31dee1b5b457322c1f8a" +checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da" dependencies = [ "cfg-if", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -411,7 +411,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -420,13 +429,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -436,37 +460,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index c57e964168f..586ce2286f9 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.103", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.103" } -cranelift-module = { version = "0.103" } -cranelift-native = { version = "0.103" } -cranelift-jit = { version = "0.103", optional = true } -cranelift-object = { version = "0.103" } +cranelift-codegen = { version = "0.104", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.104" } +cranelift-module = { version = "0.104" } +cranelift-native = { version = "0.104" } +cranelift-jit = { version = "0.104", optional = true } +cranelift-object = { version = "0.104" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index ca6ecdf1d0e..4f455261963 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -62,6 +62,27 @@ $ ./test.sh For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. +## Platform support + +|OS \ architecture|x86\_64|AArch64|Riscv64|s390x (System-Z)| +|---|---|---|---|---| +|Linux|✅|✅|✅[^no-rustup]|✅[^no-rustup]| +|FreeBSD|✅[^no-rustup]|❓|❓|❓| +|AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| +|Other unixes|❓|❓|❓|❓| +|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|Windows|✅[^no-rustup]|❌|N/A|N/A| + +✅: Fully supported and tested +❓: Maybe supported, not tested +❌: Not supported at all + +Not all targets are available as rustup component for nightly. See notes in the platform support matrix. + +[^xcoff]: XCOFF object file format is not supported. +[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). +[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. + ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. @@ -100,6 +121,8 @@ You need to do this steps to successfully compile and use the cranelift backend * (Optional) run tests: `rustup run stage2 ./y.sh test` 8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. +You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. + ## Configuration See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index cb7b2454cd5..818f3d6f08d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -113,8 +113,8 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rust-random", "rand", - "9a02c819cc1e4ec6959ae25eafbb5cf6acb68234", - "4934f0afb1d1c2ca", + "1f4507a8e1cf8050e4ceef95eeda8f64645b6719", + "981f8bf489338978", "rand", ); @@ -133,8 +133,8 @@ pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( "rust-lang", "portable-simd", - "4825b2a64d765317066948867e8714674419359b", - "9e67d07c00f5fb0b", + "97007cc2e70df8c97326ce896a79e2f0ce4dd98b", + "e54a16035cedf205", "portable-simd", ); diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch deleted file mode 100644 index b8c0783f524..00000000000 --- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch +++ /dev/null @@ -1,22 +0,0 @@ -From a101a43b795431ce617e7782afb451f4853afc00 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Thu, 7 Dec 2023 14:51:35 +0000 -Subject: [PATCH] Enable the exposed_provenance feature - ---- - crates/core_simd/tests/pointers.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs -index 0ae8f83..06620d6 100644 ---- a/crates/core_simd/tests/pointers.rs -+++ b/crates/core_simd/tests/pointers.rs -@@ -1,4 +1,4 @@ --#![feature(portable_simd, strict_provenance)] -+#![feature(exposed_provenance, portable_simd, strict_provenance)] - - use core_simd::simd::{Simd, SimdConstPtr, SimdMutPtr}; - --- -2.34.1 - diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch index be29ae09bcf..271ca12eabb 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch @@ -21,7 +21,7 @@ index 897a5e9..331f66f 100644 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] - #![feature(slice_group_by)] + #![feature(split_array)] diff --git a/atomic.rs b/atomic.rs index b735957..ea728b6 100644 --- a/atomic.rs diff --git a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml index aacf3653c16..815b828a68b 100644 --- a/compiler/rustc_codegen_cranelift/patches/rand-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/rand-lock.toml @@ -487,6 +487,7 @@ dependencies = [ "rand_pcg", "rayon", "serde", + "zerocopy", ] [[package]] @@ -505,6 +506,7 @@ version = "0.7.0" dependencies = [ "getrandom", "serde", + "zerocopy", ] [[package]] @@ -525,6 +527,7 @@ name = "rand_pcg" version = "0.4.0" dependencies = [ "bincode", + "rand", "rand_core", "serde", ] @@ -823,3 +826,23 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml index 8e213f71c3f..ad63b0768d3 100644 --- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.104" +version = "0.1.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3f9035afc33f4358773239573f7d121099856753e1bbd2a6a5207098fc741" +checksum = "f4ab134a739bafec76aa91ccb15d519a54e569350644a1fea6528d5a0d407e22" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index a086c029360..ccd7edbc2a9 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-31" +channel = "nightly-2024-01-26" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index e6edc452cfb..2d9c2ecdbc2 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -13,17 +13,14 @@ use gimli::write::{ }; use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; use indexmap::IndexSet; +use rustc_session::Session; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; pub(crate) use self::unwind::UnwindContext; use crate::prelude::*; -pub(crate) fn producer() -> String { - format!( - "rustc version {} with cranelift {}", - rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), - cranelift_codegen::VERSION, - ) +pub(crate) fn producer(sess: &Session) -> String { + format!("rustc version {} with cranelift {}", sess.cfg_version, cranelift_codegen::VERSION) } pub(crate) struct DebugContext { @@ -67,7 +64,7 @@ impl DebugContext { let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen(); - let producer = producer(); + let producer = producer(tcx.sess); let comp_dir = tcx .sess .opts diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index e77b0cd0721..757082a5fed 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -143,6 +143,7 @@ fn emit_cgu( debug: Option<DebugContext>, unwind_context: UnwindContext, global_asm_object_file: Option<PathBuf>, + producer: &str, ) -> Result<ModuleCodegenResult, String> { let mut product = module.finish(); @@ -152,8 +153,14 @@ fn emit_cgu( unwind_context.emit(&mut product); - let module_regular = - emit_module(output_filenames, prof, product.object, ModuleKind::Regular, name.clone())?; + let module_regular = emit_module( + output_filenames, + prof, + product.object, + ModuleKind::Regular, + name.clone(), + producer, + )?; Ok(ModuleCodegenResult { module_regular, @@ -174,6 +181,7 @@ fn emit_module( mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, name: String, + producer_str: &str, ) -> Result<CompiledModule, String> { if object.format() == cranelift_object::object::BinaryFormat::Elf { let comment_section = object.add_section( @@ -182,7 +190,7 @@ fn emit_module( cranelift_object::object::SectionKind::OtherString, ); let mut producer = vec![0]; - producer.extend(crate::debuginfo::producer().as_bytes()); + producer.extend(producer_str.as_bytes()); producer.push(0); object.set_section_data(comment_section, producer, 1); } @@ -321,6 +329,8 @@ fn module_codegen( (cgu_name, cx, module, codegened_functions) }); + let producer = crate::debuginfo::producer(tcx.sess); + OngoingModuleCodegen::Async(std::thread::spawn(move || { cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| { cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( @@ -348,6 +358,7 @@ fn module_codegen( cx.debug_context, cx.unwind_context, global_asm_object_file, + &producer, ) }); std::mem::drop(token); @@ -453,6 +464,7 @@ pub(crate) fn run_aot( product.object, ModuleKind::Allocator, "allocator_shim".to_owned(), + &crate::debuginfo::producer(tcx.sess), ) { Ok(allocator_module) => Some(allocator_module), Err(err) => tcx.dcx().fatal(err), @@ -467,7 +479,7 @@ pub(crate) fn run_aot( let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")) + .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) .as_str() .to_string(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 50d9f287e74..6b2b946db02 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -321,10 +321,9 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - sess.dcx() - .struct_err(format!("Can't load static lib {}", name)) - .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") - .emit(); + let mut diag = sess.dcx().struct_err(format!("Can't load static lib {}", name)); + diag.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); + diag.emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 6b9cec39d70..7793b1b7092 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -52,7 +52,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( } let operands = operands - .into_iter() + .iter() .map(|operand| match *operand { InlineAsmOperand::In { reg, ref value } => CInlineAsmOperand::In { reg, @@ -506,10 +506,34 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push('%'); } - self.registers[*operand_idx] - .unwrap() - .emit(&mut generated_asm, self.arch, *modifier) - .unwrap(); + + let reg = self.registers[*operand_idx].unwrap(); + match self.arch { + InlineAsmArch::X86_64 => match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + let class = match *modifier { + None | Some('x') => "xmm", + Some('y') => "ymm", + Some('z') => "zmm", + _ => unreachable!(), + }; + write!( + generated_asm, + "{class}{}", + reg as u32 - X86InlineAsmReg::xmm0 as u32 + ) + .unwrap(); + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) + .unwrap(), + }, + _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), + } } CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); @@ -739,7 +763,7 @@ fn call_inline_asm<'tcx>( }, ) .unwrap(); - let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); + let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(inline_asm_func, asm_name); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 1345c4614e2..e50c74b87f6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -35,6 +35,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( } match intrinsic { + "llvm.prefetch" => { + // Nothing to do. This is merely a perf hint. + } + _ if intrinsic.starts_with("llvm.ctlz.v") => { intrinsic_args!(fx, args => (a); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index f6f3b85d3ef..e66bcbf4e40 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -243,6 +243,20 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( } // FIXME generalize vector types + "llvm.aarch64.neon.tbl1.v8i8" => { + intrinsic_args!(fx, args => (t, idx); intrinsic); + + let zero = fx.bcx.ins().iconst(types::I8, 0); + for i in 0..8 { + let idx_lane = idx.value_lane(fx, i).load_scalar(fx); + let is_zero = + fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, idx_lane, 16); + let t_idx = fx.bcx.ins().uextend(fx.pointer_type, idx_lane); + let t_lane = t.value_lane_dyn(fx, t_idx).load_scalar(fx); + let res = fx.bcx.ins().select(is_zero, zero, t_lane); + ret.place_lane(fx, i).to_ptr().store(fx, res, MemFlags::trusted()); + } + } "llvm.aarch64.neon.tbl1.v16i8" => { intrinsic_args!(fx, args => (t, idx); intrinsic); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 994dc66835c..2e3e7ce986b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -610,230 +610,56 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi16&ig_expand=4903 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); + "llvm.x86.sse2.packsswb.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi16&ig_expand=4848 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Sse); } "llvm.x86.avx2.packuswb" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi16&ig_expand=4906 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i16); - assert_eq!(ret_lane_ty, fx.tcx.types.u8); - assert_eq!(lane_count * 2, ret_lane_count); - - let zero = fx.bcx.ins().iconst(types::I16, 0); - let max_u8 = fx.bcx.ins().iconst(types::I16, 255); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u8); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, zero); - let sat = fx.bcx.ins().umin(sat, max_u8); - let res = fx.bcx.ins().ireduce(types::I8, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U8, PackWidth::Avx); } - "llvm.x86.sse2.packssdw.128" => { - // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + "llvm.x86.avx2.packsswb" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi16&ig_expand=4851 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S8, PackWidth::Avx); } "llvm.x86.sse41.packusdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packus_epi32&ig_expand=4912 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.u16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MIN)); - let max_u16 = fx.bcx.ins().iconst(types::I32, i64::from(u16::MAX)); - let ret_lane_layout = fx.layout_of(fx.tcx.types.u16); + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.sse2.packssdw.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi32&ig_expand=4889 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Sse); + } - for idx in 0..lane_count { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_u16); - let sat = fx.bcx.ins().smin(sat, max_u16); - let res = fx.bcx.ins().ireduce(types::I16, sat); + "llvm.x86.avx2.packusdw" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packus_epi32&ig_expand=4883 + intrinsic_args!(fx, args => (a, b); intrinsic); - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::U16, PackWidth::Avx); } "llvm.x86.avx2.packssdw" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi32&ig_expand=4892 intrinsic_args!(fx, args => (a, b); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); - - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i32); - assert_eq!(ret_lane_ty, fx.tcx.types.i16); - assert_eq!(lane_count * 2, ret_lane_count); - - let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); - let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); - let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 2 + idx).write_cvalue(fx, res_lane); - } - - for idx in 0..lane_count / 2 { - let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().smin(sat, max_i16); - let res = fx.bcx.ins().ireduce(types::I16, sat); - - let res_lane = CValue::by_val(res, ret_lane_layout); - ret.place_lane(fx, lane_count / 2 * 3 + idx).write_cvalue(fx, res_lane); - } + pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx); } "llvm.x86.fma.vfmaddsub.ps" @@ -1407,3 +1233,115 @@ fn llvm_add_sub<'tcx>( (cb_out, c) } + +enum PackSize { + U8, + U16, + S8, + S16, +} + +impl PackSize { + fn ret_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I8, + Self::U16 | Self::S16 => types::I16, + } + } + fn src_clif_type(&self) -> Type { + match self { + Self::U8 | Self::S8 => types::I16, + Self::U16 | Self::S16 => types::I32, + } + } + fn src_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 | Self::S8 => tcx.types.i16, + Self::U16 | Self::S16 => tcx.types.i32, + } + } + fn ret_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self { + Self::U8 => tcx.types.u8, + Self::S8 => tcx.types.i8, + Self::U16 => tcx.types.u16, + Self::S16 => tcx.types.i16, + } + } + fn max(&self) -> i64 { + match self { + Self::U8 => u8::MAX as u64 as i64, + Self::S8 => i8::MAX as u8 as u64 as i64, + Self::U16 => u16::MAX as u64 as i64, + Self::S16 => i16::MAX as u64 as u64 as i64, + } + } + fn min(&self) -> i64 { + match self { + Self::U8 | Self::U16 => 0, + Self::S8 => i16::from(i8::MIN) as u16 as i64, + Self::S16 => i32::from(i16::MIN) as u32 as i64, + } + } +} + +enum PackWidth { + Sse = 1, + Avx = 2, +} +impl PackWidth { + fn divisor(&self) -> u64 { + match self { + Self::Sse => 1, + Self::Avx => 2, + } + } +} + +/// Implement an x86 pack instruction with the intrinsic `_mm{,256}pack{us,s}_epi{16,32}`. +/// Validated for correctness against LLVM, see commit `c8f5d35508e062bd2d95e6c03429bfec831db6d3`. +fn pack_instruction<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + a: CValue<'tcx>, + b: CValue<'tcx>, + ret: CPlace<'tcx>, + ret_size: PackSize, + width: PackWidth, +) { + assert_eq!(a.layout(), b.layout()); + let layout = a.layout(); + + let (src_lane_count, src_lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(src_lane_ty, ret_size.src_ty(fx.tcx)); + assert_eq!(ret_lane_ty, ret_size.ret_ty(fx.tcx)); + assert_eq!(src_lane_count * 2, ret_lane_count); + + let min = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.min()); + let max = fx.bcx.ins().iconst(ret_size.src_clif_type(), ret_size.max()); + let ret_lane_layout = fx.layout_of(ret_size.ret_ty(fx.tcx)); + + let mut round = |source: CValue<'tcx>, source_offset: u64, dest_offset: u64| { + let step_amount = src_lane_count / width.divisor(); + let dest_offset = step_amount * dest_offset; + for idx in 0..step_amount { + let lane = source.value_lane(fx, step_amount * source_offset + idx).load_scalar(fx); + let sat = fx.bcx.ins().smax(lane, min); + let sat = match ret_size { + PackSize::U8 | PackSize::U16 => fx.bcx.ins().umin(sat, max), + PackSize::S8 | PackSize::S16 => fx.bcx.ins().smin(sat, max), + }; + let res = fx.bcx.ins().ireduce(ret_size.ret_clif_type(), sat); + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, dest_offset + idx).write_cvalue(fx, res_lane); + } + }; + + round(a, 0, 0); + round(b, 0, 1); + + if let PackWidth::Avx = width { + round(a, 1, 2); + round(b, 1, 3); + } +} diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index d56d17892d5..ebdc744bcd8 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -293,7 +293,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } ret.write_cvalue(fx, base); - let ret_lane = ret.place_lane(fx, idx.try_into().unwrap()); + let ret_lane = ret.place_lane(fx, idx.into()); ret_lane.write_cvalue(fx, val); } @@ -340,7 +340,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); } - let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); + let ret_lane = v.value_lane(fx, idx.into()); ret.write_cvalue(fx, ret_lane); } @@ -822,7 +822,35 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); let lane_layout = fx.layout_of(lane_ty); - let m = m.load_scalar(fx); + let expected_int_bits = lane_count.max(8); + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + + let m = match m.layout().ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => m.load_scalar(fx), + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + m.force_stack(fx).0.load( + fx, + Type::int(expected_int_bits as u16).unwrap(), + MemFlags::trusted(), + ) + } + _ => { + fx.tcx.dcx().span_fatal( + span, + format!( + "invalid monomorphization of `simd_select_bitmask` intrinsic: \ + cannot accept `{}` as mask, expected `u{}` or `[u8; {}]`", + ret.layout().ty, + expected_int_bits, + expected_bytes + ), + ); + } + }; for lane in 0..lane_count { let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b482f0dd2f0..416f87fcc87 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -18,7 +18,6 @@ extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; -extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_session; extern crate rustc_span; @@ -42,7 +41,7 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; pub use crate::config::*; use crate::prelude::*; @@ -190,8 +189,17 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> { - vec![] // FIXME necessary for #[cfg(target_feature] + fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> { + // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] + if sess.target.arch == "x86_64" && sess.target.os != "none" { + // x86_64 mandates SSE2 support + vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")] + } else if sess.target.arch == "aarch64" && sess.target.os != "none" { + // AArch64 mandates Neon support + vec![sym::neon] + } else { + vec![] + } } fn print_version(&self) { @@ -305,16 +313,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar let flags = settings::Flags::new(flags_builder); let isa_builder = match sess.opts.cg.target_cpu.as_deref() { - Some("native") => { - let builder = cranelift_native::builder_with_options(true).unwrap(); - builder - } + Some("native") => cranelift_native::builder_with_options(true).unwrap(), Some(value) => { let mut builder = cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| { sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err)); }); - if let Err(_) = builder.enable(value) { + if builder.enable(value).is_err() { sess.dcx() .fatal("the specified target cpu isn't currently supported by Cranelift."); } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f777e11371f..acfa461a6f3 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -28,10 +28,9 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - ( - &ty::Dynamic(ref data_a, _, src_dyn_kind), - &ty::Dynamic(ref data_b, _, target_dyn_kind), - ) if src_dyn_kind == target_dyn_kind => { + (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) + if src_dyn_kind == target_dyn_kind => + { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 41ea0b122de..d2254d4c15e 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -95,7 +95,7 @@ pub(crate) fn get_vtable<'tcx>( let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); let data_id = data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id)); } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 7a86ddc7556..d5bc04f594d 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -39,6 +39,9 @@ codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdy codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type without `-Zdylib-lto` +codegen_llvm_mismatch_data_layout = + data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}` + codegen_llvm_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5ef05dfbe4c..6cb62280a59 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; use libc::c_uint; +use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::CStr; use std::str; @@ -155,8 +156,7 @@ pub unsafe fn create_module<'ll>( } // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.is_builtin { - // tm is disposed by its drop impl + { let tm = crate::back::write::create_informational_target_machine(tcx.sess); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); @@ -164,33 +164,13 @@ pub unsafe fn create_module<'ll>( let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) .expect("got a non-UTF8 data-layout from LLVM"); - // Unfortunately LLVM target specs change over time, and right now we - // don't have proper support to work with any more than one - // `data_layout` than the one that is in the rust-lang/rust repo. If - // this compiler is configured against a custom LLVM, we may have a - // differing data layout, even though we should update our own to use - // that one. - // - // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we - // disable this check entirely as we may be configured with something - // that has a different target layout. - // - // Unsure if this will actually cause breakage when rustc is configured - // as such. - // - // FIXME(#34960) - let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); - - if !custom_llvm_used && target_data_layout != llvm_data_layout { - bug!( - "data-layout for target `{rustc_target}`, `{rustc_layout}`, \ - differs from LLVM target's `{llvm_target}` default layout, `{llvm_layout}`", - rustc_target = sess.opts.target_triple, - rustc_layout = target_data_layout, - llvm_target = sess.target.llvm_target, - llvm_layout = llvm_data_layout - ); + if target_data_layout != llvm_data_layout { + tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + rustc_target: sess.opts.target_triple.to_string().as_str(), + rustc_layout: target_data_layout.as_str(), + llvm_target: sess.target.llvm_target.borrow(), + llvm_layout: llvm_data_layout, + }); } } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 697ce602298..d82ff6656f4 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -244,3 +244,12 @@ pub(crate) struct CopyBitcode { pub struct UnknownCompression { pub algorithm: &'static str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_mismatch_data_layout)] +pub struct MismatchedDataLayout<'a> { + pub rustc_target: &'a str, + pub rustc_layout: &'a str, + pub llvm_target: &'a str, + pub llvm_layout: &'a str, +} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5d497d4a188..b13d566b40b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -15,7 +15,7 @@ use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{translation::Translate, DiagCtxt, FatalError, Level}; -use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, Style}; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, ErrCode, Style}; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ @@ -1000,7 +1000,7 @@ type DiagnosticArgName<'source> = Cow<'source, str>; struct Diagnostic { msgs: Vec<(DiagnosticMessage, Style)>, args: FxHashMap<DiagnosticArgName<'static>, rustc_errors::DiagnosticArgValue<'static>>, - code: Option<String>, + code: Option<ErrCode>, lvl: Level, } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index cca239a43b3..47b1b080119 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,6 +1,6 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f90e1906caf..ef291ead190 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -4,7 +4,7 @@ use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + codes::*, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_macros::Diagnostic; @@ -612,7 +612,7 @@ pub struct UnknownAtomicOperation; #[derive(Diagnostic)] pub enum InvalidMonomorphization<'tcx> { - #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = E0511)] BasicIntegerType { #[primary_span] span: Span, @@ -620,7 +620,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)] BasicFloatType { #[primary_span] span: Span, @@ -628,14 +628,14 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = E0511)] FloatToIntUnchecked { #[primary_span] span: Span, ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = E0511)] FloatingPointVector { #[primary_span] span: Span, @@ -644,7 +644,7 @@ pub enum InvalidMonomorphization<'tcx> { in_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = E0511)] FloatingPointType { #[primary_span] span: Span, @@ -652,14 +652,14 @@ pub enum InvalidMonomorphization<'tcx> { in_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = E0511)] UnrecognizedIntrinsic { #[primary_span] span: Span, name: Symbol, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = E0511)] SimdArgument { #[primary_span] span: Span, @@ -667,7 +667,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = E0511)] SimdInput { #[primary_span] span: Span, @@ -675,7 +675,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = E0511)] SimdFirst { #[primary_span] span: Span, @@ -683,7 +683,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = E0511)] SimdSecond { #[primary_span] span: Span, @@ -691,7 +691,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = E0511)] SimdThird { #[primary_span] span: Span, @@ -699,7 +699,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = E0511)] SimdReturn { #[primary_span] span: Span, @@ -707,7 +707,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = E0511)] InvalidBitmask { #[primary_span] span: Span, @@ -717,7 +717,7 @@ pub enum InvalidMonomorphization<'tcx> { expected_bytes: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = E0511)] ReturnLengthInputType { #[primary_span] span: Span, @@ -728,7 +728,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = E0511)] SecondArgumentLength { #[primary_span] span: Span, @@ -739,7 +739,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = E0511)] ThirdArgumentLength { #[primary_span] span: Span, @@ -750,7 +750,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = E0511)] ReturnIntegerType { #[primary_span] span: Span, @@ -759,7 +759,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = E0511)] SimdShuffle { #[primary_span] span: Span, @@ -767,7 +767,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_length, code = E0511)] ReturnLength { #[primary_span] span: Span, @@ -777,7 +777,7 @@ pub enum InvalidMonomorphization<'tcx> { out_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_element, code = E0511)] ReturnElement { #[primary_span] span: Span, @@ -788,7 +788,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = E0511)] ShuffleIndexNotConstant { #[primary_span] span: Span, @@ -796,7 +796,7 @@ pub enum InvalidMonomorphization<'tcx> { arg_idx: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = E0511)] ShuffleIndexOutOfBounds { #[primary_span] span: Span, @@ -805,7 +805,7 @@ pub enum InvalidMonomorphization<'tcx> { total_len: u128, }, - #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = E0511)] InsertedType { #[primary_span] span: Span, @@ -815,7 +815,7 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_return_type, code = E0511)] ReturnType { #[primary_span] span: Span, @@ -825,7 +825,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = E0511)] ExpectedReturnType { #[primary_span] span: Span, @@ -834,7 +834,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = E0511)] MismatchedLengths { #[primary_span] span: Span, @@ -843,7 +843,7 @@ pub enum InvalidMonomorphization<'tcx> { v_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)] MaskType { #[primary_span] span: Span, @@ -851,7 +851,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)] VectorArgument { #[primary_span] span: Span, @@ -860,7 +860,7 @@ pub enum InvalidMonomorphization<'tcx> { in_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)] CannotReturn { #[primary_span] span: Span, @@ -870,7 +870,7 @@ pub enum InvalidMonomorphization<'tcx> { expected_bytes: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = E0511)] ExpectedElementType { #[primary_span] span: Span, @@ -882,7 +882,7 @@ pub enum InvalidMonomorphization<'tcx> { mutability: ExpectedPointerMutability, }, - #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)] ThirdArgElementType { #[primary_span] span: Span, @@ -891,7 +891,7 @@ pub enum InvalidMonomorphization<'tcx> { third_arg: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)] UnsupportedSymbolOfSize { #[primary_span] span: Span, @@ -903,7 +903,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = E0511)] UnsupportedSymbol { #[primary_span] span: Span, @@ -914,7 +914,7 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)] CastFatPointer { #[primary_span] span: Span, @@ -922,7 +922,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = E0511)] ExpectedPointer { #[primary_span] span: Span, @@ -930,7 +930,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = E0511)] ExpectedUsize { #[primary_span] span: Span, @@ -938,7 +938,7 @@ pub enum InvalidMonomorphization<'tcx> { ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = E0511)] UnsupportedCast { #[primary_span] span: Span, @@ -949,7 +949,7 @@ pub enum InvalidMonomorphization<'tcx> { out_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = E0511)] UnsupportedOperation { #[primary_span] span: Span, @@ -958,7 +958,7 @@ pub enum InvalidMonomorphization<'tcx> { in_elem: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")] + #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = E0511)] ExpectedVectorElementType { #[primary_span] span: Span, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 064d97a49d7..9e27c19e94c 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use rustc_errors::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, - IntoDiagnostic, Level, + codes::*, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, + EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -55,14 +55,14 @@ pub(crate) struct UnstableInStable { } #[derive(Diagnostic)] -#[diag(const_eval_thread_local_access, code = "E0625")] +#[diag(const_eval_thread_local_access, code = E0625)] pub(crate) struct NonConstOpErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_static_access, code = "E0013")] +#[diag(const_eval_static_access, code = E0013)] #[help] pub(crate) struct StaticAccessErr { #[primary_span] @@ -98,7 +98,7 @@ pub(crate) struct PanicNonStrErr { } #[derive(Diagnostic)] -#[diag(const_eval_mut_deref, code = "E0658")] +#[diag(const_eval_mut_deref, code = E0658)] pub(crate) struct MutDerefErr { #[primary_span] pub span: Span, @@ -106,7 +106,7 @@ pub(crate) struct MutDerefErr { } #[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow, code = "E0658")] +#[diag(const_eval_transient_mut_borrow, code = E0658)] pub(crate) struct TransientMutBorrowErr { #[primary_span] pub span: Span, @@ -114,7 +114,7 @@ pub(crate) struct TransientMutBorrowErr { } #[derive(Diagnostic)] -#[diag(const_eval_transient_mut_raw, code = "E0658")] +#[diag(const_eval_transient_mut_raw, code = E0658)] pub(crate) struct TransientMutRawErr { #[primary_span] pub span: Span, @@ -146,7 +146,7 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_refs, code = "E0764")] +#[diag(const_eval_unallowed_mutable_refs, code = E0764)] pub(crate) struct UnallowedMutableRefs { #[primary_span] pub span: Span, @@ -156,7 +156,7 @@ pub(crate) struct UnallowedMutableRefs { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_raw, code = "E0764")] +#[diag(const_eval_unallowed_mutable_raw, code = E0764)] pub(crate) struct UnallowedMutableRaw { #[primary_span] pub span: Span, @@ -165,7 +165,7 @@ pub(crate) struct UnallowedMutableRaw { pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")] +#[diag(const_eval_non_const_fmt_macro_call, code = E0015)] pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, @@ -173,7 +173,7 @@ pub(crate) struct NonConstFmtMacroCall { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fn_call, code = "E0015")] +#[diag(const_eval_non_const_fn_call, code = E0015)] pub(crate) struct NonConstFnCall { #[primary_span] pub span: Span, @@ -190,7 +190,7 @@ pub(crate) struct UnallowedOpInConstContext { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_heap_allocations, code = "E0010")] +#[diag(const_eval_unallowed_heap_allocations, code = E0010)] pub(crate) struct UnallowedHeapAllocations { #[primary_span] #[label] @@ -201,7 +201,7 @@ pub(crate) struct UnallowedHeapAllocations { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_inline_asm, code = "E0015")] +#[diag(const_eval_unallowed_inline_asm, code = E0015)] pub(crate) struct UnallowedInlineAsm { #[primary_span] pub span: Span, @@ -209,7 +209,7 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_data_refer, code = "E0492")] +#[diag(const_eval_interior_mutable_data_refer, code = E0492)] pub(crate) struct InteriorMutableDataRefer { #[primary_span] #[label] @@ -274,7 +274,7 @@ pub struct RawBytesNote { // FIXME(fee1-dead) do not use stringly typed `ConstContext` #[derive(Diagnostic)] -#[diag(const_eval_match_eq_non_const, code = "E0015")] +#[diag(const_eval_match_eq_non_const, code = E0015)] #[note] pub struct NonConstMatchEq<'tcx> { #[primary_span] @@ -284,7 +284,7 @@ pub struct NonConstMatchEq<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")] +#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)] pub struct NonConstForLoopIntoIter<'tcx> { #[primary_span] pub span: Span, @@ -293,7 +293,7 @@ pub struct NonConstForLoopIntoIter<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_question_branch_non_const, code = "E0015")] +#[diag(const_eval_question_branch_non_const, code = E0015)] pub struct NonConstQuestionBranch<'tcx> { #[primary_span] pub span: Span, @@ -302,7 +302,7 @@ pub struct NonConstQuestionBranch<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_question_from_residual_non_const, code = "E0015")] +#[diag(const_eval_question_from_residual_non_const, code = E0015)] pub struct NonConstQuestionFromResidual<'tcx> { #[primary_span] pub span: Span, @@ -311,7 +311,7 @@ pub struct NonConstQuestionFromResidual<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_try_block_from_output_non_const, code = "E0015")] +#[diag(const_eval_try_block_from_output_non_const, code = E0015)] pub struct NonConstTryBlockFromOutput<'tcx> { #[primary_span] pub span: Span, @@ -320,7 +320,7 @@ pub struct NonConstTryBlockFromOutput<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_await_non_const, code = "E0015")] +#[diag(const_eval_await_non_const, code = E0015)] pub struct NonConstAwait<'tcx> { #[primary_span] pub span: Span, @@ -329,7 +329,7 @@ pub struct NonConstAwait<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_closure_non_const, code = "E0015")] +#[diag(const_eval_closure_non_const, code = E0015)] pub struct NonConstClosure { #[primary_span] pub span: Span, @@ -362,7 +362,7 @@ pub struct ConsiderDereferencing { } #[derive(Diagnostic)] -#[diag(const_eval_operator_non_const, code = "E0015")] +#[diag(const_eval_operator_non_const, code = E0015)] pub struct NonConstOperator { #[primary_span] pub span: Span, @@ -372,7 +372,7 @@ pub struct NonConstOperator { } #[derive(Diagnostic)] -#[diag(const_eval_deref_coercion_non_const, code = "E0015")] +#[diag(const_eval_deref_coercion_non_const, code = E0015)] #[note] pub struct NonConstDerefCoercion<'tcx> { #[primary_span] @@ -385,7 +385,7 @@ pub struct NonConstDerefCoercion<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_live_drop, code = "E0493")] +#[diag(const_eval_live_drop, code = E0493)] pub struct LiveDrop<'tcx> { #[primary_span] #[label] @@ -397,7 +397,7 @@ pub struct LiveDrop<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_error, code = "E0080")] +#[diag(const_eval_error, code = E0080)] pub struct ConstEvalError { #[primary_span] pub span: Span, @@ -423,7 +423,7 @@ pub struct NullaryIntrinsicError { } #[derive(Diagnostic)] -#[diag(const_eval_undefined_behavior, code = "E0080")] +#[diag(const_eval_undefined_behavior, code = E0080)] pub struct UndefinedBehavior { #[primary_span] pub span: Span, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 80d4bda4827..4653c9016c6 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -260,8 +260,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). let inner_val: Immediate<_> = match (**self, self.layout.abi) { - // if the entire value is uninit, then so is the field (can happen in ConstProp) + // If the entire value is uninit, then so is the field (can happen in ConstProp). (Immediate::Uninit, _) => Immediate::Uninit, + // If the field is uninhabited, we can forget the data (can happen in ConstProp). + // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that + // has an `Uninhabited` variant, which means this case is possible. + _ if layout.abi.is_uninhabited() => Immediate::Uninit, // the field contains no information, can be left uninit // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) _ if layout.is_zst() => Immediate::Uninit, diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index bd60e066f72..3a441c1d649 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -201,25 +201,8 @@ where // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) // So we just "offset" by 0. let layout = base.layout().for_variant(self, variant); - // In the future we might want to allow this to permit code like this: - // (this is a Rust/MIR pseudocode mix) - // ``` - // enum Option2 { - // Some(i32, !), - // None, - // } - // - // fn panic() -> ! { panic!() } - // - // let x: Option2; - // x.Some.0 = 42; - // x.Some.1 = panic(); - // SetDiscriminant(x, Some); - // ``` - // However, for now we don't generate such MIR, and this check here *has* found real - // bugs (see https://github.com/rust-lang/rust/issues/115145), so we will keep rejecting - // it. - assert!(!layout.abi.is_uninhabited()); + // This variant may in fact be uninhabited. + // See <https://github.com/rust-lang/rust/issues/120337>. // This cannot be `transmute` as variants *can* have a smaller size than the entire enum. base.offset(Size::ZERO, layout, self) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 39bc2b960e9..fb705d91977 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -2,7 +2,7 @@ use hir::def_id::LocalDefId; use hir::{ConstContext, LangItem}; -use rustc_errors::{error_code, DiagnosticBuilder}; +use rustc_errors::{codes::*, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -372,7 +372,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx.dcx().create_err(errors::UnallowedHeapAllocations { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + teach: ccx.tcx.sess.teach(E0010).then_some(()), }) } } @@ -434,14 +434,14 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { span, opt_help: Some(()), kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + teach: ccx.tcx.sess.teach(E0492).then_some(()), }) } else { ccx.dcx().create_err(errors::InteriorMutableDataRefer { span, opt_help: None, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + teach: ccx.tcx.sess.teach(E0492).then_some(()), }) } } @@ -469,12 +469,12 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + teach: ccx.tcx.sess.teach(E0764).then_some(()), }), hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + teach: ccx.tcx.sess.teach(E0764).then_some(()), }), } } @@ -588,7 +588,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { ccx.dcx().create_err(errors::StaticAccessErr { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()), + teach: ccx.tcx.sess.teach(E0013).then_some(()), }) } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 5564902396e..21bdb66a276 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -810,13 +810,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let adt_def = self.tcx.adt_def(def_id); assert!(adt_def.is_union()); assert_eq!(idx, FIRST_VARIANT); - let dest = adt_def.non_enum_variant().fields[field].ty(self.tcx, args); - if fields.len() != 1 { + let dest_ty = self.tcx.normalize_erasing_regions( + self.param_env, + adt_def.non_enum_variant().fields[field].ty(self.tcx, args), + ); + if fields.len() == 1 { + let src_ty = fields.raw[0].ty(self.body, self.tcx); + if !self.mir_assign_valid_types(src_ty, dest_ty) { + self.fail(location, "union field has the wrong type"); + } + } else { self.fail(location, "unions should have one initialized field"); } - if !self.mir_assign_valid_types(fields.raw[0].ty(self.body, self.tcx), dest) { - self.fail(location, "union field has the wrong type"); - } } AggregateKind::Adt(def_id, idx, args, _, None) => { let adt_def = self.tcx.adt_def(def_id); @@ -826,10 +831,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "adt has the wrong number of initialized fields"); } for (src, dest) in std::iter::zip(fields, &variant.fields) { - if !self.mir_assign_valid_types( - src.ty(self.body, self.tcx), - dest.ty(self.tcx, args), - ) { + let dest_ty = self + .tcx + .normalize_erasing_regions(self.param_env, dest.ty(self.tcx, args)); + if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest_ty) { self.fail(location, "adt field has the wrong type"); } } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 97a7dfef3b3..bfdd871455c 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -15,7 +15,6 @@ rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_error_codes = { path = "../rustc_error_codes" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 09e627fa7a3..5903c43ae98 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -23,9 +23,8 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; -use rustc_errors::registry::{InvalidErrorCode, Registry}; -use rustc_errors::{markdown, ColorConfig}; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; +use rustc_errors::registry::Registry; +use rustc_errors::{markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, PResult}; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; @@ -207,7 +206,7 @@ impl Callbacks for TimePassesCallbacks { } pub fn diagnostics_registry() -> Registry { - Registry::new(rustc_error_codes::DIAGNOSTICS) + Registry::new(rustc_errors::codes::DIAGNOSTICS) } /// This is the primary entry point for rustc. @@ -535,37 +534,36 @@ pub enum Compilation { } fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, color: ColorConfig) { + // Allow "E0123" or "0123" form. let upper_cased_code = code.to_ascii_uppercase(); - let normalised = - if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") }; - match registry.try_find_description(&normalised) { - Ok(description) => { - let mut is_in_code_block = false; - let mut text = String::new(); - // Slice off the leading newline and print. - for line in description.lines() { - let indent_level = - line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len()); - let dedented_line = &line[indent_level..]; - if dedented_line.starts_with("```") { - is_in_code_block = !is_in_code_block; - text.push_str(&line[..(indent_level + 3)]); - } else if is_in_code_block && dedented_line.starts_with("# ") { - continue; - } else { - text.push_str(line); - } - text.push('\n'); - } - if io::stdout().is_terminal() { - show_md_content_with_pager(&text, color); + let start = if upper_cased_code.starts_with('E') { 1 } else { 0 }; + if let Ok(code) = upper_cased_code[start..].parse::<u32>() + && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code)) + { + let mut is_in_code_block = false; + let mut text = String::new(); + // Slice off the leading newline and print. + for line in description.lines() { + let indent_level = + line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len()); + let dedented_line = &line[indent_level..]; + if dedented_line.starts_with("```") { + is_in_code_block = !is_in_code_block; + text.push_str(&line[..(indent_level + 3)]); + } else if is_in_code_block && dedented_line.starts_with("# ") { + continue; } else { - safe_print!("{text}"); + text.push_str(line); } + text.push('\n'); } - Err(InvalidErrorCode) => { - early_dcx.early_fatal(format!("{code} is not a valid error code")); + if io::stdout().is_terminal() { + show_md_content_with_pager(&text, color); + } else { + safe_print!("{text}"); } + } else { + early_dcx.early_fatal(format!("{code} is not a valid error code")); } } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs deleted file mode 100644 index 9cd9ed54d41..00000000000 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ /dev/null @@ -1,658 +0,0 @@ -// Error messages for EXXXX errors. Each message should start and end with a -// new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and -// use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -// -// /!\ IMPORTANT /!\ -// -// Error messages' format must follow the RFC 1567 available here: -// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html - -register_diagnostics! { -E0001: include_str!("./error_codes/E0001.md"), -E0002: include_str!("./error_codes/E0002.md"), -E0004: include_str!("./error_codes/E0004.md"), -E0005: include_str!("./error_codes/E0005.md"), -E0007: include_str!("./error_codes/E0007.md"), -E0009: include_str!("./error_codes/E0009.md"), -E0010: include_str!("./error_codes/E0010.md"), -E0013: include_str!("./error_codes/E0013.md"), -E0014: include_str!("./error_codes/E0014.md"), -E0015: include_str!("./error_codes/E0015.md"), -E0023: include_str!("./error_codes/E0023.md"), -E0025: include_str!("./error_codes/E0025.md"), -E0026: include_str!("./error_codes/E0026.md"), -E0027: include_str!("./error_codes/E0027.md"), -E0029: include_str!("./error_codes/E0029.md"), -E0030: include_str!("./error_codes/E0030.md"), -E0033: include_str!("./error_codes/E0033.md"), -E0034: include_str!("./error_codes/E0034.md"), -E0038: include_str!("./error_codes/E0038.md"), -E0040: include_str!("./error_codes/E0040.md"), -E0044: include_str!("./error_codes/E0044.md"), -E0045: include_str!("./error_codes/E0045.md"), -E0046: include_str!("./error_codes/E0046.md"), -E0049: include_str!("./error_codes/E0049.md"), -E0050: include_str!("./error_codes/E0050.md"), -E0053: include_str!("./error_codes/E0053.md"), -E0054: include_str!("./error_codes/E0054.md"), -E0055: include_str!("./error_codes/E0055.md"), -E0057: include_str!("./error_codes/E0057.md"), -E0059: include_str!("./error_codes/E0059.md"), -E0060: include_str!("./error_codes/E0060.md"), -E0061: include_str!("./error_codes/E0061.md"), -E0062: include_str!("./error_codes/E0062.md"), -E0063: include_str!("./error_codes/E0063.md"), -E0067: include_str!("./error_codes/E0067.md"), -E0069: include_str!("./error_codes/E0069.md"), -E0070: include_str!("./error_codes/E0070.md"), -E0071: include_str!("./error_codes/E0071.md"), -E0072: include_str!("./error_codes/E0072.md"), -E0073: include_str!("./error_codes/E0073.md"), -E0074: include_str!("./error_codes/E0074.md"), -E0075: include_str!("./error_codes/E0075.md"), -E0076: include_str!("./error_codes/E0076.md"), -E0077: include_str!("./error_codes/E0077.md"), -E0080: include_str!("./error_codes/E0080.md"), -E0081: include_str!("./error_codes/E0081.md"), -E0084: include_str!("./error_codes/E0084.md"), -E0087: include_str!("./error_codes/E0087.md"), -E0088: include_str!("./error_codes/E0088.md"), -E0089: include_str!("./error_codes/E0089.md"), -E0090: include_str!("./error_codes/E0090.md"), -E0091: include_str!("./error_codes/E0091.md"), -E0092: include_str!("./error_codes/E0092.md"), -E0093: include_str!("./error_codes/E0093.md"), -E0094: include_str!("./error_codes/E0094.md"), -E0106: include_str!("./error_codes/E0106.md"), -E0107: include_str!("./error_codes/E0107.md"), -E0109: include_str!("./error_codes/E0109.md"), -E0110: include_str!("./error_codes/E0110.md"), -E0116: include_str!("./error_codes/E0116.md"), -E0117: include_str!("./error_codes/E0117.md"), -E0118: include_str!("./error_codes/E0118.md"), -E0119: include_str!("./error_codes/E0119.md"), -E0120: include_str!("./error_codes/E0120.md"), -E0121: include_str!("./error_codes/E0121.md"), -E0124: include_str!("./error_codes/E0124.md"), -E0128: include_str!("./error_codes/E0128.md"), -E0130: include_str!("./error_codes/E0130.md"), -E0131: include_str!("./error_codes/E0131.md"), -E0132: include_str!("./error_codes/E0132.md"), -E0133: include_str!("./error_codes/E0133.md"), -E0136: include_str!("./error_codes/E0136.md"), -E0137: include_str!("./error_codes/E0137.md"), -E0138: include_str!("./error_codes/E0138.md"), -E0139: include_str!("./error_codes/E0139.md"), -E0152: include_str!("./error_codes/E0152.md"), -E0154: include_str!("./error_codes/E0154.md"), -E0158: include_str!("./error_codes/E0158.md"), -E0161: include_str!("./error_codes/E0161.md"), -E0162: include_str!("./error_codes/E0162.md"), -E0164: include_str!("./error_codes/E0164.md"), -E0165: include_str!("./error_codes/E0165.md"), -E0170: include_str!("./error_codes/E0170.md"), -E0178: include_str!("./error_codes/E0178.md"), -E0183: include_str!("./error_codes/E0183.md"), -E0184: include_str!("./error_codes/E0184.md"), -E0185: include_str!("./error_codes/E0185.md"), -E0186: include_str!("./error_codes/E0186.md"), -E0191: include_str!("./error_codes/E0191.md"), -E0192: include_str!("./error_codes/E0192.md"), -E0193: include_str!("./error_codes/E0193.md"), -E0195: include_str!("./error_codes/E0195.md"), -E0197: include_str!("./error_codes/E0197.md"), -E0198: include_str!("./error_codes/E0198.md"), -E0199: include_str!("./error_codes/E0199.md"), -E0200: include_str!("./error_codes/E0200.md"), -E0201: include_str!("./error_codes/E0201.md"), -E0203: include_str!("./error_codes/E0203.md"), -E0204: include_str!("./error_codes/E0204.md"), -E0205: include_str!("./error_codes/E0205.md"), -E0206: include_str!("./error_codes/E0206.md"), -E0207: include_str!("./error_codes/E0207.md"), -E0208: include_str!("./error_codes/E0208.md"), -E0210: include_str!("./error_codes/E0210.md"), -E0211: include_str!("./error_codes/E0211.md"), -E0212: include_str!("./error_codes/E0212.md"), -E0214: include_str!("./error_codes/E0214.md"), -E0220: include_str!("./error_codes/E0220.md"), -E0221: include_str!("./error_codes/E0221.md"), -E0222: include_str!("./error_codes/E0222.md"), -E0223: include_str!("./error_codes/E0223.md"), -E0224: include_str!("./error_codes/E0224.md"), -E0225: include_str!("./error_codes/E0225.md"), -E0226: include_str!("./error_codes/E0226.md"), -E0227: include_str!("./error_codes/E0227.md"), -E0228: include_str!("./error_codes/E0228.md"), -E0229: include_str!("./error_codes/E0229.md"), -E0230: include_str!("./error_codes/E0230.md"), -E0231: include_str!("./error_codes/E0231.md"), -E0232: include_str!("./error_codes/E0232.md"), -E0243: include_str!("./error_codes/E0243.md"), -E0244: include_str!("./error_codes/E0244.md"), -E0251: include_str!("./error_codes/E0251.md"), -E0252: include_str!("./error_codes/E0252.md"), -E0253: include_str!("./error_codes/E0253.md"), -E0254: include_str!("./error_codes/E0254.md"), -E0255: include_str!("./error_codes/E0255.md"), -E0256: include_str!("./error_codes/E0256.md"), -E0259: include_str!("./error_codes/E0259.md"), -E0260: include_str!("./error_codes/E0260.md"), -E0261: include_str!("./error_codes/E0261.md"), -E0262: include_str!("./error_codes/E0262.md"), -E0263: include_str!("./error_codes/E0263.md"), -E0264: include_str!("./error_codes/E0264.md"), -E0267: include_str!("./error_codes/E0267.md"), -E0268: include_str!("./error_codes/E0268.md"), -E0271: include_str!("./error_codes/E0271.md"), -E0275: include_str!("./error_codes/E0275.md"), -E0276: include_str!("./error_codes/E0276.md"), -E0277: include_str!("./error_codes/E0277.md"), -E0281: include_str!("./error_codes/E0281.md"), -E0282: include_str!("./error_codes/E0282.md"), -E0283: include_str!("./error_codes/E0283.md"), -E0284: include_str!("./error_codes/E0284.md"), -E0297: include_str!("./error_codes/E0297.md"), -E0301: include_str!("./error_codes/E0301.md"), -E0302: include_str!("./error_codes/E0302.md"), -E0303: include_str!("./error_codes/E0303.md"), -E0307: include_str!("./error_codes/E0307.md"), -E0308: include_str!("./error_codes/E0308.md"), -E0309: include_str!("./error_codes/E0309.md"), -E0310: include_str!("./error_codes/E0310.md"), -E0311: include_str!("./error_codes/E0311.md"), -E0312: include_str!("./error_codes/E0312.md"), -E0316: include_str!("./error_codes/E0316.md"), -E0317: include_str!("./error_codes/E0317.md"), -E0320: include_str!("./error_codes/E0320.md"), -E0321: include_str!("./error_codes/E0321.md"), -E0322: include_str!("./error_codes/E0322.md"), -E0323: include_str!("./error_codes/E0323.md"), -E0324: include_str!("./error_codes/E0324.md"), -E0325: include_str!("./error_codes/E0325.md"), -E0326: include_str!("./error_codes/E0326.md"), -E0328: include_str!("./error_codes/E0328.md"), -E0329: include_str!("./error_codes/E0329.md"), -E0364: include_str!("./error_codes/E0364.md"), -E0365: include_str!("./error_codes/E0365.md"), -E0366: include_str!("./error_codes/E0366.md"), -E0367: include_str!("./error_codes/E0367.md"), -E0368: include_str!("./error_codes/E0368.md"), -E0369: include_str!("./error_codes/E0369.md"), -E0370: include_str!("./error_codes/E0370.md"), -E0371: include_str!("./error_codes/E0371.md"), -E0373: include_str!("./error_codes/E0373.md"), -E0374: include_str!("./error_codes/E0374.md"), -E0375: include_str!("./error_codes/E0375.md"), -E0376: include_str!("./error_codes/E0376.md"), -E0377: include_str!("./error_codes/E0377.md"), -E0378: include_str!("./error_codes/E0378.md"), -E0379: include_str!("./error_codes/E0379.md"), -E0380: include_str!("./error_codes/E0380.md"), -E0381: include_str!("./error_codes/E0381.md"), -E0382: include_str!("./error_codes/E0382.md"), -E0383: include_str!("./error_codes/E0383.md"), -E0384: include_str!("./error_codes/E0384.md"), -E0386: include_str!("./error_codes/E0386.md"), -E0387: include_str!("./error_codes/E0387.md"), -E0388: include_str!("./error_codes/E0388.md"), -E0389: include_str!("./error_codes/E0389.md"), -E0390: include_str!("./error_codes/E0390.md"), -E0391: include_str!("./error_codes/E0391.md"), -E0392: include_str!("./error_codes/E0392.md"), -E0393: include_str!("./error_codes/E0393.md"), -E0398: include_str!("./error_codes/E0398.md"), -E0399: include_str!("./error_codes/E0399.md"), -E0401: include_str!("./error_codes/E0401.md"), -E0403: include_str!("./error_codes/E0403.md"), -E0404: include_str!("./error_codes/E0404.md"), -E0405: include_str!("./error_codes/E0405.md"), -E0407: include_str!("./error_codes/E0407.md"), -E0408: include_str!("./error_codes/E0408.md"), -E0409: include_str!("./error_codes/E0409.md"), -E0411: include_str!("./error_codes/E0411.md"), -E0412: include_str!("./error_codes/E0412.md"), -E0415: include_str!("./error_codes/E0415.md"), -E0416: include_str!("./error_codes/E0416.md"), -E0422: include_str!("./error_codes/E0422.md"), -E0423: include_str!("./error_codes/E0423.md"), -E0424: include_str!("./error_codes/E0424.md"), -E0425: include_str!("./error_codes/E0425.md"), -E0426: include_str!("./error_codes/E0426.md"), -E0428: include_str!("./error_codes/E0428.md"), -E0429: include_str!("./error_codes/E0429.md"), -E0430: include_str!("./error_codes/E0430.md"), -E0431: include_str!("./error_codes/E0431.md"), -E0432: include_str!("./error_codes/E0432.md"), -E0433: include_str!("./error_codes/E0433.md"), -E0434: include_str!("./error_codes/E0434.md"), -E0435: include_str!("./error_codes/E0435.md"), -E0436: include_str!("./error_codes/E0436.md"), -E0437: include_str!("./error_codes/E0437.md"), -E0438: include_str!("./error_codes/E0438.md"), -E0439: include_str!("./error_codes/E0439.md"), -E0445: include_str!("./error_codes/E0445.md"), -E0446: include_str!("./error_codes/E0446.md"), -E0447: include_str!("./error_codes/E0447.md"), -E0448: include_str!("./error_codes/E0448.md"), -E0449: include_str!("./error_codes/E0449.md"), -E0451: include_str!("./error_codes/E0451.md"), -E0452: include_str!("./error_codes/E0452.md"), -E0453: include_str!("./error_codes/E0453.md"), -E0454: include_str!("./error_codes/E0454.md"), -E0455: include_str!("./error_codes/E0455.md"), -E0457: include_str!("./error_codes/E0457.md"), -E0458: include_str!("./error_codes/E0458.md"), -E0459: include_str!("./error_codes/E0459.md"), -E0460: include_str!("./error_codes/E0460.md"), -E0461: include_str!("./error_codes/E0461.md"), -E0462: include_str!("./error_codes/E0462.md"), -E0463: include_str!("./error_codes/E0463.md"), -E0464: include_str!("./error_codes/E0464.md"), -E0466: include_str!("./error_codes/E0466.md"), -E0468: include_str!("./error_codes/E0468.md"), -E0469: include_str!("./error_codes/E0469.md"), -E0472: include_str!("./error_codes/E0472.md"), -E0476: include_str!("./error_codes/E0476.md"), -E0477: include_str!("./error_codes/E0477.md"), -E0478: include_str!("./error_codes/E0478.md"), -E0482: include_str!("./error_codes/E0482.md"), -E0491: include_str!("./error_codes/E0491.md"), -E0492: include_str!("./error_codes/E0492.md"), -E0493: include_str!("./error_codes/E0493.md"), -E0495: include_str!("./error_codes/E0495.md"), -E0496: include_str!("./error_codes/E0496.md"), -E0497: include_str!("./error_codes/E0497.md"), -E0498: include_str!("./error_codes/E0498.md"), -E0499: include_str!("./error_codes/E0499.md"), -E0500: include_str!("./error_codes/E0500.md"), -E0501: include_str!("./error_codes/E0501.md"), -E0502: include_str!("./error_codes/E0502.md"), -E0503: include_str!("./error_codes/E0503.md"), -E0504: include_str!("./error_codes/E0504.md"), -E0505: include_str!("./error_codes/E0505.md"), -E0506: include_str!("./error_codes/E0506.md"), -E0507: include_str!("./error_codes/E0507.md"), -E0508: include_str!("./error_codes/E0508.md"), -E0509: include_str!("./error_codes/E0509.md"), -E0510: include_str!("./error_codes/E0510.md"), -E0511: include_str!("./error_codes/E0511.md"), -E0512: include_str!("./error_codes/E0512.md"), -E0514: include_str!("./error_codes/E0514.md"), -E0515: include_str!("./error_codes/E0515.md"), -E0516: include_str!("./error_codes/E0516.md"), -E0517: include_str!("./error_codes/E0517.md"), -E0518: include_str!("./error_codes/E0518.md"), -E0519: include_str!("./error_codes/E0519.md"), -E0520: include_str!("./error_codes/E0520.md"), -E0521: include_str!("./error_codes/E0521.md"), -E0522: include_str!("./error_codes/E0522.md"), -E0523: include_str!("./error_codes/E0523.md"), -E0524: include_str!("./error_codes/E0524.md"), -E0525: include_str!("./error_codes/E0525.md"), -E0527: include_str!("./error_codes/E0527.md"), -E0528: include_str!("./error_codes/E0528.md"), -E0529: include_str!("./error_codes/E0529.md"), -E0530: include_str!("./error_codes/E0530.md"), -E0531: include_str!("./error_codes/E0531.md"), -E0532: include_str!("./error_codes/E0532.md"), -E0533: include_str!("./error_codes/E0533.md"), -E0534: include_str!("./error_codes/E0534.md"), -E0535: include_str!("./error_codes/E0535.md"), -E0536: include_str!("./error_codes/E0536.md"), -E0537: include_str!("./error_codes/E0537.md"), -E0538: include_str!("./error_codes/E0538.md"), -E0539: include_str!("./error_codes/E0539.md"), -E0541: include_str!("./error_codes/E0541.md"), -E0542: include_str!("./error_codes/E0542.md"), -E0543: include_str!("./error_codes/E0543.md"), -E0544: include_str!("./error_codes/E0544.md"), -E0545: include_str!("./error_codes/E0545.md"), -E0546: include_str!("./error_codes/E0546.md"), -E0547: include_str!("./error_codes/E0547.md"), -E0549: include_str!("./error_codes/E0549.md"), -E0550: include_str!("./error_codes/E0550.md"), -E0551: include_str!("./error_codes/E0551.md"), -E0552: include_str!("./error_codes/E0552.md"), -E0554: include_str!("./error_codes/E0554.md"), -E0556: include_str!("./error_codes/E0556.md"), -E0557: include_str!("./error_codes/E0557.md"), -E0559: include_str!("./error_codes/E0559.md"), -E0560: include_str!("./error_codes/E0560.md"), -E0561: include_str!("./error_codes/E0561.md"), -E0562: include_str!("./error_codes/E0562.md"), -E0565: include_str!("./error_codes/E0565.md"), -E0566: include_str!("./error_codes/E0566.md"), -E0567: include_str!("./error_codes/E0567.md"), -E0568: include_str!("./error_codes/E0568.md"), -E0569: include_str!("./error_codes/E0569.md"), -E0570: include_str!("./error_codes/E0570.md"), -E0571: include_str!("./error_codes/E0571.md"), -E0572: include_str!("./error_codes/E0572.md"), -E0573: include_str!("./error_codes/E0573.md"), -E0574: include_str!("./error_codes/E0574.md"), -E0575: include_str!("./error_codes/E0575.md"), -E0576: include_str!("./error_codes/E0576.md"), -E0577: include_str!("./error_codes/E0577.md"), -E0578: include_str!("./error_codes/E0578.md"), -E0579: include_str!("./error_codes/E0579.md"), -E0580: include_str!("./error_codes/E0580.md"), -E0581: include_str!("./error_codes/E0581.md"), -E0582: include_str!("./error_codes/E0582.md"), -E0583: include_str!("./error_codes/E0583.md"), -E0584: include_str!("./error_codes/E0584.md"), -E0585: include_str!("./error_codes/E0585.md"), -E0586: include_str!("./error_codes/E0586.md"), -E0587: include_str!("./error_codes/E0587.md"), -E0588: include_str!("./error_codes/E0588.md"), -E0589: include_str!("./error_codes/E0589.md"), -E0590: include_str!("./error_codes/E0590.md"), -E0591: include_str!("./error_codes/E0591.md"), -E0592: include_str!("./error_codes/E0592.md"), -E0593: include_str!("./error_codes/E0593.md"), -E0594: include_str!("./error_codes/E0594.md"), -E0595: include_str!("./error_codes/E0595.md"), -E0596: include_str!("./error_codes/E0596.md"), -E0597: include_str!("./error_codes/E0597.md"), -E0599: include_str!("./error_codes/E0599.md"), -E0600: include_str!("./error_codes/E0600.md"), -E0601: include_str!("./error_codes/E0601.md"), -E0602: include_str!("./error_codes/E0602.md"), -E0603: include_str!("./error_codes/E0603.md"), -E0604: include_str!("./error_codes/E0604.md"), -E0605: include_str!("./error_codes/E0605.md"), -E0606: include_str!("./error_codes/E0606.md"), -E0607: include_str!("./error_codes/E0607.md"), -E0608: include_str!("./error_codes/E0608.md"), -E0609: include_str!("./error_codes/E0609.md"), -E0610: include_str!("./error_codes/E0610.md"), -E0614: include_str!("./error_codes/E0614.md"), -E0615: include_str!("./error_codes/E0615.md"), -E0616: include_str!("./error_codes/E0616.md"), -E0617: include_str!("./error_codes/E0617.md"), -E0618: include_str!("./error_codes/E0618.md"), -E0619: include_str!("./error_codes/E0619.md"), -E0620: include_str!("./error_codes/E0620.md"), -E0621: include_str!("./error_codes/E0621.md"), -E0622: include_str!("./error_codes/E0622.md"), -E0623: include_str!("./error_codes/E0623.md"), -E0624: include_str!("./error_codes/E0624.md"), -E0625: include_str!("./error_codes/E0625.md"), -E0626: include_str!("./error_codes/E0626.md"), -E0627: include_str!("./error_codes/E0627.md"), -E0628: include_str!("./error_codes/E0628.md"), -E0631: include_str!("./error_codes/E0631.md"), -E0632: include_str!("./error_codes/E0632.md"), -E0633: include_str!("./error_codes/E0633.md"), -E0634: include_str!("./error_codes/E0634.md"), -E0635: include_str!("./error_codes/E0635.md"), -E0636: include_str!("./error_codes/E0636.md"), -E0637: include_str!("./error_codes/E0637.md"), -E0638: include_str!("./error_codes/E0638.md"), -E0639: include_str!("./error_codes/E0639.md"), -E0640: include_str!("./error_codes/E0640.md"), -E0641: include_str!("./error_codes/E0641.md"), -E0642: include_str!("./error_codes/E0642.md"), -E0643: include_str!("./error_codes/E0643.md"), -E0644: include_str!("./error_codes/E0644.md"), -E0646: include_str!("./error_codes/E0646.md"), -E0647: include_str!("./error_codes/E0647.md"), -E0648: include_str!("./error_codes/E0648.md"), -E0657: include_str!("./error_codes/E0657.md"), -E0658: include_str!("./error_codes/E0658.md"), -E0659: include_str!("./error_codes/E0659.md"), -E0660: include_str!("./error_codes/E0660.md"), -E0661: include_str!("./error_codes/E0661.md"), -E0662: include_str!("./error_codes/E0662.md"), -E0663: include_str!("./error_codes/E0663.md"), -E0664: include_str!("./error_codes/E0664.md"), -E0665: include_str!("./error_codes/E0665.md"), -E0666: include_str!("./error_codes/E0666.md"), -E0667: include_str!("./error_codes/E0667.md"), -E0668: include_str!("./error_codes/E0668.md"), -E0669: include_str!("./error_codes/E0669.md"), -E0670: include_str!("./error_codes/E0670.md"), -E0671: include_str!("./error_codes/E0671.md"), -E0687: include_str!("./error_codes/E0687.md"), -E0688: include_str!("./error_codes/E0688.md"), -E0689: include_str!("./error_codes/E0689.md"), -E0690: include_str!("./error_codes/E0690.md"), -E0691: include_str!("./error_codes/E0691.md"), -E0692: include_str!("./error_codes/E0692.md"), -E0693: include_str!("./error_codes/E0693.md"), -E0695: include_str!("./error_codes/E0695.md"), -E0696: include_str!("./error_codes/E0696.md"), -E0697: include_str!("./error_codes/E0697.md"), -E0698: include_str!("./error_codes/E0698.md"), -E0699: include_str!("./error_codes/E0699.md"), -E0700: include_str!("./error_codes/E0700.md"), -E0701: include_str!("./error_codes/E0701.md"), -E0703: include_str!("./error_codes/E0703.md"), -E0704: include_str!("./error_codes/E0704.md"), -E0705: include_str!("./error_codes/E0705.md"), -E0706: include_str!("./error_codes/E0706.md"), -E0708: include_str!("./error_codes/E0708.md"), -E0710: include_str!("./error_codes/E0710.md"), -E0712: include_str!("./error_codes/E0712.md"), -E0713: include_str!("./error_codes/E0713.md"), -E0714: include_str!("./error_codes/E0714.md"), -E0715: include_str!("./error_codes/E0715.md"), -E0716: include_str!("./error_codes/E0716.md"), -E0711: include_str!("./error_codes/E0711.md"), -E0717: include_str!("./error_codes/E0717.md"), -E0718: include_str!("./error_codes/E0718.md"), -E0719: include_str!("./error_codes/E0719.md"), -E0720: include_str!("./error_codes/E0720.md"), -E0722: include_str!("./error_codes/E0722.md"), -E0724: include_str!("./error_codes/E0724.md"), -E0725: include_str!("./error_codes/E0725.md"), -E0726: include_str!("./error_codes/E0726.md"), -E0727: include_str!("./error_codes/E0727.md"), -E0728: include_str!("./error_codes/E0728.md"), -E0729: include_str!("./error_codes/E0729.md"), -E0730: include_str!("./error_codes/E0730.md"), -E0731: include_str!("./error_codes/E0731.md"), -E0732: include_str!("./error_codes/E0732.md"), -E0733: include_str!("./error_codes/E0733.md"), -E0734: include_str!("./error_codes/E0734.md"), -E0735: include_str!("./error_codes/E0735.md"), -E0736: include_str!("./error_codes/E0736.md"), -E0737: include_str!("./error_codes/E0737.md"), -E0739: include_str!("./error_codes/E0739.md"), -E0740: include_str!("./error_codes/E0740.md"), -E0741: include_str!("./error_codes/E0741.md"), -E0742: include_str!("./error_codes/E0742.md"), -E0743: include_str!("./error_codes/E0743.md"), -E0744: include_str!("./error_codes/E0744.md"), -E0745: include_str!("./error_codes/E0745.md"), -E0746: include_str!("./error_codes/E0746.md"), -E0747: include_str!("./error_codes/E0747.md"), -E0748: include_str!("./error_codes/E0748.md"), -E0749: include_str!("./error_codes/E0749.md"), -E0750: include_str!("./error_codes/E0750.md"), -E0751: include_str!("./error_codes/E0751.md"), -E0752: include_str!("./error_codes/E0752.md"), -E0753: include_str!("./error_codes/E0753.md"), -E0754: include_str!("./error_codes/E0754.md"), -E0755: include_str!("./error_codes/E0755.md"), -E0756: include_str!("./error_codes/E0756.md"), -E0757: include_str!("./error_codes/E0757.md"), -E0758: include_str!("./error_codes/E0758.md"), -E0759: include_str!("./error_codes/E0759.md"), -E0760: include_str!("./error_codes/E0760.md"), -E0761: include_str!("./error_codes/E0761.md"), -E0762: include_str!("./error_codes/E0762.md"), -E0763: include_str!("./error_codes/E0763.md"), -E0764: include_str!("./error_codes/E0764.md"), -E0765: include_str!("./error_codes/E0765.md"), -E0766: include_str!("./error_codes/E0766.md"), -E0767: include_str!("./error_codes/E0767.md"), -E0768: include_str!("./error_codes/E0768.md"), -E0769: include_str!("./error_codes/E0769.md"), -E0770: include_str!("./error_codes/E0770.md"), -E0771: include_str!("./error_codes/E0771.md"), -E0772: include_str!("./error_codes/E0772.md"), -E0773: include_str!("./error_codes/E0773.md"), -E0774: include_str!("./error_codes/E0774.md"), -E0775: include_str!("./error_codes/E0775.md"), -E0776: include_str!("./error_codes/E0776.md"), -E0777: include_str!("./error_codes/E0777.md"), -E0778: include_str!("./error_codes/E0778.md"), -E0779: include_str!("./error_codes/E0779.md"), -E0780: include_str!("./error_codes/E0780.md"), -E0781: include_str!("./error_codes/E0781.md"), -E0782: include_str!("./error_codes/E0782.md"), -E0783: include_str!("./error_codes/E0783.md"), -E0784: include_str!("./error_codes/E0784.md"), -E0785: include_str!("./error_codes/E0785.md"), -E0786: include_str!("./error_codes/E0786.md"), -E0787: include_str!("./error_codes/E0787.md"), -E0788: include_str!("./error_codes/E0788.md"), -E0789: include_str!("./error_codes/E0789.md"), -E0790: include_str!("./error_codes/E0790.md"), -E0791: include_str!("./error_codes/E0791.md"), -E0792: include_str!("./error_codes/E0792.md"), -E0793: include_str!("./error_codes/E0793.md"), -E0794: include_str!("./error_codes/E0794.md"), -E0795: include_str!("./error_codes/E0795.md"), -E0796: include_str!("./error_codes/E0796.md"), -E0797: include_str!("./error_codes/E0797.md"), -} - -// Undocumented removed error codes. Note that many removed error codes are kept in the list above -// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). -// E0006, // merged with E0005 -// E0008, // cannot bind by-move into a pattern guard -// E0019, // merged into E0015 -// E0035, // merged into E0087/E0089 -// E0036, // merged into E0087/E0089 -// E0068, -// E0085, -// E0086, -// E0101, // replaced with E0282 -// E0102, // replaced with E0282 -// E0103, -// E0104, -// E0122, // bounds in type aliases are ignored, turned into proper lint -// E0123, -// E0127, -// E0129, -// E0134, -// E0135, -// E0141, -// E0153, // unused error code -// E0157, // unused error code -// E0159, // use of trait `{}` as struct constructor -// E0163, // merged into E0071 -// E0167, -// E0168, -// E0172, // non-trait found in a type sum, moved to resolve -// E0173, // manual implementations of unboxed closure traits are experimental -// E0174, -// E0182, // merged into E0229 -// E0187, // cannot infer the kind of the closure -// E0188, // can not cast an immutable reference to a mutable pointer -// E0189, // deprecated: can only cast a boxed pointer to a boxed object -// E0190, // deprecated: can only cast a &-pointer to an &-object -// E0194, // merged into E0403 -// E0196, // cannot determine a type for this closure -// E0209, // builtin traits can only be implemented on structs or enums -// E0213, // associated types are not accepted in this context -// E0215, // angle-bracket notation is not stable with `Fn` -// E0216, // parenthetical notation is only stable with `Fn` -// E0217, // ambiguous associated type, defined in multiple supertraits -// E0218, // no associated type defined -// E0219, // associated type defined in higher-ranked supertrait -// E0233, -// E0234, -// E0235, // structure constructor specifies a structure of type but -// E0236, // no lang item for range syntax -// E0237, // no lang item for range syntax -// E0238, // parenthesized parameters may only be used with a trait -// E0239, // `next` method of `Iterator` trait has unexpected type -// E0240, -// E0241, -// E0242, -// E0245, // not a trait -// E0246, // invalid recursive type -// E0247, -// E0248, // value used as a type, now reported earlier during resolution -// // as E0412 -// E0249, -// E0257, -// E0258, -// E0272, // on_unimplemented #0 -// E0273, // on_unimplemented #1 -// E0274, // on_unimplemented #2 -// E0278, // requirement is not satisfied -// E0279, -// E0280, // changed to ICE -// E0285, // overflow evaluation builtin bounds -// E0296, // replaced with a generic attribute input check -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0300, // unexpanded macro -// E0304, // expected signed integer constant -// E0305, // expected constant -// E0313, // removed: found unreachable -// E0314, // closure outlives stack frame -// E0315, // cannot invoke closure outside of its lifetime -// E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe -// E0385, // {} in an aliasable location -// E0402, // cannot use an outer type parameter in this context -// E0406, // merged into 420 -// E0410, // merged into 408 -// E0413, // merged into 530 -// E0414, // merged into 530 -// E0417, // merged into 532 -// E0418, // merged into 532 -// E0419, // merged into 531 -// E0420, // merged into 532 -// E0421, // merged into 531 -// E0427, // merged into 530 -// E0445, // merged into 446 and type privacy lints -// E0456, // plugin `..` is not available for triple `..` -// E0465, // removed: merged with E0464 -// E0467, // removed -// E0470, // removed -// E0471, // constant evaluation error (in pattern) -// E0473, // dereference of reference outside its lifetime -// E0474, // captured variable `..` does not outlive the enclosing closure -// E0475, // index of slice outside its lifetime -// E0479, // the type `..` (provided as the value of a type parameter) is... -// E0480, // lifetime of method receiver does not outlive the method call -// E0481, // lifetime of function argument does not outlive the function call -// E0483, // lifetime of operand does not outlive the operation -// E0484, // reference is not valid at the time of borrow -// E0485, // automatically reference is not valid at the time of borrow -// E0486, // type of expression contains references that are not valid during.. -// E0487, // unsafe use of destructor: destructor might be called while... -// E0488, // lifetime of variable does not enclose its declaration -// E0489, // type/lifetime parameter not in scope here -// E0490, // removed: unreachable -// E0526, // shuffle indices are not constant -// E0540, // multiple rustc_deprecated attributes -// E0548, // replaced with a generic attribute input check -// E0553, // multiple rustc_const_unstable attributes -// E0555, // replaced with a generic attribute input check -// E0558, // replaced with a generic attribute input check -// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 -// E0564, // only named lifetimes are allowed in `impl Trait`, -// // but `{}` was found in the type `{}` -// E0598, // lifetime of {} is too short to guarantee its contents can be... -// E0611, // merged into E0616 -// E0612, // merged into E0609 -// E0613, // Removed (merged with E0609) -// E0629, // missing 'feature' (rustc_const_unstable) -// E0630, // rustc_const_unstable attribute must be paired with stable/unstable -// // attribute -// E0645, // trait aliases not finished -// E0694, // an unknown tool name found in scoped attributes -// E0702, // replaced with a generic attribute input check -// E0707, // multiple elided lifetimes used in arguments of `async fn` -// E0709, // multiple different lifetimes used in arguments of `async fn` -// E0721, // `await` keyword -// E0723, // unstable feature in `const` context -// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. -// E0744, // merged into E0728 diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index dd281811636..5b2766618fc 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,19 +1,679 @@ +//! This library is used to gather all error codes into one place, to make +//! their maintenance easier. + #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] #![deny(rustdoc::invalid_codeblock_attributes)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -//! This library is used to gather all error codes into one place, -//! the goal being to make their maintenance easier. -macro_rules! register_diagnostics { - ($($ecode:ident: $message:expr,)*) => ( - pub static DIAGNOSTICS: &[(&str, &str)] = &[ - $( (stringify!($ecode), $message), )* - ]; +// This higher-order macro defines the error codes that are in use. It is used +// in the `rustc_errors` crate. Removed error codes are listed in the comment +// below. +// +// /!\ IMPORTANT /!\ +// +// Error code explanation are defined in `error_codes/EXXXX.md` files. They must follow the RFC +// 1567 available here: +// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html +// +// Also, the contents of this macro is checked by tidy (in `check_error_codes_docs`). If you change +// the macro syntax you will need to change tidy as well. +// +// Both columns are necessary because it's not possible in Rust to create a new identifier such as +// `E0123` from an integer literal such as `0123`, unfortunately. +#[macro_export] +macro_rules! error_codes { + ($macro:path) => ( + $macro!( +E0001: 0001, +E0002: 0002, +E0004: 0004, +E0005: 0005, +E0007: 0007, +E0009: 0009, +E0010: 0010, +E0013: 0013, +E0014: 0014, +E0015: 0015, +E0023: 0023, +E0025: 0025, +E0026: 0026, +E0027: 0027, +E0029: 0029, +E0030: 0030, +E0033: 0033, +E0034: 0034, +E0038: 0038, +E0040: 0040, +E0044: 0044, +E0045: 0045, +E0046: 0046, +E0049: 0049, +E0050: 0050, +E0053: 0053, +E0054: 0054, +E0055: 0055, +E0057: 0057, +E0059: 0059, +E0060: 0060, +E0061: 0061, +E0062: 0062, +E0063: 0063, +E0067: 0067, +E0069: 0069, +E0070: 0070, +E0071: 0071, +E0072: 0072, +E0073: 0073, +E0074: 0074, +E0075: 0075, +E0076: 0076, +E0077: 0077, +E0080: 0080, +E0081: 0081, +E0084: 0084, +E0087: 0087, +E0088: 0088, +E0089: 0089, +E0090: 0090, +E0091: 0091, +E0092: 0092, +E0093: 0093, +E0094: 0094, +E0106: 0106, +E0107: 0107, +E0109: 0109, +E0110: 0110, +E0116: 0116, +E0117: 0117, +E0118: 0118, +E0119: 0119, +E0120: 0120, +E0121: 0121, +E0124: 0124, +E0128: 0128, +E0130: 0130, +E0131: 0131, +E0132: 0132, +E0133: 0133, +E0136: 0136, +E0137: 0137, +E0138: 0138, +E0139: 0139, +E0152: 0152, +E0154: 0154, +E0158: 0158, +E0161: 0161, +E0162: 0162, +E0164: 0164, +E0165: 0165, +E0170: 0170, +E0178: 0178, +E0183: 0183, +E0184: 0184, +E0185: 0185, +E0186: 0186, +E0191: 0191, +E0192: 0192, +E0193: 0193, +E0195: 0195, +E0197: 0197, +E0198: 0198, +E0199: 0199, +E0200: 0200, +E0201: 0201, +E0203: 0203, +E0204: 0204, +E0205: 0205, +E0206: 0206, +E0207: 0207, +E0208: 0208, +E0210: 0210, +E0211: 0211, +E0212: 0212, +E0214: 0214, +E0220: 0220, +E0221: 0221, +E0222: 0222, +E0223: 0223, +E0224: 0224, +E0225: 0225, +E0226: 0226, +E0227: 0227, +E0228: 0228, +E0229: 0229, +E0230: 0230, +E0231: 0231, +E0232: 0232, +E0243: 0243, +E0244: 0244, +E0251: 0251, +E0252: 0252, +E0253: 0253, +E0254: 0254, +E0255: 0255, +E0256: 0256, +E0259: 0259, +E0260: 0260, +E0261: 0261, +E0262: 0262, +E0263: 0263, +E0264: 0264, +E0267: 0267, +E0268: 0268, +E0271: 0271, +E0275: 0275, +E0276: 0276, +E0277: 0277, +E0281: 0281, +E0282: 0282, +E0283: 0283, +E0284: 0284, +E0297: 0297, +E0301: 0301, +E0302: 0302, +E0303: 0303, +E0307: 0307, +E0308: 0308, +E0309: 0309, +E0310: 0310, +E0311: 0311, +E0312: 0312, +E0316: 0316, +E0317: 0317, +E0320: 0320, +E0321: 0321, +E0322: 0322, +E0323: 0323, +E0324: 0324, +E0325: 0325, +E0326: 0326, +E0328: 0328, +E0329: 0329, +E0364: 0364, +E0365: 0365, +E0366: 0366, +E0367: 0367, +E0368: 0368, +E0369: 0369, +E0370: 0370, +E0371: 0371, +E0373: 0373, +E0374: 0374, +E0375: 0375, +E0376: 0376, +E0377: 0377, +E0378: 0378, +E0379: 0379, +E0380: 0380, +E0381: 0381, +E0382: 0382, +E0383: 0383, +E0384: 0384, +E0386: 0386, +E0387: 0387, +E0388: 0388, +E0389: 0389, +E0390: 0390, +E0391: 0391, +E0392: 0392, +E0393: 0393, +E0398: 0398, +E0399: 0399, +E0401: 0401, +E0403: 0403, +E0404: 0404, +E0405: 0405, +E0407: 0407, +E0408: 0408, +E0409: 0409, +E0411: 0411, +E0412: 0412, +E0415: 0415, +E0416: 0416, +E0422: 0422, +E0423: 0423, +E0424: 0424, +E0425: 0425, +E0426: 0426, +E0428: 0428, +E0429: 0429, +E0430: 0430, +E0431: 0431, +E0432: 0432, +E0433: 0433, +E0434: 0434, +E0435: 0435, +E0436: 0436, +E0437: 0437, +E0438: 0438, +E0439: 0439, +E0445: 0445, +E0446: 0446, +E0447: 0447, +E0448: 0448, +E0449: 0449, +E0451: 0451, +E0452: 0452, +E0453: 0453, +E0454: 0454, +E0455: 0455, +E0457: 0457, +E0458: 0458, +E0459: 0459, +E0460: 0460, +E0461: 0461, +E0462: 0462, +E0463: 0463, +E0464: 0464, +E0466: 0466, +E0468: 0468, +E0469: 0469, +E0472: 0472, +E0476: 0476, +E0477: 0477, +E0478: 0478, +E0482: 0482, +E0491: 0491, +E0492: 0492, +E0493: 0493, +E0495: 0495, +E0496: 0496, +E0497: 0497, +E0498: 0498, +E0499: 0499, +E0500: 0500, +E0501: 0501, +E0502: 0502, +E0503: 0503, +E0504: 0504, +E0505: 0505, +E0506: 0506, +E0507: 0507, +E0508: 0508, +E0509: 0509, +E0510: 0510, +E0511: 0511, +E0512: 0512, +E0514: 0514, +E0515: 0515, +E0516: 0516, +E0517: 0517, +E0518: 0518, +E0519: 0519, +E0520: 0520, +E0521: 0521, +E0522: 0522, +E0523: 0523, +E0524: 0524, +E0525: 0525, +E0527: 0527, +E0528: 0528, +E0529: 0529, +E0530: 0530, +E0531: 0531, +E0532: 0532, +E0533: 0533, +E0534: 0534, +E0535: 0535, +E0536: 0536, +E0537: 0537, +E0538: 0538, +E0539: 0539, +E0541: 0541, +E0542: 0542, +E0543: 0543, +E0544: 0544, +E0545: 0545, +E0546: 0546, +E0547: 0547, +E0549: 0549, +E0550: 0550, +E0551: 0551, +E0552: 0552, +E0554: 0554, +E0556: 0556, +E0557: 0557, +E0559: 0559, +E0560: 0560, +E0561: 0561, +E0562: 0562, +E0565: 0565, +E0566: 0566, +E0567: 0567, +E0568: 0568, +E0569: 0569, +E0570: 0570, +E0571: 0571, +E0572: 0572, +E0573: 0573, +E0574: 0574, +E0575: 0575, +E0576: 0576, +E0577: 0577, +E0578: 0578, +E0579: 0579, +E0580: 0580, +E0581: 0581, +E0582: 0582, +E0583: 0583, +E0584: 0584, +E0585: 0585, +E0586: 0586, +E0587: 0587, +E0588: 0588, +E0589: 0589, +E0590: 0590, +E0591: 0591, +E0592: 0592, +E0593: 0593, +E0594: 0594, +E0595: 0595, +E0596: 0596, +E0597: 0597, +E0599: 0599, +E0600: 0600, +E0601: 0601, +E0602: 0602, +E0603: 0603, +E0604: 0604, +E0605: 0605, +E0606: 0606, +E0607: 0607, +E0608: 0608, +E0609: 0609, +E0610: 0610, +E0614: 0614, +E0615: 0615, +E0616: 0616, +E0617: 0617, +E0618: 0618, +E0619: 0619, +E0620: 0620, +E0621: 0621, +E0622: 0622, +E0623: 0623, +E0624: 0624, +E0625: 0625, +E0626: 0626, +E0627: 0627, +E0628: 0628, +E0631: 0631, +E0632: 0632, +E0633: 0633, +E0634: 0634, +E0635: 0635, +E0636: 0636, +E0637: 0637, +E0638: 0638, +E0639: 0639, +E0640: 0640, +E0641: 0641, +E0642: 0642, +E0643: 0643, +E0644: 0644, +E0646: 0646, +E0647: 0647, +E0648: 0648, +E0657: 0657, +E0658: 0658, +E0659: 0659, +E0660: 0660, +E0661: 0661, +E0662: 0662, +E0663: 0663, +E0664: 0664, +E0665: 0665, +E0666: 0666, +E0667: 0667, +E0668: 0668, +E0669: 0669, +E0670: 0670, +E0671: 0671, +E0687: 0687, +E0688: 0688, +E0689: 0689, +E0690: 0690, +E0691: 0691, +E0692: 0692, +E0693: 0693, +E0695: 0695, +E0696: 0696, +E0697: 0697, +E0698: 0698, +E0699: 0699, +E0700: 0700, +E0701: 0701, +E0703: 0703, +E0704: 0704, +E0705: 0705, +E0706: 0706, +E0708: 0708, +E0710: 0710, +E0712: 0712, +E0713: 0713, +E0714: 0714, +E0715: 0715, +E0716: 0716, +E0711: 0711, +E0717: 0717, +E0718: 0718, +E0719: 0719, +E0720: 0720, +E0722: 0722, +E0724: 0724, +E0725: 0725, +E0726: 0726, +E0727: 0727, +E0728: 0728, +E0729: 0729, +E0730: 0730, +E0731: 0731, +E0732: 0732, +E0733: 0733, +E0734: 0734, +E0735: 0735, +E0736: 0736, +E0737: 0737, +E0739: 0739, +E0740: 0740, +E0741: 0741, +E0742: 0742, +E0743: 0743, +E0744: 0744, +E0745: 0745, +E0746: 0746, +E0747: 0747, +E0748: 0748, +E0749: 0749, +E0750: 0750, +E0751: 0751, +E0752: 0752, +E0753: 0753, +E0754: 0754, +E0755: 0755, +E0756: 0756, +E0757: 0757, +E0758: 0758, +E0759: 0759, +E0760: 0760, +E0761: 0761, +E0762: 0762, +E0763: 0763, +E0764: 0764, +E0765: 0765, +E0766: 0766, +E0767: 0767, +E0768: 0768, +E0769: 0769, +E0770: 0770, +E0771: 0771, +E0772: 0772, +E0773: 0773, +E0774: 0774, +E0775: 0775, +E0776: 0776, +E0777: 0777, +E0778: 0778, +E0779: 0779, +E0780: 0780, +E0781: 0781, +E0782: 0782, +E0783: 0783, +E0784: 0784, +E0785: 0785, +E0786: 0786, +E0787: 0787, +E0788: 0788, +E0789: 0789, +E0790: 0790, +E0791: 0791, +E0792: 0792, +E0793: 0793, +E0794: 0794, +E0795: 0795, +E0796: 0796, +E0797: 0797, + ); ) } -mod error_codes; -pub use error_codes::DIAGNOSTICS; +// Undocumented removed error codes. Note that many removed error codes are kept in the list above +// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). +// E0006, // merged with E0005 +// E0008, // cannot bind by-move into a pattern guard +// E0019, // merged into E0015 +// E0035, // merged into E0087/E0089 +// E0036, // merged into E0087/E0089 +// E0068, +// E0085, +// E0086, +// E0101, // replaced with E0282 +// E0102, // replaced with E0282 +// E0103, +// E0104, +// E0122, // bounds in type aliases are ignored, turned into proper lint +// E0123, +// E0127, +// E0129, +// E0134, +// E0135, +// E0141, +// E0153, // unused error code +// E0157, // unused error code +// E0159, // use of trait `{}` as struct constructor +// E0163, // merged into E0071 +// E0167, +// E0168, +// E0172, // non-trait found in a type sum, moved to resolve +// E0173, // manual implementations of unboxed closure traits are experimental +// E0174, +// E0182, // merged into E0229 +// E0187, // cannot infer the kind of the closure +// E0188, // can not cast an immutable reference to a mutable pointer +// E0189, // deprecated: can only cast a boxed pointer to a boxed object +// E0190, // deprecated: can only cast a &-pointer to an &-object +// E0194, // merged into E0403 +// E0196, // cannot determine a type for this closure +// E0209, // builtin traits can only be implemented on structs or enums +// E0213, // associated types are not accepted in this context +// E0215, // angle-bracket notation is not stable with `Fn` +// E0216, // parenthetical notation is only stable with `Fn` +// E0217, // ambiguous associated type, defined in multiple supertraits +// E0218, // no associated type defined +// E0219, // associated type defined in higher-ranked supertrait +// E0233, +// E0234, +// E0235, // structure constructor specifies a structure of type but +// E0236, // no lang item for range syntax +// E0237, // no lang item for range syntax +// E0238, // parenthesized parameters may only be used with a trait +// E0239, // `next` method of `Iterator` trait has unexpected type +// E0240, +// E0241, +// E0242, +// E0245, // not a trait +// E0246, // invalid recursive type +// E0247, +// E0248, // value used as a type, now reported earlier during resolution +// // as E0412 +// E0249, +// E0257, +// E0258, +// E0272, // on_unimplemented #0 +// E0273, // on_unimplemented #1 +// E0274, // on_unimplemented #2 +// E0278, // requirement is not satisfied +// E0279, +// E0280, // changed to ICE +// E0285, // overflow evaluation builtin bounds +// E0296, // replaced with a generic attribute input check +// E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0300, // unexpanded macro +// E0304, // expected signed integer constant +// E0305, // expected constant +// E0313, // removed: found unreachable +// E0314, // closure outlives stack frame +// E0315, // cannot invoke closure outside of its lifetime +// E0319, // trait impls for defaulted traits allowed just for structs/enums +// E0372, // coherence not object safe +// E0385, // {} in an aliasable location +// E0402, // cannot use an outer type parameter in this context +// E0406, // merged into 420 +// E0410, // merged into 408 +// E0413, // merged into 530 +// E0414, // merged into 530 +// E0417, // merged into 532 +// E0418, // merged into 532 +// E0419, // merged into 531 +// E0420, // merged into 532 +// E0421, // merged into 531 +// E0427, // merged into 530 +// E0445, // merged into 446 and type privacy lints +// E0456, // plugin `..` is not available for triple `..` +// E0465, // removed: merged with E0464 +// E0467, // removed +// E0470, // removed +// E0471, // constant evaluation error (in pattern) +// E0473, // dereference of reference outside its lifetime +// E0474, // captured variable `..` does not outlive the enclosing closure +// E0475, // index of slice outside its lifetime +// E0479, // the type `..` (provided as the value of a type parameter) is... +// E0480, // lifetime of method receiver does not outlive the method call +// E0481, // lifetime of function argument does not outlive the function call +// E0483, // lifetime of operand does not outlive the operation +// E0484, // reference is not valid at the time of borrow +// E0485, // automatically reference is not valid at the time of borrow +// E0486, // type of expression contains references that are not valid during.. +// E0487, // unsafe use of destructor: destructor might be called while... +// E0488, // lifetime of variable does not enclose its declaration +// E0489, // type/lifetime parameter not in scope here +// E0490, // removed: unreachable +// E0526, // shuffle indices are not constant +// E0540, // multiple rustc_deprecated attributes +// E0548, // replaced with a generic attribute input check +// E0553, // multiple rustc_const_unstable attributes +// E0555, // replaced with a generic attribute input check +// E0558, // replaced with a generic attribute input check +// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 +// E0564, // only named lifetimes are allowed in `impl Trait`, +// // but `{}` was found in the type `{}` +// E0598, // lifetime of {} is too short to guarantee its contents can be... +// E0611, // merged into E0616 +// E0612, // merged into E0609 +// E0613, // Removed (merged with E0609) +// E0629, // missing 'feature' (rustc_const_unstable) +// E0630, // rustc_const_unstable attribute must be paired with stable/unstable +// // attribute +// E0645, // trait aliases not finished +// E0694, // an unknown tool name found in scoped attributes +// E0702, // replaced with a generic attribute input check +// E0707, // multiple elided lifetimes used in arguments of `async fn` +// E0709, // multiple different lifetimes used in arguments of `async fn` +// E0721, // `await` keyword +// E0723, // unstable feature in `const` context +// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. +// E0744, // merged into E0728 diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 0c1fcecb571..a2d1fd2a924 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -10,9 +10,11 @@ derive_setters = "0.1.6" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f0699a56f98..949f52ef6b5 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -9,8 +9,8 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; use crate::translation::{to_fluent_args, Translate}; use crate::{ - CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Style, SubDiagnostic, + CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, ErrCode, FluentBundle, + LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic, }; use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; use rustc_data_structures::sync::Lrc; @@ -127,7 +127,7 @@ impl AnnotateSnippetEmitter { level: &Level, messages: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option<String>, + code: &Option<ErrCode>, msp: &MultiSpan, _children: &[SubDiagnostic], _suggestions: &[CodeSuggestion], @@ -178,6 +178,7 @@ impl AnnotateSnippetEmitter { .collect::<Vec<Owned>>() }) .collect(); + let code = code.map(|code| code.to_string()); let snippet = Snippet { title: Some(Annotation { label: Some(&message), diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs new file mode 100644 index 00000000000..947cf27ca79 --- /dev/null +++ b/compiler/rustc_errors/src/codes.rs @@ -0,0 +1,39 @@ +//! This module defines the following. +//! - The `ErrCode` type. +//! - A constant for every error code, with a name like `E0123`. +//! - A static table `DIAGNOSTICS` pairing every error code constant with its +//! long description text. + +use std::fmt; + +rustc_index::newtype_index! { + #[max = 9999] // Because all error codes have four digits. + #[orderable] + #[encodable] + #[debug_format = "ErrCode({})"] + pub struct ErrCode {} +} + +impl fmt::Display for ErrCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "E{:04}", self.as_u32()) + } +} + +macro_rules! define_error_code_constants_and_diagnostics_table { + ($($name:ident: $num:literal,)*) => ( + $( + pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num); + )* + pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[ + $( ( + $name, + include_str!( + concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md") + ) + ), )* + ]; + ) +} + +rustc_error_codes::error_codes!(define_error_code_constants_and_diagnostics_table); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 4934bc2450c..8a32e29ddc9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,8 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, - MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, + CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, + ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, + SuggestionStyle, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; @@ -104,7 +105,7 @@ pub struct Diagnostic { pub(crate) level: Level, pub messages: Vec<(DiagnosticMessage, Style)>, - pub code: Option<String>, + pub code: Option<ErrCode>, pub span: MultiSpan, pub children: Vec<SubDiagnostic>, pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>, @@ -893,8 +894,8 @@ impl Diagnostic { self } - pub fn code(&mut self, s: String) -> &mut Self { - self.code = Some(s); + pub fn code(&mut self, code: ErrCode) -> &mut Self { + self.code = Some(code); self } @@ -903,8 +904,8 @@ impl Diagnostic { self } - pub fn get_code(&self) -> Option<&str> { - self.code.as_deref() + pub fn get_code(&self) -> Option<ErrCode> { + self.code } pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self { @@ -990,7 +991,7 @@ impl Diagnostic { &Level, &[(DiagnosticMessage, Style)], Vec<(&Cow<'static, str>, &DiagnosticArgValue<'static>)>, - &Option<String>, + &Option<ErrCode>, &Option<IsLint>, &MultiSpan, &Result<Vec<CodeSuggestion>, SuggestionsDisabled>, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 87e2d295c7f..8bfb1816486 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,7 +1,7 @@ use crate::diagnostic::IntoDiagnosticArg; use crate::{DiagCtxt, Level, MultiSpan, StashKey}; use crate::{ - Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, ExplicitBug, + Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrCode, ErrorGuaranteed, ExplicitBug, SubdiagnosticMessage, }; use rustc_lint_defs::Applicability; @@ -399,7 +399,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { name: String, has_future_breakage: bool, )); forward!((code, with_code)( - s: String, + code: ErrCode, )); forward!((arg, with_arg)( name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg, @@ -439,12 +439,7 @@ impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> { #[macro_export] macro_rules! struct_span_code_err { - ($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - $dcx.struct_span_err($span, format!($($message)*)).with_code($crate::error_code!($code)) + ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({ + $dcx.struct_span_err($span, format!($($message)*)).with_code($code) }) } - -#[macro_export] -macro_rules! error_code { - ($code:ident) => {{ stringify!($code).to_owned() }}; -} diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index f6679ae9bb3..df3fd4af4b4 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,7 +1,7 @@ use crate::diagnostic::DiagnosticLocation; use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{ - DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, ErrCode, IntoDiagnostic, IntoDiagnosticArg, Level, }; use rustc_ast as ast; @@ -58,16 +58,29 @@ macro_rules! into_diagnostic_arg_using_display { } } +macro_rules! into_diagnostic_arg_for_number { + ($( $ty:ty ),+ $(,)?) => { + $( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + // HACK: `FluentNumber` the underline backing struct represent + // numbers using a f64 which can't represent all the i128 numbers + // So in order to be able to use fluent selectors and still + // have all the numbers representable we only convert numbers + // below a certain threshold. + if let Ok(n) = TryInto::<i128>::try_into(self) && n >= -100 && n <= 100 { + DiagnosticArgValue::Number(n) + } else { + self.to_string().into_diagnostic_arg() + } + } + } + )+ + } +} + into_diagnostic_arg_using_display!( ast::ParamKindOrd, - i8, - u8, - i16, - u16, - u32, - i64, - i128, - u128, std::io::Error, Box<dyn std::error::Error>, std::num::NonZeroU32, @@ -80,19 +93,10 @@ into_diagnostic_arg_using_display!( &TargetTriple, SplitDebuginfo, ExitStatus, + ErrCode, ); -impl IntoDiagnosticArg for i32 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self.into()) - } -} - -impl IntoDiagnosticArg for u64 { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self.into()) - } -} +into_diagnostic_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagnosticArg for bool { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { @@ -154,12 +158,6 @@ impl IntoDiagnosticArg for PathBuf { } } -impl IntoDiagnosticArg for usize { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self as i128) - } -} - impl IntoDiagnosticArg for PanicStrategy { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 23efdaea0eb..9f76c1dd248 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -17,8 +17,8 @@ use crate::styled_buffer::StyledBuffer; use crate::translation::{to_fluent_args, Translate}; use crate::{ diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticMessage, - FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, - SuggestionStyle, TerminalUrl, + ErrCode, FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, + SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; use rustc_lint_defs::pluralize; @@ -1309,7 +1309,7 @@ impl HumanEmitter { msp: &MultiSpan, msgs: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option<String>, + code: &Option<ErrCode>, level: &Level, max_line_num_len: usize, is_secondary: bool, @@ -1340,9 +1340,9 @@ impl HumanEmitter { buffer.append(0, "[", Style::Level(*level)); let code = if let TerminalUrl::Yes = self.terminal_url { let path = "https://doc.rust-lang.org/error_codes"; - Cow::Owned(format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")) + format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07") } else { - Cow::Borrowed(code) + code.to_string() }; buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); @@ -2076,7 +2076,7 @@ impl HumanEmitter { level: &Level, messages: &[(DiagnosticMessage, Style)], args: &FluentArgs<'_>, - code: &Option<String>, + code: &Option<ErrCode>, span: &MultiSpan, children: &[SubDiagnostic], suggestions: &[CodeSuggestion], diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 51b064f4c61..6f922998279 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -400,10 +400,10 @@ impl Diagnostic { let translated_message = je.translate_messages(&diag.messages, &args); - let code = if let Some(code) = &diag.code { + let code = if let Some(code) = diag.code { Some(DiagnosticCode { code: code.to_string(), - explanation: je.registry.as_ref().unwrap().try_find_description(&code).ok(), + explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(), }) } else if let Some(IsLint { name, .. }) = &diag.is_lint { Some(DiagnosticCode { code: name.to_string(), explanation: None }) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ee831c4f560..6d9208341a5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,23 +2,26 @@ //! //! This module contains the code for creating and emitting diagnostics. +// tidy-alphabetical-start +#![allow(incomplete_features)] +#![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(rustdoc_internals)] #![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(box_into_inner)] #![feature(box_patterns)] +#![feature(error_reporter)] #![feature(extract_if)] #![feature(let_chains)] +#![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] -#![feature(yeet_expr)] +#![feature(rustdoc_internals)] #![feature(try_blocks)] -#![feature(error_reporter)] -#![allow(incomplete_features)] -#![allow(internal_features)] +#![feature(yeet_expr)] +// tidy-alphabetical-end #[macro_use] extern crate rustc_macros; @@ -28,6 +31,7 @@ extern crate tracing; extern crate self as rustc_errors; +pub use codes::*; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, @@ -76,6 +80,7 @@ use std::path::{Path, PathBuf}; use Level::*; pub mod annotate_snippet_emitter_writer; +pub mod codes; mod diagnostic; mod diagnostic_builder; mod diagnostic_impls; @@ -444,10 +449,10 @@ struct DiagCtxtInner { /// This set contains the code of all emitted diagnostics to avoid /// emitting the same diagnostic with extended help (`--teach`) twice, which /// would be unnecessary repetition. - taught_diagnostics: FxHashSet<String>, + taught_diagnostics: FxHashSet<ErrCode>, /// Used to suggest rustc --explain `<error code>` - emitted_diagnostic_codes: FxIndexSet<String>, + emitted_diagnostic_codes: FxIndexSet<ErrCode>, /// This set contains a hash of every diagnostic that has been emitted by /// this `DiagCtxt`. These hashes is used to avoid emitting the same error @@ -1002,9 +1007,9 @@ impl DiagCtxt { let mut error_codes = inner .emitted_diagnostic_codes .iter() - .filter_map(|code| { + .filter_map(|&code| { if registry.try_find_description(code).is_ok().clone() { - Some(code.clone()) + Some(code.to_string()) } else { None } @@ -1050,8 +1055,8 @@ impl DiagCtxt { /// /// Used to suppress emitting the same error multiple times with extended explanation when /// calling `-Zteach`. - pub fn must_teach(&self, code: &str) -> bool { - self.inner.borrow_mut().taught_diagnostics.insert(code.to_string()) + pub fn must_teach(&self, code: ErrCode) -> bool { + self.inner.borrow_mut().taught_diagnostics.insert(code) } pub fn force_print_diagnostic(&self, db: Diagnostic) { @@ -1311,8 +1316,8 @@ impl DiagCtxtInner { let mut guaranteed = None; (*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| { - if let Some(ref code) = diagnostic.code { - self.emitted_diagnostic_codes.insert(code.clone()); + if let Some(code) = diagnostic.code { + self.emitted_diagnostic_codes.insert(code); } let already_emitted = { diff --git a/compiler/rustc_errors/src/registry.rs b/compiler/rustc_errors/src/registry.rs index f26d8e7ebdc..8834d04d971 100644 --- a/compiler/rustc_errors/src/registry.rs +++ b/compiler/rustc_errors/src/registry.rs @@ -1,3 +1,4 @@ +use crate::ErrCode; use rustc_data_structures::fx::FxHashMap; #[derive(Debug)] @@ -5,17 +6,17 @@ pub struct InvalidErrorCode; #[derive(Clone)] pub struct Registry { - long_descriptions: FxHashMap<&'static str, &'static str>, + long_descriptions: FxHashMap<ErrCode, &'static str>, } impl Registry { - pub fn new(long_descriptions: &[(&'static str, &'static str)]) -> Registry { + pub fn new(long_descriptions: &[(ErrCode, &'static str)]) -> Registry { Registry { long_descriptions: long_descriptions.iter().copied().collect() } } /// Returns `InvalidErrorCode` if the code requested does not exist in the /// registry. - pub fn try_find_description(&self, code: &str) -> Result<&'static str, InvalidErrorCode> { - self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode) + pub fn try_find_description(&self, code: ErrCode) -> Result<&'static str, InvalidErrorCode> { + self.long_descriptions.get(&code).copied().ok_or(InvalidErrorCode) } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 29b70f33a6c..657e19277a7 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -796,9 +796,15 @@ impl SyntaxExtension { /// | external | no | if-ext | if-ext | yes | /// | yes | yes | yes | yes | yes | fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool { - let collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) + let mut collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) .map(|v| Self::collapse_debuginfo_by_name(sess, v)) .unwrap_or(CollapseMacroDebuginfo::Unspecified); + if collapse_debuginfo_attr == CollapseMacroDebuginfo::Unspecified + && attr::contains_name(attrs, sym::rustc_builtin_macro) + { + collapse_debuginfo_attr = CollapseMacroDebuginfo::Yes; + } + let flag = sess.opts.unstable_opts.collapse_macro_debuginfo; let attr = collapse_debuginfo_attr; let ext = !is_local; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index f574e81e905..781186764fa 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -373,7 +373,9 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) { + if self.features.is_some_and(|features| !features.stmt_expr_attributes) + && !attr.span.allows_unstable(sym::stmt_expr_attributes) + { let mut err = feature_err( &self.sess, sym::stmt_expr_attributes, diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 4a1c00f0104..2584ff62e98 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -1,4 +1,5 @@ use rustc_ast::ast; +use rustc_errors::codes::*; use rustc_macros::Diagnostic; use rustc_session::Limit; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -175,7 +176,7 @@ pub(crate) struct TakesNoArguments<'a> { } #[derive(Diagnostic)] -#[diag(expand_feature_removed, code = "E0557")] +#[diag(expand_feature_removed, code = E0557)] pub(crate) struct FeatureRemoved<'a> { #[primary_span] #[label] @@ -191,7 +192,7 @@ pub(crate) struct FeatureRemovedReason<'a> { } #[derive(Diagnostic)] -#[diag(expand_feature_not_allowed, code = "E0725")] +#[diag(expand_feature_not_allowed, code = E0725)] pub(crate) struct FeatureNotAllowed { #[primary_span] pub span: Span, @@ -210,7 +211,7 @@ pub(crate) struct RecursionLimitReached<'a> { } #[derive(Diagnostic)] -#[diag(expand_malformed_feature_attribute, code = "E0556")] +#[diag(expand_malformed_feature_attribute, code = E0556)] pub(crate) struct MalformedFeatureAttribute { #[primary_span] pub span: Span, @@ -347,7 +348,7 @@ pub(crate) struct ModuleInBlockName { } #[derive(Diagnostic)] -#[diag(expand_module_file_not_found, code = "E0583")] +#[diag(expand_module_file_not_found, code = E0583)] #[help] #[note] pub(crate) struct ModuleFileNotFound { @@ -359,7 +360,7 @@ pub(crate) struct ModuleFileNotFound { } #[derive(Diagnostic)] -#[diag(expand_module_multiple_candidates, code = "E0761")] +#[diag(expand_module_multiple_candidates, code = E0761)] #[help] pub(crate) struct ModuleMultipleCandidates { #[primary_span] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6eed2178ead..e66a66e23dc 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -516,6 +516,9 @@ declare_features! ( (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), + /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are + /// unambiguously sound. + (incomplete, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 3aad510f366..c22daad334f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index bfe88df4e1a..5e9076243f8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -7,7 +7,9 @@ use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{ + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 4284758b117..30b10446afc 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -5,7 +5,9 @@ use crate::astconv::{ }; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 33e782abc68..98cd8a085ba 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -1,5 +1,5 @@ use rustc_ast::TraitObjectSyntax; -use rustc_errors::{Diagnostic, StashKey}; +use rustc_errors::{codes::*, Diagnostic, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 7c97c2a1a6f..2dec0ab4355 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - error_code, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, FatalError, MultiSpan, + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + FatalError, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -1072,9 +1072,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(binding) = binding && let ConvertedBindingKind::Equality(_) = binding.kind { - error_code!(E0222) + E0222 } else { - error_code!(E0221) + E0221 }, ); @@ -1630,7 +1630,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let reported = tcx .dcx() .struct_span_err(span, msg) - .with_code(rustc_errors::error_code!(E0624)) + .with_code(E0624) .with_span_label(span, format!("private {kind}")) .with_span_label(def_span, format!("{kind} defined here")) .emit(); diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 5f35f75c77b..2d85ad5789e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -2,7 +2,7 @@ use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBou use crate::bounds::Bounds; use crate::errors::TraitObjectDeclaredWithNoTraits; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c63bafcdcd4..2fe3499e8e6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -5,7 +5,7 @@ use super::compare_impl_item::check_type_bounds; use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::*; use rustc_attr as attr; -use rustc_errors::{ErrorGuaranteed, MultiSpan}; +use rustc_errors::{codes::*, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 57829d9d418..479421af77f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2,7 +2,7 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -1382,7 +1382,7 @@ fn compare_number_of_generics<'tcx>( kind = kind, ), ); - err.code("E0049".into()); + err.code(E0049); let msg = format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 3275a81c3dd..9fe95487bb9 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -2,7 +2,7 @@ // // We don't do any drop checking during hir typeck. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::util::CheckRegions; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 60e4403c1c7..2d0d6611444 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -8,7 +8,7 @@ use crate::errors::{ }; use hir::def_id::DefId; -use rustc_errors::{struct_span_code_err, DiagnosticMessage}; +use rustc_errors::{codes::*, struct_span_code_err, DiagnosticMessage}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 70213ee0614..0978a5e6596 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -4,7 +4,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 63ea0272014..951440d6a2d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index dafa899ef24..8cf1f2c9407 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -6,7 +6,7 @@ // mappings. That mapping code resides here. use crate::errors; -use rustc_errors::{error_code, struct_span_code_err}; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -61,7 +61,7 @@ fn enforce_trait_manually_implementable( // Maintain explicit error code for `Unsize`, since it has a useful // explanation about using `CoerceUnsized` instead. if Some(trait_def_id) == tcx.lang_items().unsize_trait() { - err.code(error_code!(E0328)); + err.code(E0328); } return Err(err.emit()); diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index e4c407af53f..e3b5c724cde 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -1,7 +1,7 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index a857e01f4fa..97d792e49ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -8,7 +8,7 @@ use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f14390b77c6..e5871276d64 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,8 +2,8 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - error_code, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - Level, MultiSpan, + codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, + MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -52,7 +52,7 @@ pub struct AssocKindMismatchWrapInBracesSugg { } #[derive(Diagnostic)] -#[diag(hir_analysis_assoc_item_not_found, code = "E0220")] +#[diag(hir_analysis_assoc_item_not_found, code = E0220)] pub struct AssocItemNotFound<'a> { #[primary_span] pub span: Span, @@ -122,7 +122,7 @@ pub enum AssocItemNotFoundSugg<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")] +#[diag(hir_analysis_unrecognized_atomic_operation, code = E0092)] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -131,7 +131,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] +#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = E0094)] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -142,7 +142,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")] +#[diag(hir_analysis_unrecognized_intrinsic_function, code = E0093)] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -151,7 +151,7 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(Diagnostic)] -#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] +#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = E0195)] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] @@ -178,7 +178,7 @@ pub struct AsyncTraitImplShouldBeAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")] +#[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -186,7 +186,7 @@ pub struct DropImplOnWrongItem { } #[derive(Diagnostic)] -#[diag(hir_analysis_field_already_declared, code = "E0124")] +#[diag(hir_analysis_field_already_declared, code = E0124)] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] @@ -197,7 +197,7 @@ pub struct FieldAlreadyDeclared { } #[derive(Diagnostic)] -#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")] +#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = E0184)] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -205,14 +205,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(Diagnostic)] -#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] +#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub spans: Vec<Span>, } #[derive(Diagnostic)] -#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")] +#[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -228,7 +228,7 @@ pub struct ConstParamTyImplOnNonAdt { } #[derive(Diagnostic)] -#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")] +#[diag(hir_analysis_trait_object_declared_with_no_traits, code = E0224)] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, @@ -237,14 +237,14 @@ pub struct TraitObjectDeclaredWithNoTraits { } #[derive(Diagnostic)] -#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")] +#[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")] +#[diag(hir_analysis_assoc_type_binding_not_allowed, code = E0229)] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -264,7 +264,7 @@ pub struct ParenthesizedFnTraitExpansion { } #[derive(Diagnostic)] -#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")] +#[diag(hir_analysis_typeof_reserved_keyword_used, code = E0516)] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -275,7 +275,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")] +#[diag(hir_analysis_value_of_associated_struct_already_specified, code = E0719)] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] @@ -320,7 +320,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params); err.span(self.span); - err.code(error_code!(E0393)); + err.code(E0393); err.arg("parameterCount", self.missing_type_params.len()); err.arg( "parameters", @@ -373,7 +373,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { } #[derive(Diagnostic)] -#[diag(hir_analysis_manual_implementation, code = "E0183")] +#[diag(hir_analysis_manual_implementation, code = E0183)] #[help] pub struct ManualImplementation { #[primary_span] @@ -421,7 +421,7 @@ pub struct SelfInImplSelf { } #[derive(Diagnostic)] -#[diag(hir_analysis_linkage_type, code = "E0791")] +#[diag(hir_analysis_linkage_type, code = E0791)] pub(crate) struct LinkageType { #[primary_span] pub span: Span, @@ -429,7 +429,7 @@ pub(crate) struct LinkageType { #[derive(Diagnostic)] #[help] -#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")] +#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = E0055)] pub struct AutoDerefReachedRecursionLimit<'a> { #[primary_span] #[label] @@ -440,7 +440,7 @@ pub struct AutoDerefReachedRecursionLimit<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_where_clause_on_main, code = "E0646")] +#[diag(hir_analysis_where_clause_on_main, code = E0646)] pub(crate) struct WhereClauseOnMain { #[primary_span] pub span: Span, @@ -485,7 +485,7 @@ pub(crate) struct StartTargetFeature { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_not_async, code = "E0752")] +#[diag(hir_analysis_start_not_async, code = E0752)] pub(crate) struct StartAsync { #[primary_span] #[label] @@ -493,7 +493,7 @@ pub(crate) struct StartAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_function_where, code = "E0647")] +#[diag(hir_analysis_start_function_where, code = E0647)] pub(crate) struct StartFunctionWhere { #[primary_span] #[label] @@ -501,7 +501,7 @@ pub(crate) struct StartFunctionWhere { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_function_parameters, code = "E0132")] +#[diag(hir_analysis_start_function_parameters, code = E0132)] pub(crate) struct StartFunctionParameters { #[primary_span] #[label] @@ -509,14 +509,14 @@ pub(crate) struct StartFunctionParameters { } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_return_type_generic, code = "E0131")] +#[diag(hir_analysis_main_function_return_type_generic, code = E0131)] pub(crate) struct MainFunctionReturnTypeGeneric { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_async, code = "E0752")] +#[diag(hir_analysis_main_function_async, code = E0752)] pub(crate) struct MainFunctionAsync { #[primary_span] pub span: Span, @@ -525,7 +525,7 @@ pub(crate) struct MainFunctionAsync { } #[derive(Diagnostic)] -#[diag(hir_analysis_main_function_generic_parameters, code = "E0131")] +#[diag(hir_analysis_main_function_generic_parameters, code = E0131)] pub(crate) struct MainFunctionGenericParameters { #[primary_span] pub span: Span, @@ -534,7 +534,7 @@ pub(crate) struct MainFunctionGenericParameters { } #[derive(Diagnostic)] -#[diag(hir_analysis_variadic_function_compatible_convention, code = "E0045")] +#[diag(hir_analysis_variadic_function_compatible_convention, code = E0045)] pub(crate) struct VariadicFunctionCompatibleConvention<'a> { #[primary_span] #[label] @@ -587,7 +587,7 @@ pub(crate) struct TypeOf<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_pass_to_variadic_function, code = "E0617")] +#[diag(hir_analysis_pass_to_variadic_function, code = E0617)] pub(crate) struct PassToVariadicFunction<'tcx, 'a> { #[primary_span] pub span: Span, @@ -601,7 +601,7 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = "E0607")] +#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)] pub(crate) struct CastThinPointerToFatPointer<'tcx> { #[primary_span] pub span: Span, @@ -610,7 +610,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_invalid_union_field, code = "E0740")] +#[diag(hir_analysis_invalid_union_field, code = E0740)] pub(crate) struct InvalidUnionField { #[primary_span] pub field_span: Span, @@ -649,7 +649,7 @@ pub(crate) struct ReturnTypeNotationEqualityBound { } #[derive(Diagnostic)] -#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")] +#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = E0121)] pub(crate) struct PlaceholderNotAllowedItemSignatures { #[primary_span] #[label] @@ -658,7 +658,7 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures { } #[derive(Diagnostic)] -#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = "E0212")] +#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)] pub(crate) struct AssociatedTypeTraitUninferredGenericParams { #[primary_span] pub span: Span, @@ -684,7 +684,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion } #[derive(Diagnostic)] -#[diag(hir_analysis_enum_discriminant_overflowed, code = "E0370")] +#[diag(hir_analysis_enum_discriminant_overflowed, code = E0370)] #[note] pub(crate) struct EnumDiscriminantOverflowed { #[primary_span] @@ -774,7 +774,7 @@ pub(crate) struct SIMDFFIHighlyExperimental { #[derive(Diagnostic)] pub enum ImplNotMarkedDefault { - #[diag(hir_analysis_impl_not_marked_default, code = "E0520")] + #[diag(hir_analysis_impl_not_marked_default, code = E0520)] #[note] Ok { #[primary_span] @@ -784,7 +784,7 @@ pub enum ImplNotMarkedDefault { ok_label: Span, ident: Symbol, }, - #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")] + #[diag(hir_analysis_impl_not_marked_default_err, code = E0520)] #[note] Err { #[primary_span] @@ -795,7 +795,7 @@ pub enum ImplNotMarkedDefault { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_trait_item, code = "E0046")] +#[diag(hir_analysis_missing_trait_item, code = E0046)] pub(crate) struct MissingTraitItem { #[primary_span] #[label] @@ -846,7 +846,7 @@ pub(crate) struct MissingTraitItemSuggestionNone { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")] +#[diag(hir_analysis_missing_one_of_trait_item, code = E0046)] pub(crate) struct MissingOneOfTraitItem { #[primary_span] #[label] @@ -857,7 +857,7 @@ pub(crate) struct MissingOneOfTraitItem { } #[derive(Diagnostic)] -#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")] +#[diag(hir_analysis_missing_trait_item_unstable, code = E0046)] #[note] pub(crate) struct MissingTraitItemUnstable { #[primary_span] @@ -872,7 +872,7 @@ pub(crate) struct MissingTraitItemUnstable { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_enum_variant, code = "E0731")] +#[diag(hir_analysis_transparent_enum_variant, code = E0731)] pub(crate) struct TransparentEnumVariant { #[primary_span] #[label] @@ -886,7 +886,7 @@ pub(crate) struct TransparentEnumVariant { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")] +#[diag(hir_analysis_transparent_non_zero_sized_enum, code = E0690)] pub(crate) struct TransparentNonZeroSizedEnum<'a> { #[primary_span] #[label] @@ -898,7 +898,7 @@ pub(crate) struct TransparentNonZeroSizedEnum<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")] +#[diag(hir_analysis_transparent_non_zero_sized, code = E0690)] pub(crate) struct TransparentNonZeroSized<'a> { #[primary_span] #[label] @@ -1045,7 +1045,7 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside, code = E0390)] #[help] pub struct InherentTyOutside { #[primary_span] @@ -1054,7 +1054,7 @@ pub struct InherentTyOutside { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct DispatchFromDynCoercion<'a> { #[primary_span] pub span: Span, @@ -1066,14 +1066,14 @@ pub struct DispatchFromDynCoercion<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_repr, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)] pub struct DispatchFromDynRepr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)] #[help] pub struct InherentTyOutsideRelevant { #[primary_span] @@ -1083,7 +1083,7 @@ pub struct InherentTyOutsideRelevant { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")] +#[diag(hir_analysis_inherent_ty_outside_new, code = E0116)] #[note] pub struct InherentTyOutsideNew { #[primary_span] @@ -1092,7 +1092,7 @@ pub struct InherentTyOutsideNew { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")] +#[diag(hir_analysis_inherent_ty_outside_primitive, code = E0390)] #[help] pub struct InherentTyOutsidePrimitive { #[primary_span] @@ -1102,7 +1102,7 @@ pub struct InherentTyOutsidePrimitive { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")] +#[diag(hir_analysis_inherent_primitive_ty, code = E0390)] #[help] pub struct InherentPrimitiveTy<'a> { #[primary_span] @@ -1118,7 +1118,7 @@ pub struct InherentPrimitiveTyNote<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_dyn, code = "E0785")] +#[diag(hir_analysis_inherent_dyn, code = E0785)] #[note] pub struct InherentDyn { #[primary_span] @@ -1127,7 +1127,7 @@ pub struct InherentDyn { } #[derive(Diagnostic)] -#[diag(hir_analysis_inherent_nominal, code = "E0118")] +#[diag(hir_analysis_inherent_nominal, code = E0118)] #[note] pub struct InherentNominal { #[primary_span] @@ -1136,7 +1136,7 @@ pub struct InherentNominal { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_zst, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_zst, code = E0378)] #[note] pub struct DispatchFromDynZST<'a> { #[primary_span] @@ -1146,7 +1146,7 @@ pub struct DispatchFromDynZST<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct DispatchFromDynSingle<'a> { #[primary_span] pub span: Span, @@ -1156,7 +1156,7 @@ pub struct DispatchFromDynSingle<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_multi, code = "E0378")] +#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)] #[note] pub struct DispatchFromDynMulti { #[primary_span] @@ -1168,7 +1168,7 @@ pub struct DispatchFromDynMulti { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0376")] +#[diag(hir_analysis_coerce_unsized_may, code = E0376)] pub struct DispatchFromDynStruct<'a> { #[primary_span] pub span: Span, @@ -1176,7 +1176,7 @@ pub struct DispatchFromDynStruct<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0377")] +#[diag(hir_analysis_coerce_unsized_may, code = E0377)] pub struct DispatchFromDynSame<'a> { #[primary_span] pub span: Span, @@ -1188,7 +1188,7 @@ pub struct DispatchFromDynSame<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0374")] +#[diag(hir_analysis_coerce_unsized_may, code = E0374)] pub struct CoerceUnsizedOneField<'a> { #[primary_span] pub span: Span, @@ -1198,7 +1198,7 @@ pub struct CoerceUnsizedOneField<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_multi, code = "E0375")] +#[diag(hir_analysis_coerce_unsized_multi, code = E0375)] #[note] pub struct CoerceUnsizedMulti { #[primary_span] @@ -1211,7 +1211,7 @@ pub struct CoerceUnsizedMulti { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = "E0378")] +#[diag(hir_analysis_coerce_unsized_may, code = E0378)] pub struct CoerceUnsizedMay<'a> { #[primary_span] pub span: Span, @@ -1219,7 +1219,7 @@ pub struct CoerceUnsizedMay<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_trait_cannot_impl_for_ty, code = "E0204")] +#[diag(hir_analysis_trait_cannot_impl_for_ty, code = E0204)] pub struct TraitCannotImplForTy { #[primary_span] pub span: Span, @@ -1241,7 +1241,7 @@ pub struct ImplForTyRequires { } #[derive(Diagnostic)] -#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")] +#[diag(hir_analysis_traits_with_defualt_impl, code = E0321)] #[note] pub struct TraitsWithDefaultImpl<'a> { #[primary_span] @@ -1252,7 +1252,7 @@ pub struct TraitsWithDefaultImpl<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cross_crate_traits, code = "E0321")] +#[diag(hir_analysis_cross_crate_traits, code = E0321)] pub struct CrossCrateTraits<'a> { #[primary_span] #[label] @@ -1262,7 +1262,7 @@ pub struct CrossCrateTraits<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")] +#[diag(hir_analysis_cross_crate_traits_defined, code = E0321)] pub struct CrossCrateTraitsDefined { #[primary_span] #[label] @@ -1271,7 +1271,7 @@ pub struct CrossCrateTraitsDefined { } #[derive(Diagnostic)] -#[diag(hir_analysis_ty_param_first_local, code = "E0210")] +#[diag(hir_analysis_ty_param_first_local, code = E0210)] #[note] pub struct TyParamFirstLocal<'a> { #[primary_span] @@ -1284,7 +1284,7 @@ pub struct TyParamFirstLocal<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_ty_param_some, code = "E0210")] +#[diag(hir_analysis_ty_param_some, code = E0210)] #[note] pub struct TyParamSome<'a> { #[primary_span] @@ -1297,7 +1297,7 @@ pub struct TyParamSome<'a> { #[derive(Diagnostic)] pub enum OnlyCurrentTraits<'a> { - #[diag(hir_analysis_only_current_traits_outside, code = "E0117")] + #[diag(hir_analysis_only_current_traits_outside, code = E0117)] Outside { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1317,7 +1317,7 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>, }, - #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")] + #[diag(hir_analysis_only_current_traits_primitive, code = E0117)] Primitive { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1337,7 +1337,7 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>, }, - #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")] + #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] Arbitrary { #[primary_span] #[label(hir_analysis_only_current_traits_label)] @@ -1412,7 +1412,7 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[diag(hir_analysis_static_mut_ref, code = E0796)] #[note] pub struct StaticMutRef { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 2fe08ead72b..c072891e295 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -12,7 +12,7 @@ use crate::constrained_generic_params as cgp; use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs index b061d637138..6846e4defe5 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors.rs @@ -6,18 +6,18 @@ pub use self::{ missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, }; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, ErrCode}; use rustc_session::Session; pub trait StructuredDiagnostic<'tcx> { fn session(&self) -> &Session; - fn code(&self) -> String; + fn code(&self) -> ErrCode; fn diagnostic(&self) -> DiagnosticBuilder<'tcx> { let err = self.diagnostic_common(); - if self.session().teach(&self.code()) { + if self.session().teach(self.code()) { self.diagnostic_extended(err) } else { self.diagnostic_regular(err) diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs index 6f4435db411..50b4ef623ac 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -16,8 +16,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> { self.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0617) + fn code(&self) -> ErrCode { + E0617 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs index 19cac4a38aa..54d54a2af93 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs @@ -1,5 +1,5 @@ use crate::{errors, structured_errors::StructuredDiagnostic}; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_span::Span; @@ -16,8 +16,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> { self.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0607) + fn code(&self) -> ErrCode { + E0607 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index ba81e7f1f81..501915d2e7e 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,5 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, MultiSpan, +}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_session::Session; @@ -1105,8 +1107,8 @@ impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> { self.tcx.sess } - fn code(&self) -> String { - rustc_errors::error_code!(E0107) + fn code(&self) -> ErrCode { + E0107 } fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index bd8a2024caa..a0ac839f3dd 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -33,7 +33,7 @@ use super::FnCtxt; use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{codes::*, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 858faf161f6..ca636ebcade 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,7 +36,9 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4f929068887..b75cf4b4e8b 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -3,8 +3,8 @@ use std::borrow::Cow; use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan, - SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, + MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -15,7 +15,7 @@ use rustc_span::{ }; #[derive(Diagnostic)] -#[diag(hir_typeck_field_multiply_specified_in_initializer, code = "E0062")] +#[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)] pub struct FieldMultiplySpecifiedInInitializer { #[primary_span] #[label] @@ -26,7 +26,7 @@ pub struct FieldMultiplySpecifiedInInitializer { } #[derive(Diagnostic)] -#[diag(hir_typeck_return_stmt_outside_of_fn_body, code = "E0572")] +#[diag(hir_typeck_return_stmt_outside_of_fn_body, code = E0572)] pub struct ReturnStmtOutsideOfFnBody { #[primary_span] pub span: Span, @@ -62,14 +62,14 @@ pub struct RustCallIncorrectArgs { } #[derive(Diagnostic)] -#[diag(hir_typeck_yield_expr_outside_of_coroutine, code = "E0627")] +#[diag(hir_typeck_yield_expr_outside_of_coroutine, code = E0627)] pub struct YieldExprOutsideOfCoroutine { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_typeck_struct_expr_non_exhaustive, code = "E0639")] +#[diag(hir_typeck_struct_expr_non_exhaustive, code = E0639)] pub struct StructExprNonExhaustive { #[primary_span] pub span: Span, @@ -77,7 +77,7 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")] +#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)] pub struct MethodCallOnUnknownRawPointee { #[primary_span] pub span: Span, @@ -92,14 +92,14 @@ pub struct MissingFnLangItems { } #[derive(Diagnostic)] -#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")] +#[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_typeck_address_of_temporary_taken, code = "E0745")] +#[diag(hir_typeck_address_of_temporary_taken, code = E0745)] pub struct AddressOfTemporaryTaken { #[primary_span] #[label] @@ -145,7 +145,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_explicit_destructor, code = "E0040")] +#[diag(hir_typeck_explicit_destructor, code = E0040)] pub struct ExplicitDestructorCall { #[primary_span] #[label] @@ -168,7 +168,7 @@ pub enum ExplicitDestructorCallSugg { } #[derive(Diagnostic)] -#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")] +#[diag(hir_typeck_missing_parentheses_in_range, code = E0689)] pub struct MissingParenthesesInRange { #[primary_span] #[label(hir_typeck_missing_parentheses_in_range)] @@ -321,7 +321,7 @@ impl HelpUseLatestEdition { } #[derive(Diagnostic)] -#[diag(hir_typeck_invalid_callee, code = "E0618")] +#[diag(hir_typeck_invalid_callee, code = E0618)] pub struct InvalidCallee { #[primary_span] pub span: Span, @@ -329,7 +329,7 @@ pub struct InvalidCallee { } #[derive(Diagnostic)] -#[diag(hir_typeck_int_to_fat, code = "E0606")] +#[diag(hir_typeck_int_to_fat, code = E0606)] pub struct IntToWide<'tcx> { #[primary_span] #[label(hir_typeck_int_to_fat_label)] @@ -510,7 +510,7 @@ pub struct TrivialCast<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_no_associated_item, code = "E0599")] +#[diag(hir_typeck_no_associated_item, code = E0599)] pub struct NoAssociatedItem { #[primary_span] pub span: Span, @@ -532,7 +532,7 @@ pub struct CandidateTraitNote { } #[derive(Diagnostic)] -#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")] +#[diag(hir_typeck_cannot_cast_to_bool, code = E0054)] pub struct CannotCastToBool<'tcx> { #[primary_span] pub span: Span, @@ -549,7 +549,7 @@ pub struct CastEnumDrop<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")] +#[diag(hir_typeck_cast_unknown_pointer, code = E0641)] pub struct CastUnknownPointer { #[primary_span] pub span: Span, @@ -600,7 +600,7 @@ pub enum CannotCastToBoolHelp { } #[derive(Diagnostic)] -#[diag(hir_typeck_ctor_is_private, code = "E0603")] +#[diag(hir_typeck_ctor_is_private, code = E0603)] pub struct CtorIsPrivate { #[primary_span] pub span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bc259c17b7..fafed5be8c5 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -25,8 +25,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, StashKey, + codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, + DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -527,7 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_error(tcx, e) } Res::Def(DefKind::Variant, _) => { - let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value"); + let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, E0533, "value"); Ty::new_error(tcx, e) } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, @@ -939,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_lhs_assignable( &self, lhs: &'tcx hir::Expr<'tcx>, - err_code: &'static str, + code: ErrCode, op_span: Span, adjust_err: impl FnOnce(&mut Diagnostic), ) { @@ -948,7 +948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut err = self.dcx().struct_span_err(op_span, "invalid left-hand side of assignment"); - err.code(err_code.into()); + err.code(code); err.span_label(lhs.span, "cannot assign to this expression"); self.comes_from_while_condition(lhs.hir_id, |expr| { @@ -1244,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diag.emit(); } - self.check_lhs_assignable(lhs, "E0070", span, |err| { + self.check_lhs_assignable(lhs, E0070, span, |err| { if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) { suggest_deref_binop(err, rhs_ty); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 6a77450f075..2494feee1ff 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -12,7 +12,9 @@ use crate::{ use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; +use rustc_errors::{ + codes::*, pluralize, Applicability, Diagnostic, ErrCode, ErrorGuaranteed, MultiSpan, StashKey, +}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -177,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } - let mut err_code = "E0061"; + let mut err_code = E0061; // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { @@ -187,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Tuple(arg_types) => { // Argument length differs if arg_types.len() != provided_args.len() { - err_code = "E0057"; + err_code = E0057; } let expected_input_tys = match expected_input_tys { Some(expected_input_tys) => match expected_input_tys.get(0) { @@ -358,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if c_variadic && provided_arg_count < minimum_input_count { - err_code = "E0060"; + err_code = E0060; } for arg in provided_args.iter().skip(minimum_input_count) { @@ -443,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, c_variadic: bool, - err_code: &str, + err_code: ErrCode, fn_def_id: Option<DefId>, call_span: Span, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 18f547be2a7..449de631f5a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -369,6 +369,14 @@ pub struct LoweredTy<'tcx> { impl<'tcx> LoweredTy<'tcx> { pub fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> { - LoweredTy { raw, normalized: fcx.normalize(span, raw) } + // FIXME(-Znext-solver): We're still figuring out how to best handle + // normalization and this doesn't feel too great. We should look at this + // code again before stabilizing it. + let normalized = if fcx.next_trait_solver() { + fcx.try_structurally_resolve_type(span, raw) + } else { + fcx.normalize(span, raw) + }; + LoweredTy { raw, normalized } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 7780ceda1c1..95c1139e43e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2040,7 +2040,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_is_local = sole_field.did.is_local(); let field_is_accessible = sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) - // Skip suggestions for unstable public fields (for example `Pin::pointer`) + // Skip suggestions for unstable public fields (for example `Pin::__pointer`) && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); if !field_is_local && !field_is_accessible { @@ -2140,46 +2140,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; - let (adt, unwrap) = match expected.kind() { + let (adt, substs, unwrap) = match expected.kind() { // In case Option<NonZero*> is wanted, but * is provided, suggest calling new - ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { - // Unwrap option - let ty::Adt(adt, _) = args.type_at(0).kind() else { + ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + let nonzero_type = substs.type_at(0); // Unwrap option type. + let ty::Adt(adt, substs) = nonzero_type.kind() else { return false; }; - - (adt, "") + (adt, substs, "") } - // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types - ty::Adt(adt, _) => (adt, ".unwrap()"), + // In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types. + ty::Adt(adt, substs) => (adt, substs, ".unwrap()"), _ => return false, }; - let map = [ - (sym::NonZeroU8, tcx.types.u8), - (sym::NonZeroU16, tcx.types.u16), - (sym::NonZeroU32, tcx.types.u32), - (sym::NonZeroU64, tcx.types.u64), - (sym::NonZeroU128, tcx.types.u128), - (sym::NonZeroI8, tcx.types.i8), - (sym::NonZeroI16, tcx.types.i16), - (sym::NonZeroI32, tcx.types.i32), - (sym::NonZeroI64, tcx.types.i64), - (sym::NonZeroI128, tcx.types.i128), + if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + return false; + } + + // FIXME: This can be simplified once `NonZero<T>` is stable. + let coercable_types = [ + ("NonZeroU8", tcx.types.u8), + ("NonZeroU16", tcx.types.u16), + ("NonZeroU32", tcx.types.u32), + ("NonZeroU64", tcx.types.u64), + ("NonZeroU128", tcx.types.u128), + ("NonZeroI8", tcx.types.i8), + ("NonZeroI16", tcx.types.i16), + ("NonZeroI32", tcx.types.i32), + ("NonZeroI64", tcx.types.i64), + ("NonZeroI128", tcx.types.i128), ]; - let Some((s, _)) = map.iter().find(|&&(s, t)| { - self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t) + let int_type = substs.type_at(0); + + let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None } }) else { return false; }; - let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); - err.multipart_suggestion( - format!("consider calling `{s}::new`"), + format!("consider calling `{nonzero_alias}::new`"), vec![ - (expr.span.shrink_to_lo(), format!("{path}::new(")), + (expr.span.shrink_to_lo(), format!("{nonzero_alias}::new(")), (expr.span.shrink_to_hi(), format!("){unwrap}")), ], Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index e087733130e..2dee5093e87 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -1,5 +1,5 @@ use hir::HirId; -use rustc_errors::struct_span_code_err; +use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 36cd6583147..36aa949668f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -51,7 +51,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::LoweredTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrCode, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -71,7 +71,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[macro_export] macro_rules! type_error_struct { - ($dcx:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + ($dcx:expr, $span:expr, $typ:expr, $code:expr, $($message:tt)*) => ({ let mut err = rustc_errors::struct_span_code_err!($dcx, $span, $code, $($message)*); if $typ.references_error() { @@ -375,7 +375,7 @@ fn report_unexpected_variant_res( res: Res, qpath: &hir::QPath<'_>, span: Span, - err_code: &str, + err_code: ErrCode, expected: &str, ) -> ErrorGuaranteed { let res_descr = match res { @@ -386,9 +386,9 @@ fn report_unexpected_variant_res( let err = tcx .dcx() .struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`")) - .with_code(err_code.into()); + .with_code(err_code); match res { - Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => { + Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == E0164 => { let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html"; err.with_span_label(span, "`fn` calls are not allowed in patterns") .with_help(format!("for more information, visit {patterns_url}")) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b8a25eedaf..314d28e6e04 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3,17 +3,16 @@ // ignore-tidy-filelength -use crate::errors; -use crate::errors::{CandidateTraitNote, NoAssociatedItem}; +use crate::errors::{self, CandidateTraitNote, NoAssociatedItem}; use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_attr::parse_confusables; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::StashKey; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -1601,23 +1600,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ty_to_value_string(rcvr_ty.peel_refs()) }; if let SelfSource::MethodCall(_) = source { - let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) - && let Some(assoc) = self.associated_value(*impl_did, item_name) - && assoc.kind == ty::AssocKind::Fn - { + let first_arg = static_candidates.get(0).and_then(|candidate_source| { + let (assoc_did, self_ty) = match candidate_source { + CandidateSource::Impl(impl_did) => { + (*impl_did, self.tcx.type_of(*impl_did).instantiate_identity()) + } + CandidateSource::Trait(trait_did) => (*trait_did, rcvr_ty), + }; + + let assoc = self.associated_value(assoc_did, item_name)?; + if assoc.kind != ty::AssocKind::Fn { + return None; + } + + // for CandidateSource::Impl, `Self` will be instantiated to a concrete type + // but for CandidateSource::Trait, `Self` is still `Self` let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity(); sig.inputs().skip_binder().get(0).and_then(|first| { - let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); // if the type of first arg is the same as the current impl type, we should take the first arg into assoc function - if first.peel_refs() == impl_ty { + let first_ty = first.peel_refs(); + if first_ty == self_ty || first_ty == self.tcx.types.self_param { Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) } else { None } }) - } else { - None - }; + }); + let mut applicability = Applicability::MachineApplicable; let args = if let SelfSource::MethodCall(receiver) = source && let Some(args) = args diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index ff82e2d653c..bbe6d9e9670 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -5,7 +5,7 @@ use super::{has_expected_num_generic_args, FnCtxt}; use crate::Expectation; use rustc_ast as ast; use rustc_data_structures::packed::Pu128; -use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -44,7 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_ty }; - self.check_lhs_assignable(lhs, "E0067", op.span, |err| { + self.check_lhs_assignable(lhs, E0067, op.span, |err| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { if self .lookup_op_method( diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e31eeab4c4a..a611d0eda85 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -3,8 +3,8 @@ use crate::{errors, FnCtxt, LoweredTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if (lhs, rhs).references_error() { err.downgrade_to_delayed_bug(); } - if self.tcx.sess.teach(&err.get_code().unwrap()) { + if self.tcx.sess.teach(err.get_code().unwrap()) { err.note( "In a match expression, only numbers and characters can be matched \ against a range. This is because the compiler checks that the range \ @@ -847,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type_str ); err.span_label(span, format!("type `{type_str}` cannot be dereferenced")); - if self.tcx.sess.teach(&err.get_code().unwrap()) { + if self.tcx.sess.teach(err.get_code().unwrap()) { err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ); } return Err(err.emit()); @@ -907,7 +907,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected); return Ty::new_error(tcx, e); } Res::SelfCtor(..) @@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let report_unexpected_res = |res: Res| { let expected = "tuple struct or tuple variant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0164", expected); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0164, expected); on_error(e); e }; @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if tcx.sess.teach(&err.get_code().unwrap()) { + if tcx.sess.teach(err.get_code().unwrap()) { err.note( "This error indicates that a struct pattern attempted to \ extract a nonexistent field from a struct. Struct fields \ diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index d3cf267dc9d..0c1180b3e98 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -236,6 +236,12 @@ impl<I: Idx> IntervalSet<I> { I: Step, { assert_eq!(self.domain, other.domain); + if self.map.len() < other.map.len() { + let backup = self.clone(); + self.map.clone_from(&other.map); + return self.union(&backup); + } + let mut did_insert = false; for range in other.iter_intervals() { did_insert |= self.insert_range(range); diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 66c5cc774b2..d876174e620 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -12,10 +12,13 @@ use std::vec; use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. +/// Its purpose is to avoid mixing indexes. /// /// While it's possible to use `u32` or `usize` directly for `I`, /// you almost certainly want to use a [`newtype_index!`]-generated type instead. /// +/// This allows to index the IndexVec with the new index type. +/// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -25,11 +28,13 @@ pub struct IndexVec<I: Idx, T> { } impl<I: Idx, T> IndexVec<I, T> { + /// Constructs a new, empty `IndexVec<I, T>`. #[inline] pub const fn new() -> Self { IndexVec::from_raw(Vec::new()) } + /// Constructs a new `IndexVec<I, T>` from a `Vec<T>`. #[inline] pub const fn from_raw(raw: Vec<T>) -> Self { IndexVec { raw, _marker: PhantomData } @@ -59,6 +64,7 @@ impl<I: Idx, T> IndexVec<I, T> { IndexVec::from_raw(vec![elem; universe.len()]) } + /// Creates a new IndexVec with n copies of the `elem`. #[inline] pub fn from_elem_n(elem: T, n: usize) -> Self where @@ -85,6 +91,7 @@ impl<I: Idx, T> IndexVec<I, T> { IndexSlice::from_raw_mut(&mut self.raw) } + /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index aee99063e03..4e9f573091b 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,7 +1,7 @@ use hir::GenericParamKind; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, - IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, + DiagnosticStyledString, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; use rustc_hir as hir; use rustc_hir::FnRetTy; @@ -33,7 +33,7 @@ pub struct OpaqueHiddenTypeDiag { } #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0282")] +#[diag(infer_type_annotations_needed, code = E0282)] pub struct AnnotationRequired<'a> { #[primary_span] pub span: Span, @@ -51,7 +51,7 @@ pub struct AnnotationRequired<'a> { // Copy of `AnnotationRequired` for E0283 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0283")] +#[diag(infer_type_annotations_needed, code = E0283)] pub struct AmbiguousImpl<'a> { #[primary_span] pub span: Span, @@ -69,7 +69,7 @@ pub struct AmbiguousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0284")] +#[diag(infer_type_annotations_needed, code = E0284)] pub struct AmbiguousReturn<'a> { #[primary_span] pub span: Span, @@ -421,7 +421,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { } #[derive(Diagnostic)] -#[diag(infer_lifetime_mismatch, code = "E0623")] +#[diag(infer_lifetime_mismatch, code = E0623)] pub struct LifetimeMismatch<'a> { #[primary_span] pub span: Span, @@ -495,7 +495,7 @@ pub struct MismatchedStaticLifetime<'a> { #[derive(Diagnostic)] pub enum ExplicitLifetimeRequired<'a> { - #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)] WithIdent { #[primary_span] #[label] @@ -511,7 +511,7 @@ pub enum ExplicitLifetimeRequired<'a> { #[skip_arg] new_ty: Ty<'a>, }, - #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)] WithParamType { #[primary_span] #[label] @@ -819,7 +819,7 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion { } #[derive(Diagnostic)] -#[diag(infer_but_calling_introduces, code = "E0772")] +#[diag(infer_but_calling_introduces, code = E0772)] pub struct ButCallingIntroduces { #[label(infer_label1)] pub param_ty_span: Span, @@ -871,14 +871,14 @@ impl AddToDiagnostic for MoreTargeted { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.code(rustc_errors::error_code!(E0772)); + diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); diag.arg("ident", self.ident); } } #[derive(Diagnostic)] -#[diag(infer_but_needs_to_satisfy, code = "E0759")] +#[diag(infer_but_needs_to_satisfy, code = E0759)] pub struct ButNeedsToSatisfy { #[primary_span] pub sp: Span, @@ -904,7 +904,7 @@ pub struct ButNeedsToSatisfy { } #[derive(Diagnostic)] -#[diag(infer_outlives_content, code = "E0312")] +#[diag(infer_outlives_content, code = E0312)] pub struct OutlivesContent<'a> { #[primary_span] pub span: Span, @@ -913,7 +913,7 @@ pub struct OutlivesContent<'a> { } #[derive(Diagnostic)] -#[diag(infer_outlives_bound, code = "E0476")] +#[diag(infer_outlives_bound, code = E0476)] pub struct OutlivesBound<'a> { #[primary_span] pub span: Span, @@ -922,7 +922,7 @@ pub struct OutlivesBound<'a> { } #[derive(Diagnostic)] -#[diag(infer_fulfill_req_lifetime, code = "E0477")] +#[diag(infer_fulfill_req_lifetime, code = E0477)] pub struct FulfillReqLifetime<'a> { #[primary_span] pub span: Span, @@ -932,7 +932,7 @@ pub struct FulfillReqLifetime<'a> { } #[derive(Diagnostic)] -#[diag(infer_lf_bound_not_satisfied, code = "E0478")] +#[diag(infer_lf_bound_not_satisfied, code = E0478)] pub struct LfBoundNotSatisfied<'a> { #[primary_span] pub span: Span, @@ -941,7 +941,7 @@ pub struct LfBoundNotSatisfied<'a> { } #[derive(Diagnostic)] -#[diag(infer_ref_longer_than_data, code = "E0491")] +#[diag(infer_ref_longer_than_data, code = E0491)] pub struct RefLongerThanData<'a> { #[primary_span] pub span: Span, @@ -1117,7 +1117,7 @@ pub enum PlaceholderRelationLfNotSatisfied { } #[derive(Diagnostic)] -#[diag(infer_opaque_captures_lifetime, code = "E0700")] +#[diag(infer_opaque_captures_lifetime, code = E0700)] pub struct OpaqueCapturesLifetime<'tcx> { #[primary_span] pub span: Span, @@ -1378,73 +1378,73 @@ pub enum TypeErrorAdditionalDiags { #[derive(Diagnostic)] pub enum ObligationCauseFailureCode { - #[diag(infer_oc_method_compat, code = "E0308")] + #[diag(infer_oc_method_compat, code = E0308)] MethodCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_type_compat, code = "E0308")] + #[diag(infer_oc_type_compat, code = E0308)] TypeCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_const_compat, code = "E0308")] + #[diag(infer_oc_const_compat, code = E0308)] ConstCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_try_compat, code = "E0308")] + #[diag(infer_oc_try_compat, code = E0308)] TryCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_match_compat, code = "E0308")] + #[diag(infer_oc_match_compat, code = E0308)] MatchCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_if_else_different, code = "E0308")] + #[diag(infer_oc_if_else_different, code = E0308)] IfElseDifferent { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_no_else, code = "E0317")] + #[diag(infer_oc_no_else, code = E0317)] NoElse { #[primary_span] span: Span, }, - #[diag(infer_oc_no_diverge, code = "E0308")] + #[diag(infer_oc_no_diverge, code = E0308)] NoDiverge { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_fn_main_correct_type, code = "E0580")] + #[diag(infer_oc_fn_main_correct_type, code = E0580)] FnMainCorrectType { #[primary_span] span: Span, }, - #[diag(infer_oc_fn_start_correct_type, code = "E0308")] + #[diag(infer_oc_fn_start_correct_type, code = E0308)] FnStartCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_fn_lang_correct_type, code = "E0308")] + #[diag(infer_oc_fn_lang_correct_type, code = E0308)] FnLangCorrectType { #[primary_span] span: Span, @@ -1452,33 +1452,33 @@ pub enum ObligationCauseFailureCode { subdiags: Vec<TypeErrorAdditionalDiags>, lang_item_name: Symbol, }, - #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] + #[diag(infer_oc_intrinsic_correct_type, code = E0308)] IntrinsicCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_method_correct_type, code = "E0308")] + #[diag(infer_oc_method_correct_type, code = E0308)] MethodCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_closure_selfref, code = "E0644")] + #[diag(infer_oc_closure_selfref, code = E0644)] ClosureSelfref { #[primary_span] span: Span, }, - #[diag(infer_oc_cant_coerce, code = "E0308")] + #[diag(infer_oc_cant_coerce, code = E0308)] CantCoerce { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_generic, code = "E0308")] + #[diag(infer_oc_generic, code = E0308)] Generic { #[primary_span] span: Span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 7882e761a0c..e19177fccef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -60,7 +60,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - error_code, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, + codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, }; use rustc_hir as hir; @@ -2362,9 +2362,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), - ty::ReStatic => error_code!(E0310), - _ => error_code!(E0311), + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309, + ty::ReStatic => E0310, + _ => E0311, }); '_explain: { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 03c8e08aa01..cf1e042c529 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -5,7 +5,7 @@ use crate::errors::{ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{DiagnosticBuilder, IntoDiagnosticArg}; +use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -43,12 +43,12 @@ pub enum TypeAnnotationNeeded { E0284, } -impl Into<String> for TypeAnnotationNeeded { - fn into(self) -> String { +impl Into<ErrCode> for TypeAnnotationNeeded { + fn into(self) -> ErrCode { match self { - Self::E0282 => rustc_errors::error_code!(E0282), - Self::E0283 => rustc_errors::error_code!(E0283), - Self::E0284 => rustc_errors::error_code!(E0284), + Self::E0282 => E0282, + Self::E0283 => E0283, + Self::E0284 => E0284, } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 21ea48c6c83..0e7c641e0e0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } diag.help("type parameters must be constrained to match other types"); - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.get_code().unwrap()) { diag.help( "given a type parameter `T` and a method `foo`: ``` @@ -678,7 +678,7 @@ impl<T> Trait<T> for X { https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.get_code().unwrap()) { diag.help( "given an associated type `T` and a method `foo`: ``` diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 6f218019dee..eabc1b953af 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,7 +2,7 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Map; diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 0a632c4d12a..03d178eb266 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -80,12 +80,12 @@ impl EscapeError { } } -/// Takes a contents of a literal (without quotes) and produces a sequence of -/// escaped characters or errors. +/// Takes the contents of a unicode-only (non-mixed-utf8) literal (without +/// quotes) and produces a sequence of escaped characters or errors. /// /// Values are returned by invoking `callback`. For `Char` and `Byte` modes, /// the callback will be called exactly once. -pub fn unescape_literal<F>(src: &str, mode: Mode, callback: &mut F) +pub fn unescape_unicode<F>(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range<usize>, Result<char, EscapeError>), { @@ -97,50 +97,63 @@ where } Str | ByteStr => unescape_non_raw_common(src, mode, callback), RawStr | RawByteStr => check_raw_common(src, mode, callback), - CStr | RawCStr => unreachable!(), + RawCStr => check_raw_common(src, mode, &mut |r, mut result| { + if let Ok('\0') = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result) + }), + CStr => unreachable!(), } } -/// A unit within CStr. Must not be a nul character. -pub enum CStrUnit { - Byte(u8), +/// Used for mixed utf8 string literals, i.e. those that allow both unicode +/// chars and high bytes. +pub enum MixedUnit { + /// Used for ASCII chars (written directly or via `\x00`..`\x7f` escapes) + /// and Unicode chars (written directly or via `\u` escapes). + /// + /// For example, if '¥' appears in a string it is represented here as + /// `MixedUnit::Char('¥')`, and it will be appended to the relevant byte + /// string as the two-byte UTF-8 sequence `[0xc2, 0xa5]` Char(char), + + /// Used for high bytes (`\x80`..`\xff`). + /// + /// For example, if `\xa5` appears in a string it is represented here as + /// `MixedUnit::HighByte(0xa5)`, and it will be appended to the relevant + /// byte string as the single byte `0xa5`. + HighByte(u8), } -impl From<u8> for CStrUnit { - fn from(value: u8) -> Self { - CStrUnit::Byte(value) +impl From<char> for MixedUnit { + fn from(c: char) -> Self { + MixedUnit::Char(c) } } -impl From<char> for CStrUnit { - fn from(value: char) -> Self { - CStrUnit::Char(value) +impl From<u8> for MixedUnit { + fn from(n: u8) -> Self { + if n.is_ascii() { MixedUnit::Char(n as char) } else { MixedUnit::HighByte(n) } } } -pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F) +/// Takes the contents of a mixed-utf8 literal (without quotes) and produces +/// a sequence of escaped characters or errors. +/// +/// Values are returned by invoking `callback`. +pub fn unescape_mixed<F>(src: &str, mode: Mode, callback: &mut F) where - F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>), + F: FnMut(Range<usize>, Result<MixedUnit, EscapeError>), { match mode { - CStr => { - unescape_non_raw_common(src, mode, &mut |r, mut result| { - if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result { - result = Err(EscapeError::NulInCStr); - } - callback(r, result) - }); - } - RawCStr => { - check_raw_common(src, mode, &mut |r, mut result| { - if let Ok('\0') = result { - result = Err(EscapeError::NulInCStr); - } - callback(r, result.map(CStrUnit::Char)) - }); - } - Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(), + CStr => unescape_non_raw_common(src, mode, &mut |r, mut result| { + if let Ok(MixedUnit::Char('\0')) = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result) + }), + Char | Byte | Str | RawStr | ByteStr | RawByteStr | RawCStr => unreachable!(), } } @@ -181,29 +194,29 @@ impl Mode { } } - /// Non-byte literals should have `\xXX` escapes that are within the ASCII range. - fn ascii_escapes_should_be_ascii(self) -> bool { + /// Are `\x80`..`\xff` allowed? + fn allow_high_bytes(self) -> bool { match self { - Char | Str => true, - Byte | ByteStr | CStr => false, + Char | Str => false, + Byte | ByteStr | CStr => true, RawStr | RawByteStr | RawCStr => unreachable!(), } } - /// Whether characters within the literal must be within the ASCII range. + /// Are unicode (non-ASCII) chars allowed? #[inline] - fn chars_should_be_ascii(self) -> bool { + fn allow_unicode_chars(self) -> bool { match self { - Byte | ByteStr | RawByteStr => true, - Char | Str | RawStr | CStr | RawCStr => false, + Byte | ByteStr | RawByteStr => false, + Char | Str | RawStr | CStr | RawCStr => true, } } - /// Byte literals do not allow unicode escape. - fn is_unicode_escape_disallowed(self) -> bool { + /// Are unicode escapes (`\u`) allowed? + fn allow_unicode_escapes(self) -> bool { match self { - Byte | ByteStr => true, - Char | Str | CStr => false, + Byte | ByteStr => false, + Char | Str | CStr => true, RawByteStr | RawStr | RawCStr => unreachable!(), } } @@ -217,20 +230,19 @@ impl Mode { } } -fn scan_escape<T: From<u8> + From<char>>( +fn scan_escape<T: From<char> + From<u8>>( chars: &mut Chars<'_>, mode: Mode, ) -> Result<T, EscapeError> { // Previous character was '\\', unescape what follows. - let res = match chars.next().ok_or(EscapeError::LoneSlash)? { - '"' => b'"', - 'n' => b'\n', - 'r' => b'\r', - 't' => b'\t', - '\\' => b'\\', - '\'' => b'\'', - '0' => b'\0', - + let res: char = match chars.next().ok_or(EscapeError::LoneSlash)? { + '"' => '"', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + '\\' => '\\', + '\'' => '\'', + '0' => '\0', 'x' => { // Parse hexadecimal character code. @@ -240,25 +252,23 @@ fn scan_escape<T: From<u8> + From<char>>( let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?; let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; - let value = hi * 16 + lo; - - if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) { - return Err(EscapeError::OutOfRangeHexEscape); - } + let value = (hi * 16 + lo) as u8; - value as u8 + return if !mode.allow_high_bytes() && !value.is_ascii() { + Err(EscapeError::OutOfRangeHexEscape) + } else { + // This may be a high byte, but that will only happen if `T` is + // `MixedUnit`, because of the `allow_high_bytes` check above. + Ok(T::from(value as u8)) + }; } - - 'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into), + 'u' => return scan_unicode(chars, mode.allow_unicode_escapes()).map(T::from), _ => return Err(EscapeError::InvalidEscape), }; - Ok(res.into()) + Ok(T::from(res)) } -fn scan_unicode( - chars: &mut Chars<'_>, - is_unicode_escape_disallowed: bool, -) -> Result<char, EscapeError> { +fn scan_unicode(chars: &mut Chars<'_>, allow_unicode_escapes: bool) -> Result<char, EscapeError> { // We've parsed '\u', now we have to parse '{..}'. if chars.next() != Some('{') { @@ -286,7 +296,7 @@ fn scan_unicode( // Incorrect syntax has higher priority for error reporting // than unallowed value for a literal. - if is_unicode_escape_disallowed { + if !allow_unicode_escapes { return Err(EscapeError::UnicodeEscapeInByte); } @@ -312,12 +322,8 @@ fn scan_unicode( } #[inline] -fn ascii_check(c: char, chars_should_be_ascii: bool) -> Result<char, EscapeError> { - if chars_should_be_ascii && !c.is_ascii() { - Err(EscapeError::NonAsciiCharInByte) - } else { - Ok(c) - } +fn ascii_check(c: char, allow_unicode_chars: bool) -> Result<char, EscapeError> { + if allow_unicode_chars || c.is_ascii() { Ok(c) } else { Err(EscapeError::NonAsciiCharInByte) } } fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { @@ -326,7 +332,7 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, Esca '\\' => scan_escape(chars, mode), '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), '\r' => Err(EscapeError::BareCarriageReturn), - _ => ascii_check(c, mode.chars_should_be_ascii()), + _ => ascii_check(c, mode.allow_unicode_chars()), }?; if chars.next().is_some() { return Err(EscapeError::MoreThanOneChar); @@ -336,12 +342,12 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, Esca /// Takes a contents of a string literal (without quotes) and produces a /// sequence of escaped characters or errors. -fn unescape_non_raw_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F) +fn unescape_non_raw_common<F, T: From<char> + From<u8>>(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range<usize>, Result<T, EscapeError>), { let mut chars = src.chars(); - let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop + let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop // The `start` and `end` computation here is complicated because // `skip_ascii_whitespace` makes us to skip over chars without counting @@ -366,7 +372,7 @@ where } '"' => Err(EscapeError::EscapeOnlyChar), '\r' => Err(EscapeError::BareCarriageReturn), - _ => ascii_check(c, chars_should_be_ascii).map(Into::into), + _ => ascii_check(c, allow_unicode_chars).map(T::from), }; let end = src.len() - chars.as_str().len(); callback(start..end, res); @@ -408,7 +414,7 @@ where F: FnMut(Range<usize>, Result<char, EscapeError>), { let mut chars = src.chars(); - let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop + let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop // The `start` and `end` computation here matches the one in // `unescape_non_raw_common` for consistency, even though this function @@ -417,7 +423,7 @@ where let start = src.len() - chars.as_str().len() - c.len_utf8(); let res = match c { '\r' => Err(EscapeError::BareCarriageReturnInRawString), - _ => ascii_check(c, chars_should_be_ascii), + _ => ascii_check(c, allow_unicode_chars), }; let end = src.len() - chars.as_str().len(); callback(start..end, res); @@ -430,7 +436,3 @@ pub fn byte_from_char(c: char) -> u8 { debug_assert!(res <= u8::MAX as u32, "guaranteed because of ByteStr"); res as u8 } - -fn is_ascii(x: u32) -> bool { - x <= 0x7F -} diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs index 1c25b03fdb2..5b99495f475 100644 --- a/compiler/rustc_lexer/src/unescape/tests.rs +++ b/compiler/rustc_lexer/src/unescape/tests.rs @@ -100,7 +100,7 @@ fn test_unescape_char_good() { fn test_unescape_str_warn() { fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::Str, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } @@ -124,7 +124,7 @@ fn test_unescape_str_warn() { fn test_unescape_str_good() { fn check(literal_text: &str, expected: &str) { let mut buf = Ok(String::with_capacity(literal_text.len())); - unescape_literal(literal_text, Mode::Str, &mut |range, c| { + unescape_unicode(literal_text, Mode::Str, &mut |range, c| { if let Ok(b) = &mut buf { match c { Ok(c) => b.push(c), @@ -241,7 +241,7 @@ fn test_unescape_byte_good() { fn test_unescape_byte_str_good() { fn check(literal_text: &str, expected: &[u8]) { let mut buf = Ok(Vec::with_capacity(literal_text.len())); - unescape_literal(literal_text, Mode::ByteStr, &mut |range, c| { + unescape_unicode(literal_text, Mode::ByteStr, &mut |range, c| { if let Ok(b) = &mut buf { match c { Ok(c) => b.push(byte_from_char(c)), @@ -264,7 +264,7 @@ fn test_unescape_byte_str_good() { fn test_unescape_raw_str() { fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } @@ -276,7 +276,7 @@ fn test_unescape_raw_str() { fn test_unescape_raw_byte_str() { fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) { let mut unescaped = Vec::with_capacity(literal.len()); - unescape_literal(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res))); + unescape_unicode(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res))); assert_eq!(unescaped, expected); } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 841d282a099..3bd0c1b8031 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,11 +1,11 @@ use crate::fluent_generated as fluent; -use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; +use rustc_errors::{codes::*, AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(lint_overruled_attribute, code = "E0453")] +#[diag(lint_overruled_attribute, code = E0453)] pub struct OverruledAttribute<'a> { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ impl AddToDiagnostic for OverruledAttributeSub { } #[derive(Diagnostic)] -#[diag(lint_malformed_attribute, code = "E0452")] +#[diag(lint_malformed_attribute, code = E0452)] pub struct MalformedAttribute { #[primary_span] pub span: Span, @@ -67,7 +67,7 @@ pub enum MalformedAttributeSub { } #[derive(Diagnostic)] -#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")] +#[diag(lint_unknown_tool_in_scoped_lint, code = E0710)] pub struct UnknownToolInScopedLint { #[primary_span] pub span: Option<Span>, @@ -78,7 +78,7 @@ pub struct UnknownToolInScopedLint { } #[derive(Diagnostic)] -#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")] +#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = E0783)] pub struct BuiltinEllipsisInclusiveRangePatterns { #[primary_span] pub span: Span, @@ -95,13 +95,13 @@ pub struct RequestedLevel<'a> { } #[derive(Diagnostic)] -#[diag(lint_unsupported_group, code = "E0602")] +#[diag(lint_unsupported_group, code = E0602)] pub struct UnsupportedGroup { pub lint_group: String, } #[derive(Diagnostic)] -#[diag(lint_check_name_unknown_tool, code = "E0602")] +#[diag(lint_check_name_unknown_tool, code = E0602)] pub struct CheckNameUnknownTool<'a> { pub tool_name: Symbol, #[subdiagnostic] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index e19bb1cb62f..f916deb4a46 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,8 +5,8 @@ use std::num::NonZeroU32; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage, - DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, + codes::*, AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, + DiagnosticMessage, DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -1065,7 +1065,7 @@ pub enum UnknownLintSuggestion { } #[derive(LintDiagnostic)] -#[diag(lint_unknown_lint, code = "E0602")] +#[diag(lint_unknown_lint, code = E0602)] pub struct UnknownLintFromCommandLine<'a> { pub name: String, #[subdiagnostic] diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index f64509fe8bc..bed5d3c80c0 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -4,7 +4,7 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable, }; -use rustc_span::Span; +use rustc_span::{symbol::kw, Span}; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -96,6 +96,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { continue; } + // HACK: `async fn() -> Self` in traits is "ok"... + // This is not really that great, but it's similar to why the `-> Self` + // return type is well-formed in traits even when `Self` isn't sized. + if let ty::Param(param_ty) = *proj_term.kind() + && param_ty.name == kw::SelfUpper + && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) + && opaque.in_trait + { + continue; + } + let proj_ty = Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args); // For every instance of the projection type in the bounds, diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 0b7ecff8148..85bb9584a05 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -209,9 +209,9 @@ impl DiagnosticDeriveVariantBuilder { if path.is_ident("code") { self.code.set_once((), path.span().unwrap()); - let code = nested.parse::<syn::LitStr>()?; + let code = nested.parse::<syn::Expr>()?; tokens.extend(quote! { - diag.code(#code.to_string()); + diag.code(#code); }); } else { span_err(path.span().unwrap(), "unknown argument") diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 135b9e32fe7..33dffe6998a 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -20,7 +20,7 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(Diagnostic)] -/// #[diag(borrowck_move_out_of_borrow, code = "E0505")] +/// #[diag(borrowck_move_out_of_borrow, code = E0505)] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 27c26d31781..d17bf0cf708 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -4,7 +4,7 @@ use std::{ }; use rustc_errors::{ - error_code, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, + codes::*, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::Diagnostic; use rustc_session::config; @@ -122,7 +122,7 @@ pub struct WasmImportForm { } #[derive(Diagnostic)] -#[diag(metadata_empty_link_name, code = "E0454")] +#[diag(metadata_empty_link_name, code = E0454)] pub struct EmptyLinkName { #[primary_span] #[label] @@ -130,21 +130,21 @@ pub struct EmptyLinkName { } #[derive(Diagnostic)] -#[diag(metadata_link_framework_apple, code = "E0455")] +#[diag(metadata_link_framework_apple, code = E0455)] pub struct LinkFrameworkApple { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata_framework_only_windows, code = "E0455")] +#[diag(metadata_framework_only_windows, code = E0455)] pub struct FrameworkOnlyWindows { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata_unknown_link_kind, code = "E0458")] +#[diag(metadata_unknown_link_kind, code = E0458)] pub struct UnknownLinkKind<'a> { #[primary_span] #[label] @@ -239,7 +239,7 @@ pub struct IncompatibleWasmLink { } #[derive(Diagnostic)] -#[diag(metadata_link_requires_name, code = "E0459")] +#[diag(metadata_link_requires_name, code = E0459)] pub struct LinkRequiresName { #[primary_span] #[label] @@ -502,7 +502,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for MultipleCandidates { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates); diag.arg("crate_name", self.crate_name); diag.arg("flavor", self.flavor); - diag.code(error_code!(E0464)); + diag.code(E0464); diag.span(self.span); for (i, candidate) in self.candidates.iter().enumerate() { diag.note(format!("candidate #{}: {}", i + 1, candidate.display())); @@ -512,7 +512,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for MultipleCandidates { } #[derive(Diagnostic)] -#[diag(metadata_symbol_conflicts_current, code = "E0519")] +#[diag(metadata_symbol_conflicts_current, code = E0519)] pub struct SymbolConflictsCurrent { #[primary_span] pub span: Span, @@ -537,7 +537,7 @@ pub struct DlError { } #[derive(Diagnostic)] -#[diag(metadata_newer_crate_version, code = "E0460")] +#[diag(metadata_newer_crate_version, code = E0460)] #[note] #[note(metadata_found_crate_versions)] pub struct NewerCrateVersion { @@ -549,7 +549,7 @@ pub struct NewerCrateVersion { } #[derive(Diagnostic)] -#[diag(metadata_no_crate_with_triple, code = "E0461")] +#[diag(metadata_no_crate_with_triple, code = E0461)] #[note(metadata_found_crate_versions)] pub struct NoCrateWithTriple<'a> { #[primary_span] @@ -561,7 +561,7 @@ pub struct NoCrateWithTriple<'a> { } #[derive(Diagnostic)] -#[diag(metadata_found_staticlib, code = "E0462")] +#[diag(metadata_found_staticlib, code = E0462)] #[note(metadata_found_crate_versions)] #[help] pub struct FoundStaticlib { @@ -573,7 +573,7 @@ pub struct FoundStaticlib { } #[derive(Diagnostic)] -#[diag(metadata_incompatible_rustc, code = "E0514")] +#[diag(metadata_incompatible_rustc, code = E0514)] #[note(metadata_found_crate_versions)] #[help] pub struct IncompatibleRustc { @@ -598,7 +598,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidMetadataFiles { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files); diag.arg("crate_name", self.crate_name); diag.arg("add_info", self.add_info); - diag.code(error_code!(E0786)); + diag.code(E0786); diag.span(self.span); for crate_rejection in self.crate_rejections { diag.note(crate_rejection); @@ -627,7 +627,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for CannotFindCrate { diag.arg("current_crate", self.current_crate); diag.arg("add_info", self.add_info); diag.arg("locator_triple", self.locator_triple.triple()); - diag.code(error_code!(E0463)); + diag.code(E0463); diag.span(self.span); if (self.crate_name == sym::std || self.crate_name == sym::core) && self.locator_triple != TargetTriple::from_triple(config::host_triple()) diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 3c553657087..e0436b38c4b 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,14 +1,14 @@ use std::borrow::Cow; use std::fmt; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage}; +use rustc_errors::{codes::*, DiagnosticArgValue, DiagnosticMessage}; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use crate::ty::Ty; #[derive(Diagnostic)] -#[diag(middle_drop_check_overflow, code = "E0320")] +#[diag(middle_drop_check_overflow, code = E0320)] #[note] pub struct DropCheckOverflow<'tcx> { #[primary_span] diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 5d6a7f75df8..b9914f6cb7a 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -221,9 +221,6 @@ pub struct ScopeTree { /// variable is declared. var_map: FxIndexMap<hir::ItemLocalId, Scope>, - /// Maps from a `NodeId` to the associated destruction scope (if any). - destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>, - /// Identifies expressions which, if captured into a temporary, ought to /// have a temporary whose lifetime extends to the end of the enclosing *block*, /// and not the enclosing *statement*. Expressions that are not present in this @@ -336,11 +333,6 @@ impl ScopeTree { let prev = self.parent_map.insert(child, p); assert!(prev.is_none()); } - - // Record the destruction scopes for later so we can query them. - if let ScopeData::Destruction = child.data { - self.destruction_scopes.insert(child.item_local_id(), child); - } } pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index a5c229879a7..a4b6c4f9c3f 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1074,6 +1074,8 @@ pub enum ProjectionElem<V, T> { /// "Downcast" to a variant of an enum or a coroutine. /// /// The included Symbol is the name of the variant, used for printing MIR. + /// + /// This operation itself is never UB, all it does is change the type of the place. Downcast(Option<Symbol>, VariantIdx), /// Like an explicit cast from an opaque type to a concrete type, but without diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 6a03bf243eb..27b48f46e75 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,7 +1,7 @@ use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index e1b998b2471..6929c8040c5 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::DiagnosticArgValue; use rustc_errors::{ - error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -138,7 +138,7 @@ pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = E0133)] #[note] pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { #[primary_span] @@ -150,7 +150,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeNameless { #[primary_span] @@ -161,7 +161,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNameless { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] @@ -175,7 +175,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[derive(Diagnostic)] #[diag( mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { @@ -187,7 +187,7 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")] +#[diag(mir_build_inline_assembly_requires_unsafe, code = E0133)] #[note] pub struct UseOfInlineAssemblyRequiresUnsafe { #[primary_span] @@ -198,7 +198,7 @@ pub struct UseOfInlineAssemblyRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -209,7 +209,7 @@ pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")] +#[diag(mir_build_initializing_type_with_requires_unsafe, code = E0133)] #[note] pub struct InitializingTypeWithRequiresUnsafe { #[primary_span] @@ -222,7 +222,7 @@ pub struct InitializingTypeWithRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -234,7 +234,7 @@ pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")] +#[diag(mir_build_mutable_static_requires_unsafe, code = E0133)] #[note] pub struct UseOfMutableStaticRequiresUnsafe { #[primary_span] @@ -245,7 +245,7 @@ pub struct UseOfMutableStaticRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -256,7 +256,7 @@ pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")] +#[diag(mir_build_extern_static_requires_unsafe, code = E0133)] #[note] pub struct UseOfExternStaticRequiresUnsafe { #[primary_span] @@ -267,7 +267,7 @@ pub struct UseOfExternStaticRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -278,7 +278,7 @@ pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")] +#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] pub struct DerefOfRawPointerRequiresUnsafe { #[primary_span] @@ -289,7 +289,7 @@ pub struct DerefOfRawPointerRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -300,7 +300,7 @@ pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_union_field_requires_unsafe, code = E0133)] #[note] pub struct AccessToUnionFieldRequiresUnsafe { #[primary_span] @@ -311,7 +311,7 @@ pub struct AccessToUnionFieldRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -322,7 +322,7 @@ pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { } #[derive(Diagnostic)] -#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -335,7 +335,7 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -347,7 +347,7 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllow } #[derive(Diagnostic)] -#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -360,7 +360,7 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, - code = "E0133" + code = E0133 )] #[note] pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { @@ -372,7 +372,7 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")] +#[diag(mir_build_call_to_fn_with_requires_unsafe, code = E0133)] #[help] pub struct CallToFunctionWithRequiresUnsafe<'a> { #[primary_span] @@ -390,7 +390,7 @@ pub struct CallToFunctionWithRequiresUnsafe<'a> { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[help] pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] @@ -468,7 +468,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { fluent::mir_build_non_exhaustive_patterns_type_not_empty, ); diag.span(self.span); - diag.code(error_code!(E0004)); + diag.code(E0004); let peeled_ty = self.ty.peel_refs(); diag.arg("ty", self.ty); diag.arg("peeled_ty", peeled_ty); @@ -539,28 +539,28 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { pub struct NonExhaustiveMatchAllArmsGuarded; #[derive(Diagnostic)] -#[diag(mir_build_static_in_pattern, code = "E0158")] +#[diag(mir_build_static_in_pattern, code = E0158)] pub struct StaticInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_assoc_const_in_pattern, code = "E0158")] +#[diag(mir_build_assoc_const_in_pattern, code = E0158)] pub struct AssocConstInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_param_in_pattern, code = "E0158")] +#[diag(mir_build_const_param_in_pattern, code = E0158)] pub struct ConstParamInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_non_const_path, code = "E0080")] +#[diag(mir_build_non_const_path, code = E0080)] pub struct NonConstPath { #[primary_span] pub span: Span, @@ -590,7 +590,7 @@ pub struct CouldNotEvalConstPattern { } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")] +#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = E0030)] pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] #[label] @@ -611,7 +611,7 @@ pub struct LiteralOutOfRange<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")] +#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = E0579)] pub struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] pub span: Span, @@ -634,7 +634,7 @@ pub struct TrailingIrrefutableLetPatterns { } #[derive(LintDiagnostic)] -#[diag(mir_build_bindings_with_variant_name, code = "E0170")] +#[diag(mir_build_bindings_with_variant_name, code = E0170)] pub struct BindingsWithVariantName { #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] pub suggestion: Option<Span>, @@ -821,7 +821,7 @@ pub struct NonPartialEqMatch<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_pattern_not_covered, code = "E0005")] +#[diag(mir_build_pattern_not_covered, code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { #[primary_span] pub span: Span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index ce75a2831a5..caf7f4227db 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -11,7 +11,7 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, + codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; @@ -47,9 +47,18 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err }; visitor.visit_expr(&thir[expr]); + let origin = match tcx.def_kind(def_id) { + DefKind::AssocFn | DefKind::Fn => "function argument", + DefKind::Closure => "closure argument", + // other types of MIR don't have function parameters, and we don't need to + // categorize those for the irrefutable check. + _ if thir.params.is_empty() => "", + kind => bug!("unexpected function parameters in THIR: {kind:?} {def_id:?}"), + }; + for param in thir.params.iter() { if let Some(box ref pattern) = param.pat { - visitor.check_binding_is_irrefutable(pattern, "function argument", None, None); + visitor.check_binding_is_irrefutable(pattern, origin, None, None); } } visitor.error diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index ff7e985bdfd..2190ad14b55 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,7 +8,7 @@ pub(crate) use self::check_match::check_match; use crate::errors::*; use crate::thir::util::UserAnnotatedTyHelpers; -use rustc_errors::error_code; +use rustc_errors::codes::*; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; @@ -209,7 +209,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { RangeEnd::Included => { self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { span, - teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), + teach: self.tcx.sess.teach(E0030).then_some(()), }) } RangeEnd::Excluded => { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d5f22b2cdbc..ad12bce9b02 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -403,12 +403,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { operand, &mut |elem, op| match elem { TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), - TrackElem::Variant(idx) => { - if op.layout.for_variant(&self.ecx, idx).abi.is_uninhabited() { - return None; - } - self.ecx.project_downcast(op, idx).ok() - } + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), TrackElem::Discriminant => { let variant = self.ecx.read_discriminant(op).ok()?; let discr_value = diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 4574cb4d28d..4ef3d47d6a6 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_errors::{ - Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, + codes::*, Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, Level, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -33,7 +33,7 @@ pub(crate) enum ConstMutate { } #[derive(Diagnostic)] -#[diag(mir_transform_unaligned_packed_ref, code = "E0793")] +#[diag(mir_transform_unaligned_packed_ref, code = E0793)] #[note] #[note(mir_transform_note_ub)] #[help] @@ -66,7 +66,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for RequiresUnsafe { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe); - diag.code("E0133".to_string()); + diag.code(E0133); diag.span(self.span); diag.span_label(self.span, self.details.label()); let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f904e0c44ea..aac8c0b3103 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -772,6 +772,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter .label = lifetime parameters cannot have default values +parse_unexpected_expr_in_pat = + expected {$is_bound -> + [true] a pattern range bound + *[false] a pattern + }, found {$is_method_call -> + [true] a method call + *[false] an expression + } + + .label = {$is_method_call -> + [true] method calls + *[false] arbitrary expressions + } are not allowed in patterns + parse_unexpected_if_with_if = unexpected `if` in the condition expression .suggestion = remove the `if` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40852048293..4e4bf9bdad9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -25,7 +25,7 @@ pub(crate) struct AmbiguousPlus { } #[derive(Diagnostic)] -#[diag(parse_maybe_recover_from_bad_type_plus, code = "E0178")] +#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)] pub(crate) struct BadTypePlus { pub ty: String, #[primary_span] @@ -807,7 +807,7 @@ pub(crate) struct InclusiveRangeMatchArrow { } #[derive(Diagnostic)] -#[diag(parse_inclusive_range_no_end, code = "E0586")] +#[diag(parse_inclusive_range_no_end, code = E0586)] #[note] pub(crate) struct InclusiveRangeNoEnd { #[primary_span] @@ -901,7 +901,7 @@ pub(crate) struct MismatchedClosingDelimiter { } #[derive(Diagnostic)] -#[diag(parse_incorrect_visibility_restriction, code = "E0704")] +#[diag(parse_incorrect_visibility_restriction, code = E0704)] #[help] pub(crate) struct IncorrectVisibilityRestriction { #[primary_span] @@ -925,7 +925,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr { } #[derive(Diagnostic)] -#[diag(parse_doc_comment_does_not_document_anything, code = "E0585")] +#[diag(parse_doc_comment_does_not_document_anything, code = E0585)] #[help] pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] @@ -1357,7 +1357,7 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] -#[diag(parse_pattern_method_param_without_body, code = "E0642")] +#[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] #[suggestion(code = "_", applicability = "machine-applicable")] @@ -1565,7 +1565,7 @@ pub(crate) struct WhereClauseBeforeTupleStructBodySugg { } #[derive(Diagnostic)] -#[diag(parse_async_fn_in_2015, code = "E0670")] +#[diag(parse_async_fn_in_2015, code = E0670)] pub(crate) struct AsyncFnIn2015 { #[primary_span] #[label] @@ -1929,7 +1929,7 @@ pub struct CrDocComment { } #[derive(Diagnostic)] -#[diag(parse_no_digits_literal, code = "E0768")] +#[diag(parse_no_digits_literal, code = E0768)] pub struct NoDigitsLiteral { #[primary_span] pub span: Span, @@ -2416,6 +2416,18 @@ pub(crate) struct ExpectedCommaAfterPatternField { } #[derive(Diagnostic)] +#[diag(parse_unexpected_expr_in_pat)] +pub(crate) struct UnexpectedExpressionInPattern { + #[primary_span] + #[label] + pub span: Span, + /// Was a `RangePatternBound` expected? + pub is_bound: bool, + /// Was the unexpected expression a `MethodCallExpression`? + pub is_method_call: bool, +} + +#[derive(Diagnostic)] #[diag(parse_unexpected_paren_in_range_pat)] pub(crate) struct UnexpectedParenInRangePat { #[primary_span] @@ -2499,7 +2511,7 @@ pub(crate) struct FnPointerCannotBeAsync { } #[derive(Diagnostic)] -#[diag(parse_nested_c_variadic_type, code = "E0743")] +#[diag(parse_nested_c_variadic_type, code = E0743)] pub(crate) struct NestedCVariadicType { #[primary_span] pub span: Span, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d7ecf577ed6..31552452676 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagCtxt, DiagnosticBuilder, StashKey}; +use rustc_errors::{codes::*, Applicability, DiagCtxt, DiagnosticBuilder, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -397,10 +397,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if !terminated { self.dcx() .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") - .with_code(error_code!(E0762)) + .with_code(E0762) .emit() } - self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' + self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { @@ -409,10 +409,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated byte constant", ) - .with_code(error_code!(E0763)) + .with_code(E0763) .emit() } - self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' + self.cook_unicode(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { @@ -421,10 +421,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start, end), "unterminated double quote string", ) - .with_code(error_code!(E0765)) + .with_code(E0765) .emit() } - self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " + self.cook_unicode(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { @@ -433,10 +433,10 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated double quote byte string", ) - .with_code(error_code!(E0766)) + .with_code(E0766) .emit() } - self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " + self.cook_unicode(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { @@ -445,16 +445,16 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.mk_sp(start + BytePos(1), end), "unterminated C string", ) - .with_code(error_code!(E0767)) + .with_code(E0767) .emit() } - self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + self.cook_mixed(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::StrRaw(n_hashes); - self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## + self.cook_unicode(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## } else { self.report_raw_str_error(start, 1); } @@ -463,7 +463,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::ByteStrRaw(n_hashes); - self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## + self.cook_unicode(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## } else { self.report_raw_str_error(start, 2); } @@ -472,7 +472,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::CStrRaw(n_hashes); - self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + self.cook_unicode(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## } else { self.report_raw_str_error(start, 2); } @@ -582,7 +582,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { ) -> ! { let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, start), "unterminated raw string"); - err.code(error_code!(E0748)); + err.code(E0748); err.span_label(self.mk_sp(start, start), "unterminated raw string"); if n_hashes > 0 { @@ -614,7 +614,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { }; let last_bpos = self.pos; let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, last_bpos), msg); - err.code(error_code!(E0758)); + err.code(E0758); let mut nested_block_comment_open_idxs = vec![]; let mut last_nested_block_comment_idxs = None; let mut content_chars = self.str_from(start).char_indices().peekable(); @@ -735,7 +735,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { } } - fn cook_quoted( + fn cook_unicode( &self, kind: token::LitKind, mode: Mode, @@ -745,13 +745,13 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_literal(src, mode, &mut |span, result| { + unescape::unescape_unicode(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) } - fn cook_c_string( + fn cook_mixed( &self, kind: token::LitKind, mode: Mode, @@ -761,7 +761,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_c_string(src, mode, &mut |span, result| { + unescape::unescape_mixed(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a92609c2c2f..98e062dd784 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -8,7 +8,7 @@ use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter, Nonterminal}; -use rustc_errors::{error_code, Diagnostic, PResult}; +use rustc_errors::{codes::*, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -61,7 +61,7 @@ impl<'a> Parser<'a> { let mut err = self .dcx() .struct_span_err(span, fluent::parse_inner_doc_comment_not_permitted); - err.code(error_code!(E0753)); + err.code(E0753); if let Some(replacement_span) = self.annotate_following_item_if_applicable( &mut err, span, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 720a610fdf5..7a24b819b5f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -23,7 +23,7 @@ use crate::parser; use crate::parser::attr::InnerAttrPolicy; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; +use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -448,12 +448,11 @@ impl<'a> Parser<'a> { }) } - let mut expected = edible + self.expected_tokens.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token)); + let mut expected = self + .expected_tokens .iter() - .chain(inedible) .cloned() - .map(TokenType::Token) - .chain(self.expected_tokens.iter().cloned()) .filter(|token| { // Filter out suggestions that suggest the same token which was found and deemed incorrect. fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool { @@ -792,13 +791,28 @@ impl<'a> Parser<'a> { && let [segment] = &attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && let Some(args_span) = attr_kind.item.args.span() - && let Ok(next_attr) = snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) + && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) + { + Ok(next_attr) => next_attr, + Err(inner_err) => { + err.cancel(); + inner_err.cancel(); + return; + } + } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind && let Some(next_attr_args_span) = next_attr_kind.item.args.span() && let [next_segment] = &next_attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg - && let Ok(next_expr) = snapshot.parse_expr() { + let next_expr = match snapshot.parse_expr() { + Ok(next_expr) => next_expr, + Err(inner_err) => { + err.cancel(); + inner_err.cancel(); + return; + } + }; // We have for sure // #[cfg(..)] // expr @@ -2927,6 +2941,22 @@ impl<'a> Parser<'a> { Ok(()) } + /// Check for exclusive ranges written as `..<` + pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> { + if maybe_lt == token::Lt + && (self.expected_tokens.contains(&TokenType::Token(token::Gt)) + || matches!(self.token.kind, token::Literal(..))) + { + err.span_suggestion( + maybe_lt.span, + "remove the `<` to write an exclusive range", + "", + Applicability::MachineApplicable, + ); + } + err + } + pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool { (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind)) && self.look_ahead(3, |tok| tok == short_kind) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ae3661a530b..c395decab12 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -444,6 +444,19 @@ impl<'a> Parser<'a> { ) if self.restrictions.contains(Restrictions::CONST_EXPR) => { return None; } + // When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`. + ( + Some( + AssocOp::Assign + | AssocOp::AssignOp(_) + | AssocOp::BitOr + | AssocOp::DotDot + | AssocOp::DotDotEq, + ), + _, + ) if self.restrictions.contains(Restrictions::IS_PAT) => { + return None; + } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { self.dcx().emit_err(errors::InvalidLogicalOperator { @@ -482,7 +495,11 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P<Expr>> { let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?) + let maybe_lt = self.token.clone(); + Some( + self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed) + .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?, + ) } else { None }; @@ -531,11 +548,13 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { let lo = this.token.span; + let maybe_lt = this.look_ahead(1, |t| t.clone()); this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) - .map(|x| (lo.to(x.span), Some(x)))? + .map(|x| (lo.to(x.span), Some(x))) + .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? } else { (lo, None) }; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3bd8ae02586..9a77643f951 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -10,7 +10,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_code_err, Applicability, PResult, StashKey}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, PResult, StashKey}; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; use rustc_span::source_map; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ff2fb6271a8..623407eb380 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -53,6 +53,7 @@ bitflags::bitflags! { const CONST_EXPR = 1 << 2; const ALLOW_LET = 1 << 3; const IN_IF_GUARD = 1 << 4; + const IS_PAT = 1 << 5; } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7918e03750c..d04921dde54 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,4 +1,4 @@ -use super::{ForceCollect, Parser, PathStyle, TrailingToken}; +use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, @@ -6,14 +6,14 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, + TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter, Token}; use rustc_ast::{ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -23,7 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -336,6 +336,95 @@ impl<'a> Parser<'a> { } } + /// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator. + /// + /// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end)) + /// in order to say "expected a pattern range bound" instead of "expected a pattern"; + /// ```text + /// 0..=1 + 2 + /// ^^^^^ + /// ``` + /// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter. + #[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"] + fn maybe_recover_trailing_expr( + &mut self, + pat_span: Span, + is_end_bound: bool, + ) -> Option<ErrorGuaranteed> { + if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() { + // Don't recover anything after an `_` or if recovery is disabled. + return None; + } + + // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`. + let has_trailing_method = self.check_noexpect(&token::Dot) + && self.look_ahead(1, |tok| { + tok.ident() + .and_then(|(ident, _)| ident.name.as_str().chars().next()) + .is_some_and(char::is_lowercase) + }) + && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis)); + + // Check for operators. + // `|` is excluded as it is used in pattern alternatives and lambdas, + // `?` is included for error propagation, + // `[` is included for indexing operations, + // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`) + let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or) + || self.token.kind == token::Question + || (self.token.kind == token::OpenDelim(Delimiter::Bracket) + && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket))); + + if !has_trailing_method && !has_trailing_operator { + // Nothing to recover here. + return None; + } + + // Let's try to parse an expression to emit a better diagnostic. + let mut snapshot = self.create_snapshot_for_diagnostic(); + snapshot.restrictions.insert(Restrictions::IS_PAT); + + // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. + if let Ok(expr) = snapshot + .parse_expr_dot_or_call_with( + self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr` + pat_span, + AttrVec::new(), + ) + .map_err(|err| err.cancel()) + { + let non_assoc_span = expr.span; + + // Parse an associative expression such as `+ expr`, `% expr`, ... + // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. + if let Ok(expr) = + snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel()) + { + // We got a valid expression. + self.restore_snapshot(snapshot); + self.restrictions.remove(Restrictions::IS_PAT); + + let is_bound = is_end_bound + // is_start_bound: either `..` or `)..` + || self.token.is_range_separator() + || self.token.kind == token::CloseDelim(Delimiter::Parenthesis) + && self.look_ahead(1, Token::is_range_separator); + + // Check that `parse_expr_assoc_with` didn't eat a rhs. + let is_method_call = has_trailing_method && non_assoc_span == expr.span; + + return Some(self.dcx().emit_err(UnexpectedExpressionInPattern { + span: expr.span, + is_bound, + is_method_call, + })); + } + } + + // We got a trailing method/operator, but we couldn't parse an expression. + None + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -441,7 +530,10 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { self.parse_pat_tuple_struct(qself, path)? } else { - PatKind::Path(qself, path) + match self.maybe_recover_trailing_expr(span, false) { + Some(guar) => PatKind::Err(guar), + None => PatKind::Path(qself, path), + } } } else if matches!(self.token.kind, token::Lifetime(_)) // In pattern position, we're totally fine with using "next token isn't colon" @@ -470,10 +562,17 @@ impl<'a> Parser<'a> { } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { - Ok(begin) => match self.parse_range_end() { - Some(form) => self.parse_pat_range_begin_with(begin, form)?, - None => PatKind::Lit(begin), - }, + Ok(begin) => { + let begin = match self.maybe_recover_trailing_expr(begin.span, false) { + Some(_) => self.mk_expr_err(begin.span), + None => begin, + }; + + match self.parse_range_end() { + Some(form) => self.parse_pat_range_begin_with(begin, form)?, + None => PatKind::Lit(begin), + } + } Err(err) => return self.fatal_unexpected_non_pat(err, expected), } }; @@ -615,6 +714,21 @@ impl<'a> Parser<'a> { self.parse_pat_range_begin_with(begin.clone(), form)? } + // recover ranges with parentheses around the `(start)..` + PatKind::Err(_) + if self.may_recover() + && let Some(form) = self.parse_range_end() => + { + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, close_paren], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: close_paren, + }, + }); + + self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)? + } // (pat) with optional parentheses _ => PatKind::Paren(pat), @@ -853,6 +967,8 @@ impl<'a> Parser<'a> { self.parse_literal_maybe_minus() }?; + let recovered = self.maybe_recover_trailing_expr(bound.span, true); + // recover trailing `)` if let Some(open_paren) = open_paren { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; @@ -866,7 +982,10 @@ impl<'a> Parser<'a> { }); } - Ok(bound) + Ok(match recovered { + Some(_) => self.mk_expr_err(bound.span), + None => bound, + }) } /// Is this the start of a pattern beginning with a path? @@ -929,7 +1048,17 @@ impl<'a> Parser<'a> { .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); } - Ok(PatKind::Ident(binding_annotation, ident, sub)) + // Check for method calls after the `ident`, + // but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`. + + let pat = if sub.is_none() + && let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false) + { + PatKind::Err(guar) + } else { + PatKind::Ident(binding_annotation, ident, sub) + }; + Ok(pat) } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 625764876a6..d76ee161da6 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -1056,7 +1056,7 @@ fn find_width_map_from_snippet( fn unescape_string(string: &str) -> Option<string::String> { let mut buf = string::String::new(); let mut ok = true; - unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| { + unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| { match unescaped_char { Ok(c) => buf.push(c), Err(_) => ok = false, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d3909ce3a1c..9be28674435 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -917,7 +917,7 @@ impl<'tcx> DeadVisitor<'tcx> { return; } dead_codes.sort_by_key(|v| v.level); - for group in dead_codes[..].group_by(|a, b| a.level == b.level) { + for group in dead_codes[..].chunk_by(|a, b| a.level == b.level) { self.lint_at_single_level(&group, participle, Some(def_id), report_on); } } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 25ca685cbfa..97c70e327f0 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,6 +1,6 @@ use rustc_ast::attr; use rustc_ast::entry::EntryPointType; -use rustc_errors::error_code; +use rustc_errors::codes::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; @@ -180,8 +180,8 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { Default::default() }); let main_def_opt = tcx.resolutions(()).main_def; - let code = error_code!(E0601); - let add_teach_note = tcx.sess.teach(&code); + let code = E0601; + let add_teach_note = tcx.sess.teach(code); // The file may be empty, which leads to the diagnostic machinery not emitting this // note. This is a relatively simple way to detect that case and emit a span-less // note instead. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cf3c7cc4ace..77bfe57e370 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,7 +6,7 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::Label; use rustc_errors::{ - error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticSymbolList, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, }; use rustc_hir::{self as hir, ExprKind, Target}; @@ -55,7 +55,7 @@ pub struct IgnoredInlineAttrFnProto; pub struct IgnoredInlineAttrConstants; #[derive(Diagnostic)] -#[diag(passes_inline_not_fn_or_closure, code = "E0518")] +#[diag(passes_inline_not_fn_or_closure, code = E0518)] pub struct InlineNotFnOrClosure { #[primary_span] pub attr_span: Span, @@ -76,7 +76,7 @@ pub struct IgnoredCoveragePropagate; pub struct IgnoredCoverageFnDefn; #[derive(Diagnostic)] -#[diag(passes_coverage_not_coverable, code = "E0788")] +#[diag(passes_coverage_not_coverable, code = E0788)] pub struct IgnoredCoverageNotCoverable { #[primary_span] pub attr_span: Span, @@ -95,14 +95,14 @@ pub struct AttrShouldBeAppliedToFn { } #[derive(Diagnostic)] -#[diag(passes_naked_tracked_caller, code = "E0736")] +#[diag(passes_naked_tracked_caller, code = E0736)] pub struct NakedTrackedCaller { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_fn, code = "E0739")] +#[diag(passes_should_be_applied_to_fn, code = E0739)] pub struct TrackedCallerWrongLocation { #[primary_span] pub attr_span: Span, @@ -112,7 +112,7 @@ pub struct TrackedCallerWrongLocation { } #[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")] +#[diag(passes_should_be_applied_to_struct_enum, code = E0701)] pub struct NonExhaustiveWrongLocation { #[primary_span] pub attr_span: Span, @@ -370,28 +370,28 @@ pub struct HasIncoherentInherentImpl { } #[derive(Diagnostic)] -#[diag(passes_both_ffi_const_and_pure, code = "E0757")] +#[diag(passes_both_ffi_const_and_pure, code = E0757)] pub struct BothFfiConstAndPure { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_ffi_pure_invalid_target, code = "E0755")] +#[diag(passes_ffi_pure_invalid_target, code = E0755)] pub struct FfiPureInvalidTarget { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_ffi_const_invalid_target, code = "E0756")] +#[diag(passes_ffi_const_invalid_target, code = E0756)] pub struct FfiConstInvalidTarget { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes_ffi_returns_twice_invalid_target, code = "E0724")] +#[diag(passes_ffi_returns_twice_invalid_target, code = E0724)] pub struct FfiReturnsTwiceInvalidTarget { #[primary_span] pub attr_span: Span, @@ -552,21 +552,21 @@ pub struct NoMangle { } #[derive(Diagnostic)] -#[diag(passes_repr_ident, code = "E0565")] +#[diag(passes_repr_ident, code = E0565)] pub struct ReprIdent { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes_repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = E0566)] pub struct ReprConflicting { #[primary_span] pub hint_spans: Vec<Span>, } #[derive(LintDiagnostic)] -#[diag(passes_repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = E0566)] pub struct ReprConflictingLint; #[derive(Diagnostic)] @@ -667,7 +667,7 @@ pub(crate) struct EmptyConfusables { } #[derive(Diagnostic)] -#[diag(passes_incorrect_meta_item, code = "E0539")] +#[diag(passes_incorrect_meta_item, code = E0539)] pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, @@ -737,7 +737,7 @@ pub struct Unused { } #[derive(Diagnostic)] -#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")] +#[diag(passes_non_exported_macro_invalid_attrs, code = E0518)] pub struct NonExportedMacroInvalidAttrs { #[primary_span] #[label] @@ -801,7 +801,7 @@ pub struct DeprecatedAnnotationHasNoEffect { } #[derive(Diagnostic)] -#[diag(passes_unknown_external_lang_item, code = "E0264")] +#[diag(passes_unknown_external_lang_item, code = E0264)] pub struct UnknownExternLangItem { #[primary_span] pub span: Span, @@ -837,7 +837,7 @@ pub struct LangItemWithTargetFeature { } #[derive(Diagnostic)] -#[diag(passes_lang_item_on_incorrect_target, code = "E0718")] +#[diag(passes_lang_item_on_incorrect_target, code = E0718)] pub struct LangItemOnIncorrectTarget { #[primary_span] #[label] @@ -848,7 +848,7 @@ pub struct LangItemOnIncorrectTarget { } #[derive(Diagnostic)] -#[diag(passes_unknown_lang_item, code = "E0522")] +#[diag(passes_unknown_lang_item, code = E0522)] pub struct UnknownLangItem { #[primary_span] #[label] @@ -990,7 +990,7 @@ pub struct UnrecognizedField { } #[derive(Diagnostic)] -#[diag(passes_feature_stable_twice, code = "E0711")] +#[diag(passes_feature_stable_twice, code = E0711)] pub struct FeatureStableTwice { #[primary_span] pub span: Span, @@ -1000,7 +1000,7 @@ pub struct FeatureStableTwice { } #[derive(Diagnostic)] -#[diag(passes_feature_previously_declared, code = "E0711")] +#[diag(passes_feature_previously_declared, code = E0711)] pub struct FeaturePreviouslyDeclared<'a, 'b> { #[primary_span] pub span: Span, @@ -1025,7 +1025,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop); diag.span(self.span); - diag.code(error_code!(E0571)); + diag.code(E0571); diag.arg("kind", self.kind); diag.span_label(self.span, fluent::passes_label); if let Some(head) = self.head { @@ -1063,7 +1063,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { } #[derive(Diagnostic)] -#[diag(passes_continue_labeled_block, code = "E0696")] +#[diag(passes_continue_labeled_block, code = E0696)] pub struct ContinueLabeledBlock { #[primary_span] #[label] @@ -1073,7 +1073,7 @@ pub struct ContinueLabeledBlock { } #[derive(Diagnostic)] -#[diag(passes_break_inside_closure, code = "E0267")] +#[diag(passes_break_inside_closure, code = E0267)] pub struct BreakInsideClosure<'a> { #[primary_span] #[label] @@ -1084,7 +1084,7 @@ pub struct BreakInsideClosure<'a> { } #[derive(Diagnostic)] -#[diag(passes_break_inside_async_block, code = "E0267")] +#[diag(passes_break_inside_async_block, code = E0267)] pub struct BreakInsideAsyncBlock<'a> { #[primary_span] #[label] @@ -1095,7 +1095,7 @@ pub struct BreakInsideAsyncBlock<'a> { } #[derive(Diagnostic)] -#[diag(passes_outside_loop, code = "E0268")] +#[diag(passes_outside_loop, code = E0268)] pub struct OutsideLoop<'a> { #[primary_span] #[label] @@ -1115,7 +1115,7 @@ pub struct OutsideLoopSuggestion { } #[derive(Diagnostic)] -#[diag(passes_unlabeled_in_labeled_block, code = "E0695")] +#[diag(passes_unlabeled_in_labeled_block, code = E0695)] pub struct UnlabeledInLabeledBlock<'a> { #[primary_span] #[label] @@ -1124,7 +1124,7 @@ pub struct UnlabeledInLabeledBlock<'a> { } #[derive(Diagnostic)] -#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")] +#[diag(passes_unlabeled_cf_in_while_condition, code = E0590)] pub struct UnlabeledCfInWhileCondition<'a> { #[primary_span] #[label] @@ -1169,7 +1169,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block); diag.span(self.span); - diag.code(error_code!(E0787)); + diag.code(E0787); for span in self.multiple_asms.iter() { diag.span_label(*span, fluent::passes_label_multiple_asm); } @@ -1181,14 +1181,14 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_operands, code = "E0787")] +#[diag(passes_naked_functions_operands, code = E0787)] pub struct NakedFunctionsOperands { #[primary_span] pub unsupported_operands: Vec<Span>, } #[derive(Diagnostic)] -#[diag(passes_naked_functions_asm_options, code = "E0787")] +#[diag(passes_naked_functions_asm_options, code = E0787)] pub struct NakedFunctionsAsmOptions { #[primary_span] pub span: Span, @@ -1196,7 +1196,7 @@ pub struct NakedFunctionsAsmOptions { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")] +#[diag(passes_naked_functions_must_use_noreturn, code = E0787)] pub struct NakedFunctionsMustUseNoreturn { #[primary_span] pub span: Span, @@ -1229,7 +1229,7 @@ pub struct AttrOnlyInFunctions { } #[derive(Diagnostic)] -#[diag(passes_multiple_rustc_main, code = "E0137")] +#[diag(passes_multiple_rustc_main, code = E0137)] pub struct MultipleRustcMain { #[primary_span] pub span: Span, @@ -1240,7 +1240,7 @@ pub struct MultipleRustcMain { } #[derive(Diagnostic)] -#[diag(passes_multiple_start_functions, code = "E0138")] +#[diag(passes_multiple_start_functions, code = E0138)] pub struct MultipleStartFunctions { #[primary_span] pub span: Span, @@ -1280,7 +1280,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function); diag.span(DUMMY_SP); - diag.code(error_code!(E0601)); + diag.code(E0601); diag.arg("crate_name", self.crate_name); diag.arg("filename", self.filename); diag.arg("has_filename", self.has_filename); @@ -1345,7 +1345,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for DuplicateLangItem { Duplicate::CrateDepends => fluent::passes_duplicate_lang_item_crate_depends, }, ); - diag.code(error_code!(E0152)); + diag.code(E0152); diag.arg("lang_item_name", self.lang_item_name); diag.arg("crate_name", self.crate_name); diag.arg("dependency_of", self.dependency_of); @@ -1382,7 +1382,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for DuplicateLangItem { } #[derive(Diagnostic)] -#[diag(passes_incorrect_target, code = "E0718")] +#[diag(passes_incorrect_target, code = E0718)] pub struct IncorrectTarget<'a> { #[primary_span] pub span: Span, @@ -1418,7 +1418,7 @@ pub struct ObjectLifetimeErr { } #[derive(Diagnostic)] -#[diag(passes_unrecognized_repr_hint, code = "E0552")] +#[diag(passes_unrecognized_repr_hint, code = E0552)] #[help] pub struct UnrecognizedReprHint { #[primary_span] @@ -1427,35 +1427,35 @@ pub struct UnrecognizedReprHint { #[derive(Diagnostic)] pub enum AttrApplication { - #[diag(passes_attr_application_enum, code = "E0517")] + #[diag(passes_attr_application_enum, code = E0517)] Enum { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct, code = "E0517")] + #[diag(passes_attr_application_struct, code = E0517)] Struct { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_union, code = "E0517")] + #[diag(passes_attr_application_struct_union, code = E0517)] StructUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_union, code = E0517)] StructEnumUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_function_method_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)] StructEnumFunctionMethodUnion { #[primary_span] hint_span: Span, @@ -1465,7 +1465,7 @@ pub enum AttrApplication { } #[derive(Diagnostic)] -#[diag(passes_transparent_incompatible, code = "E0692")] +#[diag(passes_transparent_incompatible, code = E0692)] pub struct TransparentIncompatible { #[primary_span] pub hint_spans: Vec<Span>, @@ -1473,7 +1473,7 @@ pub struct TransparentIncompatible { } #[derive(Diagnostic)] -#[diag(passes_deprecated_attribute, code = "E0549")] +#[diag(passes_deprecated_attribute, code = E0549)] pub struct DeprecatedAttribute { #[primary_span] pub span: Span, @@ -1524,7 +1524,7 @@ pub struct TraitImplConstStable { } #[derive(Diagnostic)] -#[diag(passes_feature_only_on_nightly, code = "E0554")] +#[diag(passes_feature_only_on_nightly, code = E0554)] pub struct FeatureOnlyOnNightly { #[primary_span] pub span: Span, @@ -1532,7 +1532,7 @@ pub struct FeatureOnlyOnNightly { } #[derive(Diagnostic)] -#[diag(passes_unknown_feature, code = "E0635")] +#[diag(passes_unknown_feature, code = E0635)] pub struct UnknownFeature { #[primary_span] pub span: Span, @@ -1549,7 +1549,7 @@ pub struct ImpliedFeatureNotExist { } #[derive(Diagnostic)] -#[diag(passes_duplicate_feature_err, code = "E0636")] +#[diag(passes_duplicate_feature_err, code = E0636)] pub struct DuplicateFeatureErr { #[primary_span] pub span: Span, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 050a90efbdf..862b76b1f60 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -11,7 +11,6 @@ #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] -#![feature(slice_group_by)] #![feature(try_blocks)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index a55d53dfdac..6374874165f 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -95,6 +95,7 @@ pub trait TypeCx: Sized + fmt::Debug { type PatData: Clone; fn is_exhaustive_patterns_feature_on(&self) -> bool; + fn is_min_exhaustive_patterns_feature_on(&self) -> bool; /// The number of fields for this constructor. fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 23cab5f43ab..ef90d24b0bf 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -181,7 +181,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // `field.ty()` doesn't normalize after substituting. let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.tcx.features().exhaustive_patterns && cx.is_uninhabited(ty); + let is_uninhabited = (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && cx.is_uninhabited(ty); if is_uninhabited && (!is_visible || is_non_exhaustive) { None @@ -863,6 +865,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { fn is_exhaustive_patterns_feature_on(&self) -> bool { self.tcx.features().exhaustive_patterns } + fn is_min_exhaustive_patterns_feature_on(&self) -> bool { + self.tcx.features().min_exhaustive_patterns + } fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize { self.ctor_arity(ctor, *ty) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 0de48c9f3c0..a627bdeef81 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -548,11 +548,12 @@ //! [`ValidityConstraint::specialize`]. //! //! Having said all that, in practice we don't fully follow what's been presented in this section. -//! Under `exhaustive_patterns`, we allow omitting empty arms even in `!known_valid` places, for -//! backwards-compatibility until we have a better alternative. Without `exhaustive_patterns`, we -//! mostly treat empty types as inhabited, except specifically a non-nested `!` or empty enum. In -//! this specific case we also allow the empty match regardless of place validity, for -//! backwards-compatibility. Hopefully we can eventually deprecate this. +//! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or +//! `EmptyEnum`. First, on stable rust, we require `_` patterns for empty types in all cases apart +//! from the toplevel exception. The `exhaustive_patterns` and `min_exaustive_patterns` allow +//! omitting patterns in the cases described above. There's a final detail: in the toplevel +//! exception or with the `exhaustive_patterns` feature, we ignore place validity when checking +//! whether a pattern is required for exhaustiveness. I (Nadrieril) hope to deprecate this behavior. //! //! //! @@ -1442,10 +1443,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // We treat match scrutinees of type `!` or `EmptyEnum` differently. let is_toplevel_exception = is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors); - // Whether empty patterns can be omitted for exhaustiveness. - let can_omit_empty_arms = is_toplevel_exception || mcx.tycx.is_exhaustive_patterns_feature_on(); - // Whether empty patterns are counted as useful or not. - let empty_arms_are_unreachable = place_validity.is_known_valid() && can_omit_empty_arms; + // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if + // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). + let empty_arms_are_unreachable = place_validity.is_known_valid() + && (is_toplevel_exception + || mcx.tycx.is_exhaustive_patterns_feature_on() + || mcx.tycx.is_min_exhaustive_patterns_feature_on()); + // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the + // toplevel exception and `exhaustive_patterns` cases for backwards compatibility. + let can_omit_empty_arms = empty_arms_are_unreachable + || is_toplevel_exception + || mcx.tycx.is_exhaustive_patterns_feature_on(); // Analyze the constructors present in this column. let ctors = matrix.heads().map(|p| p.ctor()); diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index b1242f82f4f..01c6d18c0e1 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -1,9 +1,9 @@ -use rustc_errors::DiagnosticArgFromDisplay; +use rustc_errors::{codes::*, DiagnosticArgFromDisplay}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(privacy_field_is_private, code = "E0451")] +#[diag(privacy_field_is_private, code = E0451)] pub struct FieldIsPrivate { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ pub struct UnnamedItemIsPrivate { } #[derive(Diagnostic)] -#[diag(privacy_in_public_interface, code = "E0446")] +#[diag(privacy_in_public_interface, code = E0446)] pub struct InPublicInterface<'a> { #[primary_span] #[label] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9087ae00d11..a64b06e70d6 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -22,7 +22,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, PatKind}; -use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; use rustc_middle::ty::GenericArgs; @@ -34,9 +33,9 @@ use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; +use std::fmt; use std::marker::PhantomData; use std::ops::ControlFlow; -use std::{fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, @@ -933,7 +932,6 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { struct NamePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, - current_item: LocalDefId, } impl<'tcx> NamePrivacyVisitor<'tcx> { @@ -949,6 +947,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // Checks that a field in a struct constructor (expression or pattern) is accessible. fn check_field( &mut self, + hir_id: hir::HirId, // ID of the field use use_ctxt: Span, // syntax context of the field name at the use site span: Span, // span of the field pattern, e.g., `x: 0` def: ty::AdtDef<'tcx>, // definition of the struct or enum @@ -961,7 +960,6 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // definition of the field let ident = Ident::new(kw::Empty, use_ctxt); - let hir_id = self.tcx.local_def_id_to_hir_id(self.current_item); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; if !field.vis.is_accessible_from(def_id, self.tcx) { self.tcx.dcx().emit_err(FieldIsPrivate { @@ -980,33 +978,13 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - /// We want to visit items in the context of their containing - /// module and so forth, so supply a crate for doing a deep walk. - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { - // Don't visit nested modules, since we run a separate visitor walk - // for each module in `effective_visibilities` - } - - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_maybe_typeck_results = - self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); - let body = self.tcx.hir().body(body); - self.visit_body(body); + self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + self.visit_body(self.tcx.hir().body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); - intravisit::walk_item(self, item); - self.current_item = orig_current_item; - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); @@ -1020,17 +998,17 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let field = fields .iter() .find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); - let (use_ctxt, span) = match field { - Some(field) => (field.ident.span, field.span), - None => (base.span, base.span), + let (hir_id, use_ctxt, span) = match field { + Some(field) => (field.hir_id, field.ident.span, field.span), + None => (base.hir_id, base.span, base.span), }; - self.check_field(use_ctxt, span, adt, variant_field, true); + self.check_field(hir_id, use_ctxt, span, adt, variant_field, true); } } else { for field in fields { - let use_ctxt = field.ident.span; + let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); + self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); } } } @@ -1044,9 +1022,9 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); for field in fields { - let use_ctxt = field.ident.span; + let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); + self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); } } @@ -1741,17 +1719,12 @@ pub fn provide(providers: &mut Providers) { fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { // Check privacy of names not checked in previous compilation stages. - let mut visitor = NamePrivacyVisitor { - tcx, - maybe_typeck_results: None, - current_item: module_def_id.to_local_def_id(), - }; - let (module, span, hir_id) = tcx.hir().get_module(module_def_id); - - intravisit::walk_mod(&mut visitor, module, hir_id); + let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None }; + tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor); // Check privacy of explicitly written types and traits as well as // inferred types of expressions and patterns. + let span = tcx.def_span(module_def_id); let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span }; tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor); } diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 5829e17ec16..9db6fac8036 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -1,3 +1,4 @@ +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::Limit; use rustc_span::{Span, Symbol}; @@ -45,7 +46,7 @@ pub struct CycleUsage { } #[derive(Diagnostic)] -#[diag(query_system_cycle, code = "E0391")] +#[diag(query_system_cycle, code = E0391)] pub struct Cycle { #[primary_span] pub span: Span, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index b855ec8f920..7eb7c8c2bca 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,7 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_code_err, Applicability}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability}; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 66dfee6c062..f3a6eb65a72 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, - DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, + codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, + Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 821b1e946f3..50ff09feb4d 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,3 +1,4 @@ +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -7,16 +8,16 @@ use rustc_span::{ use crate::{late::PatternSource, Res}; #[derive(Diagnostic)] -#[diag(resolve_parent_module_reset_for_binding, code = "E0637")] +#[diag(resolve_parent_module_reset_for_binding, code = E0637)] pub(crate) struct ParentModuleResetForBinding; #[derive(Diagnostic)] -#[diag(resolve_ampersand_used_without_explicit_lifetime_name, code = "E0637")] +#[diag(resolve_ampersand_used_without_explicit_lifetime_name, code = E0637)] #[note] pub(crate) struct AmpersandUsedWithoutExplicitLifetimeName(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_underscore_lifetime_name_cannot_be_used_here, code = "E0637")] +#[diag(resolve_underscore_lifetime_name_cannot_be_used_here, code = E0637)] #[note] pub(crate) struct UnderscoreLifetimeNameCannotBeUsedHere(#[primary_span] pub(crate) Span); @@ -33,7 +34,7 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate) pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_generic_params_from_outer_item, code = "E0401")] +#[diag(resolve_generic_params_from_outer_item, code = E0401)] pub(crate) struct GenericParamsFromOuterItem { #[primary_span] #[label] @@ -67,7 +68,7 @@ pub(crate) struct GenericParamsFromOuterItemSugg { } #[derive(Diagnostic)] -#[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")] +#[diag(resolve_name_is_already_used_as_generic_parameter, code = E0403)] pub(crate) struct NameAlreadyUsedInParameterList { #[primary_span] #[label] @@ -78,7 +79,7 @@ pub(crate) struct NameAlreadyUsedInParameterList { } #[derive(Diagnostic)] -#[diag(resolve_method_not_member_of_trait, code = "E0407")] +#[diag(resolve_method_not_member_of_trait, code = E0407)] pub(crate) struct MethodNotMemberOfTrait { #[primary_span] #[label] @@ -102,7 +103,7 @@ pub(crate) struct AssociatedFnWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_type_not_member_of_trait, code = "E0437")] +#[diag(resolve_type_not_member_of_trait, code = E0437)] pub(crate) struct TypeNotMemberOfTrait { #[primary_span] #[label] @@ -126,7 +127,7 @@ pub(crate) struct AssociatedTypeWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_const_not_member_of_trait, code = "E0438")] +#[diag(resolve_const_not_member_of_trait, code = E0438)] pub(crate) struct ConstNotMemberOfTrait { #[primary_span] #[label] @@ -150,7 +151,7 @@ pub(crate) struct AssociatedConstWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_variable_bound_with_different_mode, code = "E0409")] +#[diag(resolve_variable_bound_with_different_mode, code = E0409)] pub(crate) struct VariableBoundWithDifferentMode { #[primary_span] #[label] @@ -161,7 +162,7 @@ pub(crate) struct VariableBoundWithDifferentMode { } #[derive(Diagnostic)] -#[diag(resolve_ident_bound_more_than_once_in_parameter_list, code = "E0415")] +#[diag(resolve_ident_bound_more_than_once_in_parameter_list, code = E0415)] pub(crate) struct IdentifierBoundMoreThanOnceInParameterList { #[primary_span] #[label] @@ -170,7 +171,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInParameterList { } #[derive(Diagnostic)] -#[diag(resolve_ident_bound_more_than_once_in_same_pattern, code = "E0416")] +#[diag(resolve_ident_bound_more_than_once_in_same_pattern, code = E0416)] pub(crate) struct IdentifierBoundMoreThanOnceInSamePattern { #[primary_span] #[label] @@ -179,7 +180,7 @@ pub(crate) struct IdentifierBoundMoreThanOnceInSamePattern { } #[derive(Diagnostic)] -#[diag(resolve_undeclared_label, code = "E0426")] +#[diag(resolve_undeclared_label, code = E0426)] pub(crate) struct UndeclaredLabel { #[primary_span] #[label] @@ -217,7 +218,7 @@ pub(crate) struct UnreachableLabelWithSimilarNameExists { } #[derive(Diagnostic)] -#[diag(resolve_self_import_can_only_appear_once_in_the_list, code = "E0430")] +#[diag(resolve_self_import_can_only_appear_once_in_the_list, code = E0430)] pub(crate) struct SelfImportCanOnlyAppearOnceInTheList { #[primary_span] #[label] @@ -225,7 +226,7 @@ pub(crate) struct SelfImportCanOnlyAppearOnceInTheList { } #[derive(Diagnostic)] -#[diag(resolve_self_import_only_in_import_list_with_non_empty_prefix, code = "E0431")] +#[diag(resolve_self_import_only_in_import_list_with_non_empty_prefix, code = E0431)] pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix { #[primary_span] #[label] @@ -233,7 +234,7 @@ pub(crate) struct SelfImportOnlyInImportListWithNonEmptyPrefix { } #[derive(Diagnostic)] -#[diag(resolve_cannot_capture_dynamic_environment_in_fn_item, code = "E0434")] +#[diag(resolve_cannot_capture_dynamic_environment_in_fn_item, code = E0434)] #[help] pub(crate) struct CannotCaptureDynamicEnvironmentInFnItem { #[primary_span] @@ -241,7 +242,7 @@ pub(crate) struct CannotCaptureDynamicEnvironmentInFnItem { } #[derive(Diagnostic)] -#[diag(resolve_attempt_to_use_non_constant_value_in_constant, code = "E0435")] +#[diag(resolve_attempt_to_use_non_constant_value_in_constant, code = E0435)] pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { #[primary_span] pub(crate) span: Span, @@ -283,7 +284,7 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithoutSuggestion<'a> { } #[derive(Diagnostic)] -#[diag(resolve_self_imports_only_allowed_within, code = "E0429")] +#[diag(resolve_self_imports_only_allowed_within, code = E0429)] pub(crate) struct SelfImportsOnlyAllowedWithin { #[primary_span] pub(crate) span: Span, @@ -317,7 +318,7 @@ pub(crate) struct SelfImportsOnlyAllowedWithinMultipartSuggestion { } #[derive(Diagnostic)] -#[diag(resolve_binding_shadows_something_unacceptable, code = "E0530")] +#[diag(resolve_binding_shadows_something_unacceptable, code = E0530)] pub(crate) struct BindingShadowsSomethingUnacceptable<'a> { #[primary_span] #[label] @@ -346,7 +347,7 @@ pub(crate) struct BindingShadowsSomethingUnacceptableSuggestion { } #[derive(Diagnostic)] -#[diag(resolve_forward_declared_generic_param, code = "E0128")] +#[diag(resolve_forward_declared_generic_param, code = E0128)] pub(crate) struct ForwardDeclaredGenericParam { #[primary_span] #[label] @@ -354,7 +355,7 @@ pub(crate) struct ForwardDeclaredGenericParam { } #[derive(Diagnostic)] -#[diag(resolve_param_in_ty_of_const_param, code = "E0770")] +#[diag(resolve_param_in_ty_of_const_param, code = E0770)] pub(crate) struct ParamInTyOfConstParam { #[primary_span] #[label] @@ -376,7 +377,7 @@ pub(crate) enum ParamKindInTyOfConstParam { } #[derive(Diagnostic)] -#[diag(resolve_self_in_generic_param_default, code = "E0735")] +#[diag(resolve_self_in_generic_param_default, code = E0735)] pub(crate) struct SelfInGenericParamDefault { #[primary_span] #[label] @@ -412,7 +413,7 @@ pub(crate) enum ParamKindInNonTrivialAnonConst { } #[derive(Diagnostic)] -#[diag(resolve_unreachable_label, code = "E0767")] +#[diag(resolve_unreachable_label, code = E0767)] #[note] pub(crate) struct UnreachableLabel { #[primary_span] @@ -456,7 +457,7 @@ pub(crate) struct UnreachableLabelSubLabelUnreachable { } #[derive(Diagnostic)] -#[diag(resolve_trait_impl_mismatch, code = "{code}")] +#[diag(resolve_trait_impl_mismatch)] pub(crate) struct TraitImplMismatch { #[primary_span] #[label] @@ -466,7 +467,6 @@ pub(crate) struct TraitImplMismatch { #[label(resolve_label_trait_item)] pub(crate) trait_item_span: Span, pub(crate) trait_path: String, - pub(crate) code: String, } #[derive(Diagnostic)] @@ -496,7 +496,7 @@ pub(crate) struct BindingInNeverPattern { } #[derive(Diagnostic)] -#[diag(resolve_trait_impl_duplicate, code = "E0201")] +#[diag(resolve_trait_impl_duplicate, code = E0201)] pub(crate) struct TraitImplDuplicate { #[primary_span] #[label] @@ -519,11 +519,11 @@ pub(crate) struct Relative2018 { } #[derive(Diagnostic)] -#[diag(resolve_ancestor_only, code = "E0742")] +#[diag(resolve_ancestor_only, code = E0742)] pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] -#[diag(resolve_expected_found, code = "E0577")] +#[diag(resolve_expected_found, code = E0577)] pub(crate) struct ExpectedFound { #[primary_span] #[label] @@ -533,7 +533,7 @@ pub(crate) struct ExpectedFound { } #[derive(Diagnostic)] -#[diag(resolve_indeterminate, code = "E0578")] +#[diag(resolve_indeterminate, code = E0578)] pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] @@ -715,7 +715,7 @@ pub(crate) struct CannotDetermineMacroResolution { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_private, code = "E0364")] +#[diag(resolve_cannot_be_reexported_private, code = E0364)] pub(crate) struct CannotBeReexportedPrivate { #[primary_span] pub(crate) span: Span, @@ -723,7 +723,7 @@ pub(crate) struct CannotBeReexportedPrivate { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_crate_public, code = "E0364")] +#[diag(resolve_cannot_be_reexported_crate_public, code = E0364)] pub(crate) struct CannotBeReexportedCratePublic { #[primary_span] pub(crate) span: Span, @@ -731,7 +731,7 @@ pub(crate) struct CannotBeReexportedCratePublic { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_private, code = "E0365")] +#[diag(resolve_cannot_be_reexported_private, code = E0365)] #[note(resolve_consider_declaring_with_pub)] pub(crate) struct CannotBeReexportedPrivateNS { #[primary_span] @@ -741,7 +741,7 @@ pub(crate) struct CannotBeReexportedPrivateNS { } #[derive(Diagnostic)] -#[diag(resolve_cannot_be_reexported_crate_public, code = "E0365")] +#[diag(resolve_cannot_be_reexported_crate_public, code = E0365)] #[note(resolve_consider_declaring_with_pub)] pub(crate) struct CannotBeReexportedCratePublicNS { #[primary_span] @@ -780,7 +780,7 @@ pub(crate) struct ItemsInTraitsAreNotImportable { } #[derive(Diagnostic)] -#[diag(resolve_is_not_directly_importable, code = "E0253")] +#[diag(resolve_is_not_directly_importable, code = E0253)] pub(crate) struct IsNotDirectlyImportable { #[primary_span] #[label] diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index ad60caed354..30fb35238c3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -17,7 +17,7 @@ use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult}; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; use rustc_middle::metadata::Reexport; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index abd724a6cc2..0743ff03864 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -16,7 +16,9 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{Applicability, DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_errors::{ + codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg, +}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -533,21 +535,20 @@ impl<'a> PathSource<'a> { } } - fn error_code(self, has_unexpected_resolution: bool) -> String { - use rustc_errors::error_code; + fn error_code(self, has_unexpected_resolution: bool) -> ErrCode { match (self, has_unexpected_resolution) { - (PathSource::Trait(_), true) => error_code!(E0404), - (PathSource::Trait(_), false) => error_code!(E0405), - (PathSource::Type, true) => error_code!(E0573), - (PathSource::Type, false) => error_code!(E0412), - (PathSource::Struct, true) => error_code!(E0574), - (PathSource::Struct, false) => error_code!(E0422), - (PathSource::Expr(..), true) | (PathSource::Delegation, true) => error_code!(E0423), - (PathSource::Expr(..), false) | (PathSource::Delegation, false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), - (PathSource::TraitItem(..), true) => error_code!(E0575), - (PathSource::TraitItem(..), false) => error_code!(E0576), + (PathSource::Trait(_), true) => E0404, + (PathSource::Trait(_), false) => E0405, + (PathSource::Type, true) => E0573, + (PathSource::Type, false) => E0412, + (PathSource::Struct, true) => E0574, + (PathSource::Struct, false) => E0422, + (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423, + (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425, + (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532, + (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531, + (PathSource::TraitItem(..), true) => E0575, + (PathSource::TraitItem(..), false) => E0576, } } } @@ -1673,13 +1674,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { ("`'_` cannot be used here", "`'_` is a reserved lifetime name") }; - let mut diag = rustc_errors::struct_span_code_err!( - self.r.dcx(), - lifetime.ident.span, - E0637, - "{}", - msg, - ); + let mut diag = + struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,); diag.span_label(lifetime.ident.span, note); if elided { for rib in self.lifetime_ribs[i..].iter().rev() { @@ -1863,7 +1859,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { let sess = self.r.tcx.sess; - let mut err = rustc_errors::struct_span_code_err!( + let mut err = struct_span_code_err!( sess.dcx(), path_span, E0726, @@ -2608,7 +2604,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( self.r.dcx(), param.ident.span, E0637, @@ -2622,7 +2618,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::StaticLifetime { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( self.r.dcx(), param.ident.span, E0262, @@ -3164,10 +3160,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // The method kind does not correspond to what appeared in the trait, report. let path = &self.current_trait_ref.as_ref().unwrap().1.path; let (code, kind) = match kind { - AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"), - AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"), - AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"), - AssocItemKind::Delegation(..) => (rustc_errors::error_code!(E0324), "method"), + AssocItemKind::Const(..) => (E0323, "const"), + AssocItemKind::Fn(..) => (E0324, "method"), + AssocItemKind::Type(..) => (E0325, "type"), + AssocItemKind::Delegation(..) => (E0324, "method"), AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"), }; let trait_path = path_names_to_string(path); @@ -4424,35 +4420,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ExprKind::Type(ref _type_expr, ref _ty) => { visit::walk_expr(self, expr); } - // `async |x| ...` gets desugared to `|x| async {...}`, so we need to - // resolve the arguments within the proper scopes so that usages of them inside the - // closure are detected as upvars rather than normal closure arg usages. - // - // Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too. - ExprKind::Closure(box ast::Closure { - coroutine_kind: Some(_), - ref fn_decl, - ref body, - .. - }) => { - self.with_rib(ValueNS, RibKind::Normal, |this| { - this.with_label_rib(RibKind::FnOrCoroutine, |this| { - // Resolve arguments: - this.resolve_params(&fn_decl.inputs); - // No need to resolve return type -- - // the outer closure return type is `FnRetTy::Default`. - - // Now resolve the inner closure - { - // No need to resolve arguments: the inner closure has none. - // Resolve the return type: - visit::walk_fn_ret_ty(this, &fn_decl.output); - // Resolve the body - this.visit_expr(body); - } - }) - }); - } // For closures, RibKind::FnOrCoroutine is added in visit_fn ExprKind::Closure(box ast::Closure { binder: ClosureBinder::For { ref generic_params, span }, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index abb0a7a465a..a4c041f1ff2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,8 +16,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, SuggestionStyle, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; @@ -922,8 +922,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { path: &[Segment], span: Span, ) { - if let Some(err_code) = &err.code { - if err_code == &rustc_errors::error_code!(E0425) { + if let Some(err_code) = err.code { + if err_code == E0425 { for label_rib in &self.label_ribs { for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; @@ -946,7 +946,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } } - } else if err_code == &rustc_errors::error_code!(E0412) { + } else if err_code == E0412 { if let Some(correct) = Self::likely_rust_type(path) { err.span_suggestion( span, @@ -970,7 +970,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if !is_self_type(path, source.namespace()) { return false; } - err.code(rustc_errors::error_code!(E0411)); + err.code(E0411); err.span_label(span, "`Self` is only available in impls, traits, and type definitions"); if let Some(item_kind) = self.diagnostic_metadata.current_item { if !item_kind.ident.span.is_dummy() { @@ -999,7 +999,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - err.code(rustc_errors::error_code!(E0424)); + err.code(E0424); err.span_label( span, match source { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 925c3c0e27d..9d09d060b59 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -35,7 +35,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrCode}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -256,7 +256,7 @@ enum ResolutionError<'a> { kind: &'static str, trait_path: String, trait_item_span: Span, - code: String, + code: ErrCode, }, /// Error E0201: multiple impl items for the same trait item. TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span }, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1c085ddf57b..a6bf289a76a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_code_err, Applicability}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e751ff13a34..2ec1a726cef 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -347,6 +347,7 @@ impl SwitchWithOptPath { pub enum SymbolManglingVersion { Legacy, V0, + Hashed, } #[derive(Clone, Copy, Debug, PartialEq, Hash)] @@ -2692,6 +2693,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M match cg.symbol_mangling_version { // Stable values: None | Some(SymbolManglingVersion::V0) => {} + // Unstable values: Some(SymbolManglingVersion::Legacy) => { if !unstable_opts.unstable_options { @@ -2700,6 +2702,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } } + Some(SymbolManglingVersion::Hashed) => { + if !unstable_opts.unstable_options { + early_dcx.early_fatal( + "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`", + ); + } + } } // Check for unstable values of `-C instrument-coverage`. @@ -2741,6 +2750,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } Some(SymbolManglingVersion::V0) => {} + Some(SymbolManglingVersion::Hashed) => { + early_dcx.early_warn( + "-C instrument-coverage requires symbol mangling version `v0`, \ + but `-C symbol-mangling-version=hashed` was specified", + ); + } } } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index e19f0fd84de..c36cec6f353 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, + codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -19,9 +19,7 @@ pub struct FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new(dcx, level, self.explain) - .with_span(self.span) - .with_code(error_code!(E0658)) + DiagnosticBuilder::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 486b6d4bf2e..d8d201d5f24 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -407,7 +407,8 @@ mod desc { pub const parse_switch_with_opt_path: &str = "an optional path to the profiling data output directory"; pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; - pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; + pub const parse_symbol_mangling_version: &str = + "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; @@ -1180,6 +1181,7 @@ mod parse { *slot = match v { Some("legacy") => Some(SymbolManglingVersion::Legacy), Some("v0") => Some(SymbolManglingVersion::V0), + Some("hashed") => Some(SymbolManglingVersion::Hashed), _ => return false, }; true @@ -1504,7 +1506,7 @@ options! { "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option<SymbolManglingVersion> = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), + "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"), target_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 891a83ce80c..7cd76ad7293 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -22,7 +22,7 @@ use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, + codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrCode, ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl, }; use rustc_macros::HashStable_Generic; @@ -316,7 +316,7 @@ impl Session { ) -> DiagnosticBuilder<'a> { let mut err = self.dcx().create_err(err); if err.code.is_none() { - err.code(error_code!(E0658)); + err.code(E0658); } add_feature_diagnostics(&mut err, self, feature); err @@ -893,7 +893,7 @@ impl Session { CodegenUnits::Default(16) } - pub fn teach(&self, code: &str) -> bool { + pub fn teach(&self, code: ErrCode) -> bool { self.opts.unstable_opts.teach && self.dcx().must_teach(code) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4a1c222a528..a54b928b908 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -246,17 +246,7 @@ symbols! { MutexGuard, N, NonNull, - NonZeroI128, - NonZeroI16, - NonZeroI32, - NonZeroI64, - NonZeroI8, - NonZeroU128, - NonZeroU16, - NonZeroU32, - NonZeroU64, - NonZeroU8, - NonZeroUsize, + NonZero, None, Normal, Ok, @@ -1029,6 +1019,7 @@ symbols! { min_const_fn, min_const_generics, min_const_unsafe_fn, + min_exhaustive_patterns, min_specialization, min_type_alias_impl_trait, minnumf32, diff --git a/compiler/rustc_symbol_mangling/src/hashed.rs b/compiler/rustc_symbol_mangling/src/hashed.rs new file mode 100644 index 00000000000..d4cd6161ac0 --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/hashed.rs @@ -0,0 +1,43 @@ +use crate::v0; +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; +use rustc_hir::def_id::CrateNum; +use rustc_middle::ty::{Instance, TyCtxt}; + +use std::fmt::Write; + +pub(super) fn mangle<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option<CrateNum>, + full_mangling_name: impl FnOnce() -> String, +) -> String { + // The symbol of a generic function may be scattered in multiple downstream dylibs. + // If the symbol of a generic function still contains `crate name`, hash conflicts between the + // generic funcion and other symbols of the same `crate` cannot be detected in time during + // construction. This symbol conflict is left over until it occurs during run time. + // In this case, `instantiating-crate name` is used to replace `crate name` can completely + // eliminate the risk of the preceding potential hash conflict. + let crate_num = + if let Some(krate) = instantiating_crate { krate } else { instance.def_id().krate }; + + let mut symbol = "_RNxC".to_string(); + v0::push_ident(tcx.crate_name(crate_num).as_str(), &mut symbol); + + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + full_mangling_name().hash_stable(&mut hcx, &mut hasher); + hasher.finish::<Hash64>().as_u64() + }); + + push_hash64(hash, &mut symbol); + + symbol +} + +// The hash is encoded based on `base-62` and the final terminator `_` is removed because it does +// not help prevent hash collisions +fn push_hash64(hash: u64, output: &mut String) { + let hash = v0::encode_integer_62(hash); + let hash_len = hash.len(); + let _ = write!(output, "{hash_len}H{}", &hash[..hash_len - 1]); +} diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 1817cd72b23..362aaca6364 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -109,6 +109,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; +mod hashed; mod legacy; mod v0; @@ -263,6 +264,9 @@ fn compute_symbol_name<'tcx>( let symbol = match mangling_version { SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || { + v0::mangle(tcx, instance, instantiating_crate) + }), }; debug_assert!( diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index e89a640767f..16ebda55a7a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -116,10 +116,7 @@ impl<'tcx> SymbolMangler<'tcx> { /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. fn push_integer_62(&mut self, x: u64) { - if let Some(x) = x.checked_sub(1) { - base_n::push_str(x as u128, 62, &mut self.out); - } - self.push("_"); + push_integer_62(x, &mut self.out) } /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: @@ -138,45 +135,7 @@ impl<'tcx> SymbolMangler<'tcx> { } fn push_ident(&mut self, ident: &str) { - let mut use_punycode = false; - for b in ident.bytes() { - match b { - b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} - 0x80..=0xff => use_punycode = true, - _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), - } - } - - let punycode_string; - let ident = if use_punycode { - self.push("u"); - - // FIXME(eddyb) we should probably roll our own punycode implementation. - let mut punycode_bytes = match punycode::encode(ident) { - Ok(s) => s.into_bytes(), - Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), - }; - - // Replace `-` with `_`. - if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { - *c = b'_'; - } - - // FIXME(eddyb) avoid rechecking UTF-8 validity. - punycode_string = String::from_utf8(punycode_bytes).unwrap(); - &punycode_string - } else { - ident - }; - - let _ = write!(self.out, "{}", ident.len()); - - // Write a separating `_` if necessary (leading digit or `_`). - if let Some('_' | '0'..='9') = ident.chars().next() { - self.push("_"); - } - - self.push(ident); + push_ident(ident, &mut self.out) } fn path_append_ns( @@ -836,3 +795,62 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { Ok(()) } } +/// Push a `_`-terminated base 62 integer, using the format +/// specified in the RFC as `<base-62-number>`, that is: +/// * `x = 0` is encoded as just the `"_"` terminator +/// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, +/// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. +pub(crate) fn push_integer_62(x: u64, output: &mut String) { + if let Some(x) = x.checked_sub(1) { + base_n::push_str(x as u128, 62, output); + } + output.push('_'); +} + +pub(crate) fn encode_integer_62(x: u64) -> String { + let mut output = String::new(); + push_integer_62(x, &mut output); + output +} + +pub(crate) fn push_ident(ident: &str, output: &mut String) { + let mut use_punycode = false; + for b in ident.bytes() { + match b { + b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} + 0x80..=0xff => use_punycode = true, + _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), + } + } + + let punycode_string; + let ident = if use_punycode { + output.push('u'); + + // FIXME(eddyb) we should probably roll our own punycode implementation. + let mut punycode_bytes = match punycode::encode(ident) { + Ok(s) => s.into_bytes(), + Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), + }; + + // Replace `-` with `_`. + if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { + *c = b'_'; + } + + // FIXME(eddyb) avoid rechecking UTF-8 validity. + punycode_string = String::from_utf8(punycode_bytes).unwrap(); + &punycode_string + } else { + ident + }; + + let _ = write!(output, "{}", ident.len()); + + // Write a separating `_` if necessary (leading digit or `_`). + if let Some('_' | '0'..='9') = ident.chars().next() { + output.push('_'); + } + + output.push_str(ident); +} diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 5eff52afbca..7894f8dd98f 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, - IntoDiagnostic, Level, SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessage, }; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; @@ -25,7 +25,7 @@ pub struct UnableToConstructConstantValue<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)] pub struct EmptyOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -33,7 +33,7 @@ pub struct EmptyOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)] pub struct InvalidOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -41,7 +41,7 @@ pub struct InvalidOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] @@ -59,17 +59,13 @@ pub struct NegativePositiveConflict<'tcx> { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] - fn into_diagnostic( - self, - dcx: &DiagCtxt, - level: Level, - ) -> rustc_errors::DiagnosticBuilder<'_, G> { + fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict); diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); diag.span(self.impl_span); - diag.code(rustc_errors::error_code!(E0751)); + diag.code(E0751); match self.negative_impl_span { Ok(span) => { diag.span_label(span, fluent::trait_selection_negative_implementation_here); @@ -132,7 +128,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow { } #[derive(Diagnostic)] -#[diag(trait_selection_closure_kind_mismatch, code = "E0525")] +#[diag(trait_selection_closure_kind_mismatch, code = E0525)] pub struct ClosureKindMismatch { #[primary_span] #[label] diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 864580afe62..ca43436848b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -1,7 +1,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::Node; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index bb1b6ec1390..972da180a33 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_ast::AttrKind; use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::GenericArgsRef; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6a40ffebdad..cdf99870006 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -13,7 +13,7 @@ use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - error_code, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; @@ -2014,7 +2014,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; }; - err.code(error_code!(E0746)); + err.code(E0746); err.primary_message("return type cannot have an unboxed trait object"); err.children.clear(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 149dcffe333..2a09e95b2c5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -19,8 +19,8 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ - pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, StashKey, Style, + codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, StashKey, Style, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -2529,7 +2529,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { corresponding `impl` type", ), ); - err.code(rustc_errors::error_code!(E0790)); + err.code(E0790); if let Some(local_def_id) = data.trait_ref.def_id.as_local() && let Some(hir::Node::Item(hir::Item { @@ -3162,7 +3162,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ItemObligation(def_id) if self.tcx.is_fn_trait(*def_id) => { - err.code(rustc_errors::error_code!(E0059)); + err.code(E0059); err.primary_message(format!( "type parameter to bare `{}` trait must be a tuple", self.tcx.def_path_str(*def_id) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index bfc6937a3eb..de08e7d2f03 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -20,7 +20,7 @@ use crate::traits::{ self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, }; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{error_code, DelayDm, Diagnostic}; +use rustc_errors::{codes::*, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; @@ -449,7 +449,7 @@ fn report_conflicting_impls<'tcx>( || tcx.orphan_check_impl(impl_def_id).is_ok() { let mut err = tcx.dcx().struct_span_err(impl_span, msg); - err.code(error_code!(E0119)); + err.code(E0119); decorate(tcx, &overlap, impl_span, &mut err); err.emit() } else { diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 947d4bbe86e..bfbb45f0cb5 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by ty_utils +use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -113,7 +114,7 @@ pub struct DuplicateArg<'tcx> { } #[derive(Diagnostic)] -#[diag(ty_utils_impl_trait_not_param, code = "E0792")] +#[diag(ty_utils_impl_trait_not_param, code = E0792)] pub struct NotParam<'tcx> { pub arg: GenericArg<'tcx>, #[primary_span] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 6977681e5a3..2e321018407 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,8 +191,7 @@ mod thin; #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] // The declaration of the `Box` struct must be kept in sync with the -// `alloc::alloc::box_free` function or ICEs will happen. See the comment -// on `box_free` for more details. +// compiler or ICEs will happen. pub struct Box< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 02ecbe22b3e..ab08b483367 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,7 +103,6 @@ #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_into_iter_constructors)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] @@ -149,7 +148,6 @@ #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] -#![feature(slice_group_by)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 7705c86001e..0338565980c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -939,8 +939,11 @@ impl<T, A: Allocator> Rc<T, A> { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for - /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.) + /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. + /// And while they are meant for different use-cases, `Rc::into_inner(this)` + /// is in fact equivalent to <code>[Rc::try_unwrap]\(this).[ok][Result::ok]()</code>. + /// (Note that the same kind of equivalence does **not** hold true for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) #[inline] #[stable(feature = "rc_into_inner", since = "1.70.0")] pub fn into_inner(this: Self) -> Option<T> { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index aa3b7b7e191..4033f4eb068 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -51,14 +51,14 @@ pub use core::slice::{from_mut, from_ref}; pub use core::slice::{from_mut_ptr_range, from_ptr_range}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Chunks, Windows}; #[stable(feature = "chunks_exact", since = "1.31.0")] pub use core::slice::{ChunksExact, ChunksExactMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{ChunksMut, Split, SplitMut}; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use core::slice::{GroupBy, GroupByMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Iter, IterMut}; #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 38f9f39fbf8..ade114678b7 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -30,6 +30,8 @@ pub use core::str::SplitAsciiWhitespace; pub use core::str::SplitInclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::SplitWhitespace; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use core::str::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8, from_utf8_mut, Bytes, CharIndices, Chars}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 48c8d9d113b..d0f98f9c7db 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -983,9 +983,13 @@ impl<T, A: Allocator> Arc<T, A> { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// The similar expression `Arc::try_unwrap(this).ok()` does not - /// offer such a guarantee. See the last example below - /// and the documentation of [`Arc::try_unwrap`]. + /// [`Arc::try_unwrap`] is conceptually similar to `Arc::into_inner`, but it + /// is meant for different use-cases. If used as a direct replacement + /// for `Arc::into_inner` anyway, such as with the expression + /// <code>[Arc::try_unwrap]\(this).[ok][Result::ok]()</code>, then it does + /// **not** give the same guarantee as described in the previous paragraph. + /// For more information, see the examples below and read the documentation + /// of [`Arc::try_unwrap`]. /// /// # Examples /// diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 2c799605b7b..b12910f3690 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -15,6 +15,19 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { } } +#[stable(feature = "cow_from_array_ref", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: Clone, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a reference to an array. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed + fn from(s: &'a [T; N]) -> Cow<'a, [T]> { + Cow::Borrowed(s as &[_]) + } +} + #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> { /// Creates an [`Owned`] variant of [`Cow`] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6ca0dca1e9d..a360c430946 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2204,14 +2204,6 @@ impl<T, A: Allocator> Vec<T, A> { assert_failed(at, self.len()); } - if at == 0 { - // the new vector can take over the original buffer and avoid the copy - return mem::replace( - self, - Vec::with_capacity_in(self.capacity(), self.allocator().clone()), - ); - } - let other_len = self.len - at; let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 2dcfc6b4abf..ca17dab55b0 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -29,7 +29,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(round_char_boundary)] -#![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(string_remove_matches)] #![feature(const_btree_len)] diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 784839a3ffa..c0f7a11a93e 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1614,10 +1614,10 @@ fn subslice_patterns() { } #[test] -fn test_group_by() { +fn test_chunk_by() { let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); @@ -1625,7 +1625,7 @@ fn test_group_by() { assert_eq!(iter.next(), Some(&[0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); @@ -1633,7 +1633,7 @@ fn test_group_by() { assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by(|a, b| a == b); + let mut iter = slice.chunk_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&[0][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1643,10 +1643,10 @@ fn test_group_by() { } #[test] -fn test_group_by_mut() { +fn test_chunk_by_mut() { let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); @@ -1654,7 +1654,7 @@ fn test_group_by_mut() { assert_eq!(iter.next(), Some(&mut [0][..])); assert_eq!(iter.next(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next_back(), Some(&mut [1][..])); assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); @@ -1662,7 +1662,7 @@ fn test_group_by_mut() { assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), None); - let mut iter = slice.group_by_mut(|a, b| a == b); + let mut iter = slice.chunk_by_mut(|a, b| a == b); assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); assert_eq!(iter.next_back(), Some(&mut [0][..])); assert_eq!(iter.next(), Some(&mut [3, 3][..])); diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index d5ae8cdac1f..38a68df79cc 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -958,23 +958,35 @@ fn test_append() { #[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); - let vec2 = vec.split_off(4); + + let split_off = vec.split_off(4); assert_eq!(vec, [1, 2, 3, 4]); - assert_eq!(vec2, [5, 6]); + assert_eq!(split_off, [5, 6]); assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec.as_ptr(), orig_ptr); } #[test] fn test_split_off_take_all() { - let mut vec = vec![1, 2, 3, 4, 5, 6]; + // Allocate enough capacity that we can tell whether the split-off vector's + // capacity is based on its size, or (incorrectly) on the original capacity. + let mut vec = Vec::with_capacity(1000); + vec.extend([1, 2, 3, 4, 5, 6]); let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); - let vec2 = vec.split_off(0); + + let split_off = vec.split_off(0); assert_eq!(vec, []); - assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); + assert_eq!(split_off, [1, 2, 3, 4, 5, 6]); assert_eq!(vec.capacity(), orig_capacity); - assert_eq!(vec2.as_ptr(), orig_ptr); + assert_eq!(vec.as_ptr(), orig_ptr); + + // The split-off vector should be newly-allocated, and should not have + // stolen the original vector's allocation. + assert!(split_off.capacity() < orig_capacity); + assert_ne!(split_off.as_ptr(), orig_ptr); } #[test] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 9d95b32409c..85cce81f2c1 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -559,8 +559,6 @@ impl<T, const N: usize> [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] - /// /// let floats = [3.1, 2.7, -1.0]; /// let float_refs: [&f64; 3] = floats.each_ref(); /// assert_eq!(float_refs, [&3.1, &2.7, &-1.0]); @@ -571,8 +569,6 @@ impl<T, const N: usize> [T; N] { /// array if its elements are not [`Copy`]. /// /// ``` - /// #![feature(array_methods)] - /// /// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()]; /// let is_ascii = strings.each_ref().map(|s| s.is_ascii()); /// assert_eq!(is_ascii, [true, false, true]); @@ -580,7 +576,7 @@ impl<T, const N: usize> [T; N] { /// // We can still access the original array: it has not been moved. /// assert_eq!(strings.len(), 3); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_ref(&self) -> [&T; N] { from_trusted_iterator(self.iter()) } @@ -592,7 +588,6 @@ impl<T, const N: usize> [T; N] { /// # Example /// /// ``` - /// #![feature(array_methods)] /// /// let mut floats = [3.1, 2.7, -1.0]; /// let float_refs: [&mut f64; 3] = floats.each_mut(); @@ -600,7 +595,7 @@ impl<T, const N: usize> [T; N] { /// assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]); /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_methods", since = "CURRENT_RUSTC_VERSION")] pub fn each_mut(&mut self) -> [&mut T; N] { from_trusted_iterator(self.iter_mut()) } diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index cc872a5343d..5f758af1624 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -537,6 +537,22 @@ impl AsciiChar { } } +macro_rules! into_int_impl { + ($($ty:ty)*) => { + $( + #[unstable(feature = "ascii_char", issue = "110998")] + impl From<AsciiChar> for $ty { + #[inline] + fn from(chr: AsciiChar) -> $ty { + chr as u8 as $ty + } + } + )* + } +} + +into_int_impl!(u8 u16 u32 u64 u128 char); + impl [AsciiChar] { /// Views this slice of ASCII characters as a UTF-8 `str`. #[unstable(feature = "ascii_char", issue = "110998")] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 76a53a9366a..43124535ab5 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2531,7 +2531,7 @@ extern "rust-intrinsic" { /// or `false`, and the caller has to ensure sound behavior for both cases. /// In other words, the following code has *Undefined Behavior*: /// - /// ``` + /// ```no_run /// #![feature(is_val_statically_known)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index d8bbd424cf2..c97a59b614f 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,4 +1,5 @@ -use super::Peekable; +use crate::fmt; +use crate::iter::{Fuse, FusedIterator}; /// An iterator adapter that places a separator between all elements. /// @@ -10,9 +11,18 @@ pub struct Intersperse<I: Iterator> where I::Item: Clone, { + started: bool, separator: I::Item, - iter: Peekable<I>, - needs_sep: bool, + next_item: Option<I::Item>, + iter: Fuse<I>, +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl<I> FusedIterator for Intersperse<I> +where + I: FusedIterator, + I::Item: Clone, +{ } impl<I: Iterator> Intersperse<I> @@ -20,7 +30,7 @@ where I::Item: Clone, { pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + Self { started: false, separator, next_item: None, iter: iter.fuse() } } } @@ -33,27 +43,43 @@ where type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { - if self.needs_sep && self.iter.peek().is_some() { - self.needs_sep = false; - Some(self.separator.clone()) + fn next(&mut self) -> Option<Self::Item> { + if self.started { + if let Some(v) = self.next_item.take() { + Some(v) + } else { + let next_item = self.iter.next(); + if next_item.is_some() { + self.next_item = next_item; + Some(self.separator.clone()) + } else { + None + } + } } else { - self.needs_sep = true; + self.started = true; self.iter.next() } } + fn size_hint(&self) -> (usize, Option<usize>) { + intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) + } + fn fold<B, F>(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { let separator = self.separator; - intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - intersperse_size_hint(&self.iter, self.needs_sep) + intersperse_fold( + self.iter, + init, + f, + move || separator.clone(), + self.started, + self.next_item, + ) } } @@ -66,39 +92,50 @@ pub struct IntersperseWith<I, G> where I: Iterator, { + started: bool, separator: G, - iter: Peekable<I>, - needs_sep: bool, + next_item: Option<I::Item>, + iter: Fuse<I>, +} + +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl<I, G> FusedIterator for IntersperseWith<I, G> +where + I: FusedIterator, + G: FnMut() -> I::Item, +{ } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -impl<I, G> crate::fmt::Debug for IntersperseWith<I, G> +impl<I, G> fmt::Debug for IntersperseWith<I, G> where - I: Iterator + crate::fmt::Debug, - I::Item: crate::fmt::Debug, - G: crate::fmt::Debug, + I: Iterator + fmt::Debug, + I::Item: fmt::Debug, + G: fmt::Debug, { - fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("IntersperseWith") + .field("started", &self.started) .field("separator", &self.separator) .field("iter", &self.iter) - .field("needs_sep", &self.needs_sep) + .field("next_item", &self.next_item) .finish() } } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -impl<I, G> crate::clone::Clone for IntersperseWith<I, G> +impl<I, G> Clone for IntersperseWith<I, G> where - I: Iterator + crate::clone::Clone, - I::Item: crate::clone::Clone, + I: Iterator + Clone, + I::Item: Clone, G: Clone, { fn clone(&self) -> Self { - IntersperseWith { + Self { + started: self.started, separator: self.separator.clone(), iter: self.iter.clone(), - needs_sep: self.needs_sep.clone(), + next_item: self.next_item.clone(), } } } @@ -109,7 +146,7 @@ where G: FnMut() -> I::Item, { pub(in crate::iter) fn new(iter: I, separator: G) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + Self { started: false, separator, next_item: None, iter: iter.fuse() } } } @@ -122,38 +159,52 @@ where type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { - if self.needs_sep && self.iter.peek().is_some() { - self.needs_sep = false; - Some((self.separator)()) + fn next(&mut self) -> Option<Self::Item> { + if self.started { + if let Some(v) = self.next_item.take() { + Some(v) + } else { + let next_item = self.iter.next(); + if next_item.is_some() { + self.next_item = next_item; + Some((self.separator)()) + } else { + None + } + } } else { - self.needs_sep = true; + self.started = true; self.iter.next() } } + fn size_hint(&self) -> (usize, Option<usize>) { + intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) + } + fn fold<B, F>(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - intersperse_fold(self.iter, init, f, self.separator, self.needs_sep) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - intersperse_size_hint(&self.iter, self.needs_sep) + intersperse_fold(self.iter, init, f, self.separator, self.started, self.next_item) } } -fn intersperse_size_hint<I>(iter: &I, needs_sep: bool) -> (usize, Option<usize>) +fn intersperse_size_hint<I>(iter: &I, started: bool, next_is_some: bool) -> (usize, Option<usize>) where I: Iterator, { let (lo, hi) = iter.size_hint(); - let next_is_elem = !needs_sep; ( - lo.saturating_sub(next_is_elem as usize).saturating_add(lo), - hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)), + lo.saturating_sub(!started as usize) + .saturating_add(next_is_some as usize) + .saturating_add(lo), + hi.and_then(|hi| { + hi.saturating_sub(!started as usize) + .saturating_add(next_is_some as usize) + .checked_add(hi) + }), ) } @@ -162,7 +213,8 @@ fn intersperse_fold<I, B, F, G>( init: B, mut f: F, mut separator: G, - needs_sep: bool, + started: bool, + mut next_item: Option<I::Item>, ) -> B where I: Iterator, @@ -171,12 +223,9 @@ where { let mut accum = init; - if !needs_sep { - if let Some(x) = iter.next() { - accum = f(accum, x); - } else { - return accum; - } + let first = if started { next_item.take() } else { iter.next() }; + if let Some(x) = first { + accum = f(accum, x); } iter.fold(accum, |mut accum, x| { diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 408002d18ca..959c3289aff 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1893,7 +1893,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c2b646b9b3e..03c977abbbb 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -61,7 +61,15 @@ pub use dec2flt::ParseFloatError; #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; -pub(crate) use nonzero::NonZero; +#[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +pub use nonzero::ZeroablePrimitive; + +#[unstable(feature = "generic_nonzero", issue = "120257")] +pub use nonzero::NonZero; #[stable(feature = "nonzero", since = "1.28.0")] pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 45ac544ceaa..1124719fc8d 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -3,6 +3,8 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash::{Hash, Hasher}; +#[cfg(bootstrap)] +use crate::marker::StructuralEq; use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; use crate::str::FromStr; @@ -30,9 +32,7 @@ mod private { issue = "none" )] #[const_trait] -pub trait ZeroablePrimitive: Sized + Copy + private::Sealed { - type NonZero; -} +pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {} macro_rules! impl_zeroable_primitive { ($NonZero:ident ( $primitive:ty )) => { @@ -48,9 +48,7 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const ZeroablePrimitive for $primitive { - type NonZero = $NonZero; - } + impl const ZeroablePrimitive for $primitive {} }; } @@ -67,12 +65,23 @@ impl_zeroable_primitive!(NonZeroI64(i64)); impl_zeroable_primitive!(NonZeroI128(i128)); impl_zeroable_primitive!(NonZeroIsize(isize)); -#[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" -)] -pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero; +/// A value that is known not to equal zero. +/// +/// This enables some memory layout optimization. +/// For example, `Option<NonZero<u32>>` is the same size as `u32`: +/// +/// ``` +/// #![feature(generic_nonzero)] +/// use core::mem::size_of; +/// +/// assert_eq!(size_of::<Option<core::num::NonZero<u32>>>(), size_of::<u32>()); +/// ``` +#[unstable(feature = "generic_nonzero", issue = "120257")] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +#[rustc_nonnull_optimization_guaranteed] +#[rustc_diagnostic_item = "NonZero"] +pub struct NonZero<T: ZeroablePrimitive>(T); macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { @@ -131,12 +140,7 @@ macro_rules! nonzero_integer { /// /// [null pointer optimization]: crate::option#representation #[$stability] - #[derive(Copy, Eq)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - #[rustc_diagnostic_item = stringify!($Ty)] - pub struct $Ty($Int); + pub type $Ty = NonZero<$Int>; impl $Ty { /// Creates a non-zero without checking whether the value is non-zero. @@ -544,6 +548,9 @@ macro_rules! nonzero_integer { } #[$stability] + impl Copy for $Ty {} + + #[$stability] impl PartialEq for $Ty { #[inline] fn eq(&self, other: &Self) -> bool { @@ -560,6 +567,13 @@ macro_rules! nonzero_integer { impl StructuralPartialEq for $Ty {} #[$stability] + impl Eq for $Ty {} + + #[unstable(feature = "structural_match", issue = "31434")] + #[cfg(bootstrap)] + impl StructuralEq for $Ty {} + + #[$stability] impl PartialOrd for $Ty { #[inline] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index bb6c81a486a..a0227d9130b 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1092,14 +1092,20 @@ pub struct Pin<Ptr> { // - deter downstream users from accessing it (which would be unsound!), // - let the `pin!` macro access it (such a macro requires using struct // literal syntax in order to benefit from lifetime extension). - // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives. + // + // However, if the `Deref` impl exposes a field with the same name as this + // field, then the two will collide, resulting in a confusing error when the + // user attempts to access the field through a `Pin<Ptr>`. Therefore, the + // name `__pointer` is designed to be unlikely to collide with any other + // field. Long-term, macro hygiene is expected to offer a more robust + // alternative, alongside `unsafe` fields. #[unstable(feature = "unsafe_pin_internals", issue = "none")] #[doc(hidden)] - pub pointer: Ptr, + pub __pointer: Ptr, } // The following implementations aren't derived in order to avoid soundness -// issues. `&self.pointer` should not be accessible to untrusted trait +// issues. `&self.__pointer` should not be accessible to untrusted trait // implementations. // // See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73> for more details. @@ -1212,7 +1218,7 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin<Ptr>) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1349,7 +1355,7 @@ impl<Ptr: Deref> Pin<Ptr> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin<Ptr> { - Pin { pointer } + Pin { __pointer: pointer } } /// Gets a shared reference to the pinned value this [`Pin`] points to. @@ -1363,7 +1369,7 @@ impl<Ptr: Deref> Pin<Ptr> { #[inline(always)] pub fn as_ref(&self) -> Pin<&Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&*self.pointer) } + unsafe { Pin::new_unchecked(&*self.__pointer) } } /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`. @@ -1388,7 +1394,7 @@ impl<Ptr: Deref> Pin<Ptr> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr { - pin.pointer + pin.__pointer } } @@ -1426,7 +1432,7 @@ impl<Ptr: DerefMut> Pin<Ptr> { #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { // SAFETY: see documentation on this function - unsafe { Pin::new_unchecked(&mut *self.pointer) } + unsafe { Pin::new_unchecked(&mut *self.__pointer) } } /// Assigns a new value to the memory location pointed to by the `Pin<Ptr>`. @@ -1455,7 +1461,7 @@ impl<Ptr: DerefMut> Pin<Ptr> { where Ptr::Target: Sized, { - *(self.pointer) = value; + *(self.__pointer) = value; } } @@ -1481,7 +1487,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { U: ?Sized, F: FnOnce(&T) -> &U, { - let pointer = &*self.pointer; + let pointer = &*self.__pointer; let new_pointer = func(pointer); // SAFETY: the safety contract for `new_unchecked` must be @@ -1511,7 +1517,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn get_ref(self) -> &'a T { - self.pointer + self.__pointer } } @@ -1522,7 +1528,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] pub const fn into_ref(self) -> Pin<&'a T> { - Pin { pointer: self.pointer } + Pin { __pointer: self.__pointer } } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1542,7 +1548,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { where T: Unpin, { - self.pointer + self.__pointer } /// Gets a mutable reference to the data inside of this `Pin`. @@ -1560,7 +1566,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const unsafe fn get_unchecked_mut(self) -> &'a mut T { - self.pointer + self.__pointer } /// Construct a new pin by mapping the interior value. @@ -1684,21 +1690,21 @@ impl<Ptr: Receiver> Receiver for Pin<Ptr> {} #[stable(feature = "pin", since = "1.33.0")] impl<Ptr: fmt::Debug> fmt::Debug for Pin<Ptr> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.pointer, f) + fmt::Debug::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl<Ptr: fmt::Display> fmt::Display for Pin<Ptr> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.pointer, f) + fmt::Display::fmt(&self.__pointer, f) } } #[stable(feature = "pin", since = "1.33.0")] impl<Ptr: fmt::Pointer> fmt::Pointer for Pin<Ptr> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.pointer, f) + fmt::Pointer::fmt(&self.__pointer, f) } } @@ -1941,16 +1947,16 @@ pub macro pin($value:expr $(,)?) { // instead, dropped _at the end of the enscoping block_. // For instance, // ```rust - // let p = Pin { pointer: &mut <temporary> }; + // let p = Pin { __pointer: &mut <temporary> }; // ``` // becomes: // ```rust // let mut anon = <temporary>; - // let p = Pin { pointer: &mut anon }; + // let p = Pin { __pointer: &mut anon }; // ``` // which is *exactly* what we want. // // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension // for more info. - $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } + $crate::pin::Pin::<&mut _> { __pointer: &mut { $value } } } diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 7dee30585e9..bf47d767a92 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1384,6 +1384,30 @@ mod prim_usize {} /// work on references as well as they do on owned values! The implementations described here are /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not /// locally known. +/// +/// # Safety +/// +/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API +/// boundary, the following invariants must generally be upheld: +/// +/// * `t` is aligned to `align_of_val(t)` +/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// +/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range +/// `[a, a + N)` is all contained within a single [allocated object]. +/// +/// For instance, this means that unsafe code in a safe function may assume these invariants are +/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured +/// of return values from any safe functions it calls. In most cases, the inverse is also true: +/// unsafe code must not violate these invariants when passing arguments to safe functions or +/// returning values from safe functions; such violations may result in undefined behavior. Where +/// exceptions to this latter requirement exist, they will be called out explicitly in documentation. +/// +/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal +/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data +/// may become unsound in future versions of Rust depending on how this question is decided. +/// +/// [allocated object]: ptr#allocated-object #[stable(feature = "rust1", since = "1.0.0")] mod prim_ref {} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1c65475b81d..2d4c7e78aea 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3248,26 +3248,26 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// -/// This struct is created by the [`group_by`] method on [slices]. +/// This struct is created by the [`chunk_by`] method on [slices]. /// -/// [`group_by`]: slice::group_by +/// [`chunk_by`]: slice::chunk_by /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupBy<'a, T: 'a, P> { +pub struct ChunkBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkBy<'a, T, P> { pub(super) fn new(slice: &'a [T], predicate: P) -> Self { - GroupBy { slice, predicate } + ChunkBy { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3300,8 +3300,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3322,39 +3322,39 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupBy").field("slice", &self.slice).finish() + f.debug_struct("ChunkBy").field("slice", &self.slice).finish() } } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. /// -/// This struct is created by the [`group_by_mut`] method on [slices]. +/// This struct is created by the [`chunk_by_mut`] method on [slices]. /// -/// [`group_by_mut`]: slice::group_by_mut +/// [`chunk_by_mut`]: slice::chunk_by_mut /// [slices]: slice -#[unstable(feature = "slice_group_by", issue = "80552")] +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct GroupByMut<'a, T: 'a, P> { +pub struct ChunkByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> ChunkByMut<'a, T, P> { pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self { - GroupByMut { slice, predicate } + ChunkByMut { slice, predicate } } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> Iterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3388,8 +3388,8 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> DoubleEndedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3411,12 +3411,12 @@ where } } -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P> FusedIterator for ChunkByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[unstable(feature = "slice_group_by", issue = "80552")] -impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> { +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkByMut<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GroupByMut").field("slice", &self.slice).finish() + f.debug_struct("ChunkByMut").field("slice", &self.slice).finish() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 27dda478848..2d93ef6fbeb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -68,8 +68,8 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; -#[unstable(feature = "slice_group_by", issue = "80552")] -pub use iter::{GroupBy, GroupByMut}; +#[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] +pub use iter::{ChunkBy, ChunkByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; @@ -1748,18 +1748,16 @@ impl<T> [T] { /// Returns an iterator over the slice producing non-overlapping runs /// of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by(|a, b| a == b); + /// let mut iter = slice.chunk_by(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&[3, 3][..])); @@ -1770,41 +1768,37 @@ impl<T> [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by(|a, b| a <= b); + /// let mut iter = slice.chunk_by(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3][..])); /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by<F>(&self, pred: F) -> GroupBy<'_, T, F> + pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupBy::new(self, pred) + ChunkBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable /// runs of elements using the predicate to separate them. /// - /// The predicate is called on two elements following themselves, - /// it means the predicate is called on `slice[0]` and `slice[1]` - /// then on `slice[1]` and `slice[2]` and so on. + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. /// /// # Examples /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; /// - /// let mut iter = slice.group_by_mut(|a, b| a == b); + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); @@ -1815,24 +1809,22 @@ impl<T> [T] { /// This method can be used to extract the sorted subslices: /// /// ``` - /// #![feature(slice_group_by)] - /// /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; /// - /// let mut iter = slice.group_by_mut(|a, b| a <= b); + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); /// /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "80552")] + #[stable(feature = "slice_group_by", since = "CURRENT_RUSTC_VERSION")] #[inline] - pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F> + pub fn chunk_by_mut<F>(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> bool, { - GroupByMut::new(self, pred) + ChunkByMut::new(self, pred) } /// Divides one slice into two at an index. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 0f23cf7ae23..ba282f09d20 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -1,6 +1,6 @@ //! Ways to create a `str` from bytes slice. -use crate::mem; +use crate::{mem, ptr}; use super::validations::run_utf8_validation; use super::Utf8Error; @@ -205,3 +205,41 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // comes from a reference which is guaranteed to be valid for writes. unsafe { &mut *(v as *mut [u8] as *mut str) } } + +/// Creates an `&str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts`](crate::slice::from_raw_parts). +/// See that function's documentation for safety concerns and examples. +/// +/// The mutable version of this function is [`from_raw_parts_mut`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] +pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::from_raw_parts(ptr.cast(), len) } +} + +/// Creates an `&mut str` from a pointer and a length. +/// +/// The pointed-to bytes must be valid UTF-8. +/// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, +/// which will return an `Err` if the data isn't valid UTF-8. +/// +/// This function is the `str` equivalent of [`slice::from_raw_parts_mut`](crate::slice::from_raw_parts_mut). +/// See that function's documentation for safety concerns and examples. +/// +/// The immutable version of this function is [`from_raw_parts`]. +#[inline] +#[must_use] +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +#[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] +pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a str { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::from_raw_parts_mut(ptr.cast(), len) } +} diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index dd2efb00516..4d6239e11a3 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1187,6 +1187,31 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Lines<'_> {} +impl<'a> Lines<'a> { + /// Returns the remaining lines of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_lines_remainder)] + /// + /// let mut lines = "a\nb\nc\nd".lines(); + /// assert_eq!(lines.remainder(), Some("a\nb\nc\nd")); + /// + /// lines.next(); + /// assert_eq!(lines.remainder(), Some("b\nc\nd")); + /// + /// lines.by_ref().for_each(drop); + /// assert_eq!(lines.remainder(), None); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "str_lines_remainder", issue = "77998")] + pub fn remainder(&self) -> Option<&'a str> { + self.0.iter.remainder() + } +} + /// Created with the method [`lines_any`]. /// /// [`lines_any`]: str::lines_any diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 80c5fe0de8d..ecc0613d7b9 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -33,6 +33,9 @@ pub use converts::{from_utf8, from_utf8_unchecked}; #[stable(feature = "str_mut_extras", since = "1.20.0")] pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use converts::{from_raw_parts, from_raw_parts_mut}; + #[stable(feature = "rust1", since = "1.0.0")] pub use error::{ParseBoolError, Utf8Error}; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 89d2b5ef093..9a3b477c2d1 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] -#![feature(array_methods)] #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] @@ -101,7 +100,6 @@ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(int_roundings)] -#![feature(slice_group_by)] #![feature(split_array)] #![feature(strict_provenance)] #![feature(strict_provenance_atomic_ptr)] diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index b63091deac2..13cc0511e10 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -816,12 +816,12 @@ impl Error { } } - /// Attempt to downgrade the inner error to `E` if any. + /// Attempt to downcast the inner error to `E` if any. /// /// If this [`Error`] was constructed via [`new`] then this function will /// attempt to perform downgrade on it, otherwise it will return [`Err`]. /// - /// If downgrade succeeds, it will return [`Ok`], otherwise it will also + /// If the downcast succeeds, it will return [`Ok`], otherwise it will also /// return [`Err`]. /// /// [`new`]: Error::new @@ -852,13 +852,39 @@ impl Error { /// impl From<io::Error> for E { /// fn from(err: io::Error) -> E { /// err.downcast::<E>() - /// .map(|b| *b) /// .unwrap_or_else(E::Io) /// } /// } + /// + /// impl From<E> for io::Error { + /// fn from(err: E) -> io::Error { + /// match err { + /// E::Io(io_error) => io_error, + /// e => io::Error::new(io::ErrorKind::Other, e), + /// } + /// } + /// } + /// + /// # fn main() { + /// let e = E::SomeOtherVariant; + /// // Convert it to an io::Error + /// let io_error = io::Error::from(e); + /// // Cast it back to the original variant + /// let e = E::from(io_error); + /// assert!(matches!(e, E::SomeOtherVariant)); + /// + /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists); + /// // Convert it to E + /// let e = E::from(io_error); + /// // Cast it back to the original variant + /// let io_error = io::Error::from(e); + /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists); + /// assert!(io_error.get_ref().is_none()); + /// assert!(io_error.raw_os_error().is_none()); + /// # } /// ``` #[unstable(feature = "io_error_downcast", issue = "99262")] - pub fn downcast<E>(self) -> result::Result<Box<E>, Self> + pub fn downcast<E>(self) -> result::Result<E, Self> where E: error::Error + Send + Sync + 'static, { @@ -872,7 +898,7 @@ impl Error { // And the compiler should be able to eliminate the branch // that produces `Err` here since b.error.is::<E>() // returns true. - Ok(res.unwrap()) + Ok(*res.unwrap()) } repr_data => Err(Self { repr: Repr::new(repr_data) }), } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 36d52aef03c..fc6db2825e8 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -157,7 +157,7 @@ impl error::Error for E {} fn test_std_io_error_downcast() { // Case 1: custom error, downcast succeeds let io_error = Error::new(ErrorKind::Other, Bojji(true)); - let e: Box<Bojji> = io_error.downcast().unwrap(); + let e: Bojji = io_error.downcast().unwrap(); assert!(e.0); // Case 2: custom error, downcast fails @@ -166,7 +166,7 @@ fn test_std_io_error_downcast() { // ensures that the custom error is intact assert_eq!(ErrorKind::Other, io_error.kind()); - let e: Box<Bojji> = io_error.downcast().unwrap(); + let e: Bojji = io_error.downcast().unwrap(); assert!(e.0); // Case 3: os error diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 05b21eeb40f..261b570dee7 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,9 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{ + self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, +}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -483,6 +485,13 @@ impl Read for StdinLock<'_> { } } +impl SpecReadByte for StdinLock<'_> { + #[inline] + fn spec_read_byte(&mut self) -> Option<io::Result<u8>> { + BufReader::spec_read_byte(&mut *self.inner) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for StdinLock<'_> { fn fill_buf(&mut self) -> io::Result<&[u8]> { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 751e988a99b..2e458562744 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -323,6 +323,7 @@ #![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(float_next_up_down)] +#![feature(generic_nonzero)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_assert_unchecked)] diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 55f6ddcf77f..1343fdfd1df 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -16,6 +16,16 @@ pub use core::num::Wrapping; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError}; +#[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +pub use core::num::ZeroablePrimitive; + +#[unstable(feature = "generic_nonzero", issue = "120257")] +pub use core::num::NonZero; + #[stable(feature = "signed_nonzero", since = "1.34.0")] pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; #[stable(feature = "nonzero", since = "1.28.0")] diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index d53ea16005f..270eca37b14 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -95,7 +95,7 @@ static HEAP: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut()); #[inline] fn init_or_get_process_heap() -> c::HANDLE { let heap = HEAP.load(Ordering::Relaxed); - if heap.is_null() { + if core::intrinsics::unlikely(heap.is_null()) { // `HEAP` has not yet been successfully initialized let heap = unsafe { GetProcessHeap() }; if !heap.is_null() { @@ -115,6 +115,16 @@ fn init_or_get_process_heap() -> c::HANDLE { } } +#[inline(never)] +fn process_heap_alloc(flags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID { + let heap = init_or_get_process_heap(); + if core::intrinsics::unlikely(heap.is_null()) { + return ptr::null_mut(); + } + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. + unsafe { HeapAlloc(heap, flags, dwBytes) } +} + // Get a non-null handle to the default heap of the current process. // SAFETY: `HEAP` must have been successfully initialized. #[inline] @@ -133,25 +143,17 @@ struct Header(*mut u8); // initialized. #[inline] unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { - let heap = init_or_get_process_heap(); - if heap.is_null() { - // Allocation has failed, could not get the current process heap. - return ptr::null_mut(); - } - // Allocated memory will be either zeroed or uninitialized. let flags = if zeroed { HEAP_ZERO_MEMORY } else { 0 }; if layout.align() <= MIN_ALIGN { - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. // The returned pointer points to the start of an allocated block. - unsafe { HeapAlloc(heap, flags, layout.size()) as *mut u8 } + process_heap_alloc(flags, layout.size()) as *mut u8 } else { // Allocate extra padding in order to be able to satisfy the alignment. let total = layout.align() + layout.size(); - // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. - let ptr = unsafe { HeapAlloc(heap, flags, total) as *mut u8 }; + let ptr = process_heap_alloc(flags, total) as *mut u8; if ptr.is_null() { // Allocation has failed. return ptr::null_mut(); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index e06bc3fb09a..043473287fc 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1116,16 +1116,11 @@ pub fn rustc_cargo_env( /// Pass down configuration from the LLVM build into the build of /// rustc_llvm and rustc_codegen_llvm. fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { - let target_config = builder.config.target_config.get(&target); - if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); cargo.env("LLVM_CONFIG", &llvm_config); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 55eed95492d..0db61204f77 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -74,25 +74,6 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then cksum=$(sha512sum $hash_key | \ awk '{print $1}') - - url="https://$CACHE_DOMAIN/docker/$cksum" - - echo "Attempting to download $url" - rm -f /tmp/rustci_docker_cache - set +e - retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \ - -o /tmp/rustci_docker_cache "$url" - - docker_archive_hash=$(sha512sum /tmp/rustci_docker_cache | awk '{print $1}') - echo "Downloaded archive hash: ${docker_archive_hash}" - - echo "Loading images into docker" - # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM, - # KILL after 12 minutes - loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \ - | sed 's/.* sha/sha/') - set -e - printf "Downloaded containers:\n$loaded_images\n" fi dockerfile="$docker_dir/$image/Dockerfile" @@ -103,46 +84,65 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then context="$script_dir" fi echo "::group::Building docker image for $image" - - # As of August 2023, Github Actions have updated Docker to 23.X, - # which uses the BuildKit by default. It currently throws aways all - # intermediate layers, which breaks our usage of S3 layer caching. - # Therefore we opt-in to the old build backend for now. - export DOCKER_BUILDKIT=0 - retry docker \ - build \ - --rm \ - -t rust-ci \ - -f "$dockerfile" \ - "$context" - echo "::endgroup::" - - if [ "$CI" != "" ]; then - s3url="s3://$SCCACHE_BUCKET/docker/$cksum" - upload="aws s3 cp - $s3url" - digest=$(docker inspect rust-ci --format '{{.Id}}') - echo "Built container $digest" - if ! grep -q "$digest" <(echo "$loaded_images"); then - echo "Uploading finished image $digest to $url" - set +e - # Print image history for easier debugging of layer SHAs - docker history rust-ci - docker history -q rust-ci | \ - grep -v missing | \ - xargs docker save | \ - gzip | \ - $upload - set -e - else - echo "Looks like docker image is the same as before, not uploading" - fi - # Record the container image for reuse, e.g. by rustup.rs builds - info="$dist/image-$image.txt" - mkdir -p "$dist" - echo "$url" >"$info" - echo "$digest" >>"$info" - cat "$info" + echo "Image input" + cat $hash_key + echo "Image input checksum ${cksum}" + + # Print docker version + docker --version + + # On non-CI or PR jobs, we don't have permissions to write to the registry cache, so we should + # not use `docker login` nor caching. + if [[ "$CI" == "" ]] || [[ "$PR_CI_JOB" == "1" ]]; + then + retry docker build --rm -t rust-ci -f "$dockerfile" "$context" + else + REGISTRY=ghcr.io + # Most probably rust-lang-ci, but in general the owner of the repository where CI runs + REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER} + # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup + IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum} + # Tag used to cache the Docker build + # It seems that it cannot be the same as $IMAGE_TAG, otherwise it overwrites the cache + CACHE_IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci-cache:${cksum} + + # Log into the Docker registry, so that we can read/write cache and the final image + echo ${DOCKER_TOKEN} | docker login ${REGISTRY} \ + --username ${REGISTRY_USERNAME} \ + --password-stdin + + # Enable a new Docker driver so that --cache-from/to works with a registry backend + docker buildx create --use --driver docker-container + + # Build the image using registry caching backend + retry docker \ + buildx \ + build \ + --rm \ + -t rust-ci \ + -f "$dockerfile" \ + --cache-from type=registry,ref=${CACHE_IMAGE_TAG} \ + --cache-to type=registry,ref=${CACHE_IMAGE_TAG},compression=zstd \ + --output=type=docker \ + "$context" + + # Print images for debugging purposes + docker images + + # Tag the built image and push it to the registry + docker tag rust-ci "${IMAGE_TAG}" + docker push "${IMAGE_TAG}" + + # Record the container registry tag/url for reuse, e.g. by rustup.rs builds + # It should be possible to run `docker pull <$IMAGE_TAG>` to download the image + info="$dist/image-$image.txt" + mkdir -p "$dist" + echo "${IMAGE_TAG}" > "$info" + cat "$info" + + echo "To download the image, run docker pull ${IMAGE_TAG}" fi + echo "::endgroup::" elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then if isCI; then echo Cannot run disabled images on CI! diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 68a3afc910f..ceee4690004 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -34,6 +34,7 @@ x--expand-yaml-anchors--remove: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - &public-variables SCCACHE_BUCKET: rust-lang-ci-sccache2 @@ -301,6 +302,7 @@ on: permissions: contents: read + packages: write defaults: run: diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index a54abcb606e..e72bfb8bae7 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -50,6 +50,7 @@ cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" [target.csky-unknown-linux-gnuabiv2hf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN cc = "${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc" +``` ### Build diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 624d8cc5cc5..5e0c21a13a9 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -41,40 +41,7 @@ </Expand> </Type> - <Type Name="core::num::nonzero::NonZeroI8"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroI16"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroI32"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroI64"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroI128"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroIsize"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroU8"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroU16"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroU32"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroU64"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroU128"> - <DisplayString>{__0}</DisplayString> - </Type> - <Type Name="core::num::nonzero::NonZeroUsize"> + <Type Name="core::num::nonzero::NonZero<*>"> <DisplayString>{__0}</DisplayString> </Type> @@ -99,9 +66,9 @@ </Type> <Type Name="core::pin::Pin<*>"> - <DisplayString>Pin({(void*)pointer}: {pointer})</DisplayString> + <DisplayString>Pin({(void*)__pointer}: {__pointer})</DisplayString> <Expand> - <ExpandedItem>pointer</ExpandedItem> + <ExpandedItem>__pointer</ExpandedItem> </Expand> </Type> diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8706abda979..e1829da6e2c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,6 +15,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; +use rustc_errors::{codes::*, struct_span_code_err, FatalError}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; @@ -2271,7 +2272,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Placeholder(..) => panic!("Placeholder"), ty::CoroutineWitness(..) => panic!("CoroutineWitness"), ty::Infer(..) => panic!("Infer"), - ty::Error(_) => rustc_errors::FatalError.raise(), + ty::Error(_) => FatalError.raise(), } } @@ -2995,7 +2996,7 @@ fn clean_use_statement_inner<'tcx>( visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module(); if pub_underscore && let Some(ref inline) = inline_attr { - rustc_errors::struct_span_code_err!( + struct_span_code_err!( cx.tcx.dcx(), inline.span(), E0780, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7cf385de6b7..9eb62c25892 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::emitter::{DynEmitter, HumanEmitter}; use rustc_errors::json::JsonEmitter; -use rustc_errors::TerminalUrl; +use rustc_errors::{codes::*, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 658ed862ae7..8c10f14116a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,7 +3,6 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] -#![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 4d32bbec914..5fa45ceeb39 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5606,6 +5606,7 @@ Released 2018-09-13 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl +[`suspicious_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_open_options [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn [`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned @@ -5814,6 +5815,7 @@ Released 2018-09-13 [`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles +[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 3b62ae0524a..7f7aff92bf1 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -212,7 +212,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", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "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"]` --- **Affected lints:** @@ -768,7 +768,19 @@ Additional dotfiles (files or directories starting with a dot) to allow * [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) +## `allowed-duplicate-crates` +A list of crate names to allow duplicates of + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) + + ## `enforce-iter-loop-reborrow` +Whether to recommend using implicit into iter for reborrowed values. + #### Example ```no_run let mut vec = vec![1, 2, 3]; @@ -793,7 +805,7 @@ for _ in &mut *rmvec {} ## `check-private-items` - +Whether to also run the listed lints on private items. **Default Value:** `false` @@ -806,9 +818,10 @@ for _ in &mut *rmvec {} ## `pub-underscore-fields-behavior` +Lint "public" fields in a struct that are prefixed with an underscore based on their +exported visibility, or whether they are marked as "pub". - -**Default Value:** `"PublicallyExported"` +**Default Value:** `"PubliclyExported"` --- **Affected lints:** diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 5477d9b83a7..4e9ddbf8259 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -2,7 +2,9 @@ use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_session::Session; +use rustc_span::edit_distance::edit_distance; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; use serde::de::{IgnoredAny, IntoDeserializer, MapAccess, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; @@ -26,7 +28,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", - "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", + "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", @@ -59,18 +61,25 @@ impl TryConf { #[derive(Debug)] struct ConfError { message: String, + suggestion: Option<Suggestion>, span: Span, } impl ConfError { fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { let span = error.span().unwrap_or(0..file.source_len.0 as usize); - Self::spanned(file, error.message(), span) + Self::spanned(file, error.message(), None, span) } - fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self { + fn spanned( + file: &SourceFile, + message: impl Into<String>, + suggestion: Option<Suggestion>, + span: Range<usize>, + ) -> Self { Self { message: message.into(), + suggestion, span: Span::new( file.start_pos + BytePos::from_usize(span.start), file.start_pos + BytePos::from_usize(span.end), @@ -147,16 +156,18 @@ macro_rules! define_Conf { match Field::deserialize(name.get_ref().as_str().into_deserializer()) { Err(e) => { let e: FieldError = e; - errors.push(ConfError::spanned(self.0, e.0, name.span())); + errors.push(ConfError::spanned(self.0, e.error, e.suggestion, name.span())); } $(Ok(Field::$name) => { - $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)? + $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? let raw_value = map.next_value::<toml::Spanned<toml::Value>>()?; let value_span = raw_value.span(); match <$ty>::deserialize(raw_value.into_inner()) { - Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)), + Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), None, value_span)), Ok(value) => match $name { - Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())), + Some(_) => { + errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); + } None => { $name = Some(value); // $new_conf is the same as one of the defined `$name`s, so @@ -165,7 +176,7 @@ macro_rules! define_Conf { Some(_) => errors.push(ConfError::spanned(self.0, concat!( "duplicate field `", stringify!($new_conf), "` (provided as `", stringify!($name), "`)" - ), name.span())), + ), None, name.span())), None => $new_conf = $name.clone(), })? }, @@ -523,7 +534,11 @@ define_Conf! { /// /// Additional dotfiles (files or directories starting with a dot) to allow (allowed_dotfiles: FxHashSet<String> = FxHashSet::default()), - /// Lint: EXPLICIT_ITER_LOOP + /// Lint: MULTIPLE_CRATE_VERSIONS. + /// + /// A list of crate names to allow duplicates of + (allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default()), + /// Lint: EXPLICIT_ITER_LOOP. /// /// Whether to recommend using implicit into iter for reborrowed values. /// @@ -543,15 +558,15 @@ define_Conf! { /// for _ in &mut *rmvec {} /// ``` (enforce_iter_loop_reborrow: bool = false), - /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC + /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. /// /// Whether to also run the listed lints on private items. (check_private_items: bool = false), - /// Lint: PUB_UNDERSCORE_FIELDS + /// Lint: PUB_UNDERSCORE_FIELDS. /// /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". - (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PublicallyExported), + (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported), } /// Search for the configuration file. @@ -669,10 +684,16 @@ impl Conf { // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - sess.dcx().span_err( + let mut diag = sess.dcx().struct_span_err( error.span, format!("error reading Clippy's configuration file: {}", error.message), ); + + if let Some(sugg) = error.suggestion { + diag.span_suggestion(error.span, sugg.message, sugg.suggestion, Applicability::MaybeIncorrect); + } + + diag.emit(); } for warning in warnings { @@ -689,19 +710,31 @@ impl Conf { const SEPARATOR_WIDTH: usize = 4; #[derive(Debug)] -struct FieldError(String); +struct FieldError { + error: String, + suggestion: Option<Suggestion>, +} + +#[derive(Debug)] +struct Suggestion { + message: &'static str, + suggestion: &'static str, +} impl std::error::Error for FieldError {} impl Display for FieldError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.pad(&self.0) + f.pad(&self.error) } } impl serde::de::Error for FieldError { fn custom<T: Display>(msg: T) -> Self { - Self(msg.to_string()) + Self { + error: msg.to_string(), + suggestion: None, + } } fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { @@ -723,7 +756,20 @@ impl serde::de::Error for FieldError { write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap(); } } - Self(msg) + + let suggestion = expected + .iter() + .filter_map(|expected| { + let dist = edit_distance(field, expected, 4)?; + Some((dist, expected)) + }) + .min_by_key(|&(dist, _)| dist) + .map(|(_, suggestion)| Suggestion { + message: "perhaps you meant", + suggestion, + }); + + Self { error: msg, suggestion } } } diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs index f5dcb16d670..533e375a310 100644 --- a/src/tools/clippy/clippy_config/src/lib.rs +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -11,6 +11,7 @@ extern crate rustc_ast; extern crate rustc_data_structures; #[allow(unused_extern_crates)] extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_session; extern crate rustc_span; diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs index baee09629ac..435aa9244c5 100644 --- a/src/tools/clippy/clippy_config/src/types.rs +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -129,6 +129,6 @@ unimplemented_serialize! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum PubUnderscoreFieldsBehaviour { - PublicallyExported, + PubliclyExported, AllPubFields, } diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index ce738e3f4ec..5ec67554e7d 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -4,11 +4,11 @@ version = "0.0.1" edition = "2021" [dependencies] -aho-corasick = "0.7" +aho-corasick = "1.0" clap = "4.1.4" indoc = "1.0" itertools = "0.11" -opener = "0.5" +opener = "0.6" shell-escape = "0.1" walkdir = "2.3" diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 6b76a44debf..2222abff7ad 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -504,9 +504,8 @@ fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<S } let searcher = AhoCorasickBuilder::new() - .dfa(true) .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build_with_size::<u16, _, _>(replacements.iter().map(|&(x, _)| x.as_bytes())) + .build(replacements.iter().map(|&(x, _)| x.as_bytes())) .unwrap(); let mut result = String::with_capacity(contents.len() + 1024); @@ -928,7 +927,7 @@ fn remove_line_splices(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { + unescape::unescape_unicode(s, unescape::Mode::Str, &mut |range, ch| { if ch.is_ok() { res.push_str(&s[range]); } diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 8cba35f3d87..416e9a680dd 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } -cargo_metadata = "0.15.3" +cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 657d52d0e9e..1102c7fb236 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -14,10 +14,10 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// `Arc<T>` is an Atomic `RC<T>` and guarantees that updates to the reference counter are - /// Atomic. This is useful in multiprocessing scenarios. To send an `Arc<T>` across processes - /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), - /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` + /// `Arc<T>` is a thread-safe `Rc<T>` and guarantees that updates to the reference counter + /// use atomic operations. To send an `Arc<T>` across thread boundaries and + /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety), + /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs index 1417e230aee..ff4dffd0607 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -67,6 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { ); if let ExprKind::Block(block, _) = &cond.kind { + if !block.span.eq_ctxt(expr.span) { + // If the block comes from a macro, or as an argument to a macro, + // do not lint. + return; + } if block.rules == BlockCheckMode::DefaultBlock { if block.stmts.is_empty() { if let Some(ex) = &block.expr { diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index fea6924d89e..d8107f61f37 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -6,6 +6,7 @@ mod wildcard_dependencies; use cargo_metadata::MetadataCommand; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::impl_lint_pass; @@ -128,6 +129,8 @@ declare_clippy_lint! { /// ### Known problems /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. + /// In those cases, you can allow that specific crate using + /// the `allowed_duplicate_crates` configuration option. /// /// ### Example /// ```toml @@ -163,6 +166,7 @@ declare_clippy_lint! { } pub struct Cargo { + pub allowed_duplicate_crates: FxHashSet<String>, pub ignore_publish: bool, } @@ -208,7 +212,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata); + multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index ec681adb7ae..3f30a77fcfe 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -3,27 +3,40 @@ use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; use clippy_utils::diagnostics::span_lint; use itertools::Itertools; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; use rustc_span::DUMMY_SP; use super::MULTIPLE_CRATE_VERSIONS; -pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate_crates: &FxHashSet<String>) { let local_name = cx.tcx.crate_name(LOCAL_CRATE); let mut packages = metadata.packages.clone(); packages.sort_by(|a, b| a.name.cmp(&b.name)); if let Some(resolve) = &metadata.resolve && let Some(local_id) = packages.iter().find_map(|p| { - if p.name == local_name.as_str() { + // p.name contains the original crate names with dashes intact + // local_name contains the crate name as a namespace, with the dashes converted to underscores + // the code below temporarily rectifies this discrepancy + if p.name + .as_bytes() + .iter() + .map(|b| if b == &b'-' { &b'_' } else { b }) + .eq(local_name.as_str().as_bytes()) + { Some(&p.id) } else { None } }) { - for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + for (name, group) in &packages + .iter() + .filter(|p| !allowed_duplicate_crates.contains(&p.name)) + .group_by(|p| &p.name) + { let group: Vec<&Package> = group.collect(); if group.len() <= 1 { diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 20230106d53..639edd8da30 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -439,6 +439,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, + crate::methods::SUSPICIOUS_OPEN_OPTIONS_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, crate::methods::TYPE_ID_ON_BOX_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index 2472e2ee76f..e617c19eff0 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::last_path_segment; use clippy_utils::source::snippet_with_context; +use clippy_utils::{last_path_segment, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -42,12 +42,14 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && ty.span.ctxt() == ctxt { let mut applicability = Applicability::MachineApplicable; - let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability); + let Some(path) = std_or_core(cx) else { return }; + let path = format!("{path}::iter::empty"); + let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability, &path); span_lint_and_sugg( cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, expr.span, - "`std::iter::empty()` is the more idiomatic way", + &format!("`{path}()` is the more idiomatic way"), "try", sugg, applicability, @@ -61,6 +63,7 @@ fn make_sugg( ty_path: &rustc_hir::QPath<'_>, ctxt: SyntaxContext, applicability: &mut Applicability, + path: &str, ) -> String { if let Some(last) = last_path_segment(ty_path).args && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { @@ -69,10 +72,10 @@ fn make_sugg( }) { format!( - "std::iter::empty::<{}>()", + "{path}::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 ) } else { - "std::iter::empty()".to_owned() + format!("{path}()") } } 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 712bc075650..c4437a3c4b3 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; -use clippy_utils::{get_parent_node, numeric_literal}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; +use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -50,11 +50,11 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - let is_parent_const = if let Some(Node::Item(item)) = get_parent_node(cx.tcx, body.id().hir_id) { - matches!(item.kind, ItemKind::Const(..)) - } else { - false - }; + let hir = cx.tcx.hir(); + let is_parent_const = matches!( + hir.body_const_context(hir.body_owner_def_id(body.id())), + Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) + ); let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index df596338b95..6144ec7b3ca 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; +use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; @@ -450,6 +450,7 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq) && let Some(def_id) = trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) + && !has_non_exhaustive_attr(cx.tcx, *adt) && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[]) // If all of our fields implement `Eq`, we can implement `Eq` too diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index 8b018220c17..8dde4f227ed 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::HumanEmitter; -use rustc_errors::DiagCtxt; +use rustc_errors::{DiagCtxt, DiagnosticBuilder}; use rustc_lint::LateContext; use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::parser::ForceCollect; @@ -53,7 +53,7 @@ pub fn check( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); + errs.into_iter().for_each(DiagnosticBuilder::cancel); return (false, test_attr_spans); }, }; diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index fa1f98ba013..1933a00891b 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -6,8 +6,8 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ - GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty, - TyKind, + FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, + PathSegment, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -197,10 +197,13 @@ fn convert_to_from( // fn into([mut] self) -> T -> fn into([mut] v: T) -> T // ~~~~ ~~~~ (self_ident.span, format!("val: {from}")), + ]; + + if let FnRetTy::Return(_) = sig.decl.output { // fn into(self) -> T -> fn into(self) -> Self // ~ ~~~~ - (sig.decl.output.span(), String::from("Self")), - ]; + suggestions.push((sig.decl.output.span(), String::from("Self"))); + } let mut finder = SelfFinder { cx, diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index fb7b82ec304..1127f00abde 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -53,7 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); - let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return }; + let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { + return; + }; let inherent_impls = cx .tcx .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index efdd3925949..feb4d188f39 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -574,6 +574,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { warn_on_all_wildcard_imports, check_private_items, pub_underscore_fields_behavior, + ref allowed_duplicate_crates, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -719,7 +720,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate)); store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); - store.register_late_pass(|_| Box::new(no_effect::NoEffect)); + store.register_late_pass(|_| Box::<no_effect::NoEffect>::default()); store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv()))); store.register_late_pass(move |_| { @@ -947,6 +948,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, + allowed_duplicate_crates: allowed_duplicate_crates.clone(), }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index c245eaf1ab4..920a887a6fd 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), + &format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index c22f76484d0..fa4f4a47e38 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core}; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; @@ -128,6 +128,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' // check if replacement is mem::MaybeUninit::uninit().assume_init() && cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id) { + let Some(top_crate) = std_or_core(cx) else { return }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -136,7 +137,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::MaybeUninit::uninit().assume_init()`", "consider using", format!( - "std::ptr::read({})", + "{top_crate}::ptr::read({})", snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -149,6 +150,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() { if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) { + let Some(top_crate) = std_or_core(cx) else { return }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -157,7 +159,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' "replacing with `mem::uninitialized()`", "consider using", format!( - "std::ptr::read({})", + "{top_crate}::ptr::read({})", snippet_with_applicability(cx, dest.span, "", &mut applicability) ), applicability, @@ -184,14 +186,17 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< return; } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { + let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_then( cx, MEM_REPLACE_WITH_DEFAULT, expr_span, - "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + &format!( + "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" + ), |diag| { if !expr_span.from_expansion() { - let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); + let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, "")); diag.span_suggestion( expr_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 70abe4891d9..4c7c56e7174 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res}; +use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -58,10 +58,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re return; } + let Some(top_crate) = std_or_core(cx) else { return }; if let Some(i) = item { let sugg = format!( - "{}::iter::once({}{})", - if is_no_std_crate(cx) { "core" } else { "std" }, + "{top_crate}::iter::once({}{})", iter_type.ref_prefix(), snippet(cx, i.span, "...") ); @@ -81,11 +81,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re expr.span, &format!("`{method_name}` call on an empty collection"), "try", - if is_no_std_crate(cx) { - "core::iter::empty()".to_string() - } else { - "std::iter::empty()".to_string() - }, + format!("{top_crate}::iter::empty()"), Applicability::MaybeIncorrect, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs index 02f28779cf6..aa1ec60d434 100644 --- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a ) .span_suggestion( expr_span, - "if this is intentional, try using `Path::new` instead", + "if this is intentional, consider using `Path::new`", format!("PathBuf::from({arg_str})"), Applicability::Unspecified, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 04bdbc1ea25..bf437db7e72 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -50,7 +50,7 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("try using `saturating_{arith}`"), + &format!("consider using `saturating_{arith}`"), format!( "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index f9f636bbbf7..27e17b43b01 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -113,9 +113,15 @@ fn handle_path( if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id() && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD) { - // FIXME: It would be better to infer the type to check if it's copyable or not - // to suggest to use `.copied()` instead of `.cloned()` where applicable. - lint_path(cx, e.span, recv.span); + // The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option` + // and `Result`. + if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind() + && let args = args.as_slice() + && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type()) + && ty.is_ref() + { + lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); + } } } @@ -139,17 +145,19 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { ); } -fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span) { +fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { let mut applicability = Applicability::MachineApplicable; + let replacement = if is_copy { "copied" } else { "cloned" }; + span_lint_and_sugg( cx, MAP_CLONE, replace, "you are explicitly cloning with `.map()`", - "consider calling the dedicated `cloned` method", + &format!("consider calling the dedicated `{replacement}` method"), format!( - "{}.cloned()", + "{}.{replacement}()", snippet_with_applicability(cx, root, "..", &mut applicability), ), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 89ea3597dc0..03bcf108914 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2829,6 +2829,44 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for the suspicious use of `OpenOptions::create()` + /// without an explicit `OpenOptions::truncate()`. + /// + /// ### Why is this bad? + /// `create()` alone will either create a new file or open an + /// existing file. If the file already exists, it will be + /// overwritten when written to, but the file will not be + /// truncated by default. + /// If less data is written to the file + /// than it already contains, the remainder of the file will + /// remain unchanged, and the end of the file will contain old + /// data. + /// In most cases, one should either use `create_new` to ensure + /// the file is created from scratch, or ensure `truncate` is + /// called so that the truncation behaviour is explicit. `truncate(true)` + /// will ensure the file is entirely overwritten with new data, whereas + /// `truncate(false)` will explicitely keep the default behavior. + /// + /// ### Example + /// ```rust,no_run + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().create(true); + /// ``` + /// Use instead: + /// ```rust,no_run + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().create(true).truncate(true); + /// ``` + #[clippy::version = "1.75.0"] + pub SUSPICIOUS_OPEN_OPTIONS, + suspicious, + "suspicious combination of options for opening a file" +} + +declare_clippy_lint! { + /// ### What it does ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) /// calls on `PathBuf` that can cause overwrites. /// @@ -4033,6 +4071,7 @@ impl_lint_pass!(Methods => [ MAP_ERR_IGNORE, MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, + SUSPICIOUS_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, REPEAT_ONCE, diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index 65c986dcacc..77484ab91a9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -1,46 +1,74 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_type_diagnostic_item; +use rustc_data_structures::fx::FxHashMap; + +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{match_any_def_paths, paths}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_middle::ty::Ty; use rustc_span::source_map::Spanned; use rustc_span::{sym, Span}; -use super::NONSENSICAL_OPEN_OPTIONS; +use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; + +fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || match_type(cx, ty, &paths::TOKIO_IO_OPEN_OPTIONS) +} pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions) + && is_open_options(cx, cx.tcx.type_of(impl_id).instantiate_identity()) { let mut options = Vec::new(); - get_open_options(cx, recv, &mut options); - check_open_options(cx, &options, e.span); + if get_open_options(cx, recv, &mut options) { + check_open_options(cx, &options, e.span); + } } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone, Debug)] enum Argument { - True, - False, + Set(bool), Unknown, } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Hash, Clone)] enum OpenOption { - Write, + Append, + Create, + CreateNew, Read, Truncate, - Create, - Append, + Write, +} +impl std::fmt::Display for OpenOption { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OpenOption::Append => write!(f, "append"), + OpenOption::Create => write!(f, "create"), + OpenOption::CreateNew => write!(f, "create_new"), + OpenOption::Read => write!(f, "read"), + OpenOption::Truncate => write!(f, "truncate"), + OpenOption::Write => write!(f, "write"), + } + } } -fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind { +/// Collects information about a method call chain on `OpenOptions`. +/// Returns false if an unexpected expression kind was found "on the way", +/// and linting should then be avoided. +fn get_open_options( + cx: &LateContext<'_>, + argument: &Expr<'_>, + options: &mut Vec<(OpenOption, Argument, Span)>, +) -> bool { + if let ExprKind::MethodCall(path, receiver, arguments, span) = argument.kind { let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() { + if !arguments.is_empty() && is_open_options(cx, obj_ty) { let argument_option = match arguments[0].kind { ExprKind::Lit(span) => { if let Spanned { @@ -48,11 +76,12 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec .. } = span { - if *lit { Argument::True } else { Argument::False } + Argument::Set(*lit) } else { // The function is called with a literal which is not a boolean literal. // This is theoretically possible, but not very likely. - return; + // We'll ignore it for now + return get_open_options(cx, receiver, options); } }, _ => Argument::Unknown, @@ -60,106 +89,77 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec match path.ident.as_str() { "create" => { - options.push((OpenOption::Create, argument_option)); + options.push((OpenOption::Create, argument_option, span)); + }, + "create_new" => { + options.push((OpenOption::CreateNew, argument_option, span)); }, "append" => { - options.push((OpenOption::Append, argument_option)); + options.push((OpenOption::Append, argument_option, span)); }, "truncate" => { - options.push((OpenOption::Truncate, argument_option)); + options.push((OpenOption::Truncate, argument_option, span)); }, "read" => { - options.push((OpenOption::Read, argument_option)); + options.push((OpenOption::Read, argument_option, span)); }, "write" => { - options.push((OpenOption::Write, argument_option)); + options.push((OpenOption::Write, argument_option, span)); + }, + _ => { + // Avoid linting altogether if this method is from a trait. + // This might be a user defined extension trait with a method like `truncate_write` + // which would be a false positive + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(argument.hir_id) + && cx.tcx.trait_of_item(method_def_id).is_some() + { + return false; + } }, - _ => (), } - get_open_options(cx, receiver, options); + get_open_options(cx, receiver, options) + } else { + false } + } else if let ExprKind::Call(callee, _) = argument.kind + && let ExprKind::Path(path) = callee.kind + && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() + { + match_any_def_paths( + cx, + did, + &[ + &paths::TOKIO_IO_OPEN_OPTIONS_NEW, + &paths::OPEN_OPTIONS_NEW, + &paths::FILE_OPTIONS, + &paths::TOKIO_FILE_OPTIONS, + ], + ) + .is_some() + } else { + false } } -fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) { - let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); - let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = - (false, false, false, false, false); - // This code is almost duplicated (oh, the irony), but I haven't found a way to - // unify it. - - for option in options { - match *option { - (OpenOption::Create, arg) => { - if create { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `create` is called more than once", - ); - } else { - create = true; - } - create_arg = create_arg || (arg == Argument::True); - }, - (OpenOption::Append, arg) => { - if append { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `append` is called more than once", - ); - } else { - append = true; - } - append_arg = append_arg || (arg == Argument::True); - }, - (OpenOption::Truncate, arg) => { - if truncate { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `truncate` is called more than once", - ); - } else { - truncate = true; - } - truncate_arg = truncate_arg || (arg == Argument::True); - }, - (OpenOption::Read, arg) => { - if read { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `read` is called more than once", - ); - } else { - read = true; - } - read_arg = read_arg || (arg == Argument::True); - }, - (OpenOption::Write, arg) => { - if write { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `write` is called more than once", - ); - } else { - write = true; - } - write_arg = write_arg || (arg == Argument::True); - }, +fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, Span)], span: Span) { + // The args passed to these methods, if they have been called + let mut options = FxHashMap::default(); + for (option, arg, sp) in settings { + if let Some((_, prev_span)) = options.insert(option.clone(), (arg.clone(), *sp)) { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + prev_span, + &format!("the method `{}` is called more than once", &option), + ); } } - if read && truncate && read_arg && truncate_arg && !(write && write_arg) { + if let Some((Argument::Set(true), _)) = options.get(&OpenOption::Read) + && let Some((Argument::Set(true), _)) = options.get(&OpenOption::Truncate) + && let None | Some((Argument::Set(false), _)) = options.get(&OpenOption::Write) + { span_lint( cx, NONSENSICAL_OPEN_OPTIONS, @@ -167,7 +167,10 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "file opened with `truncate` and `read`", ); } - if append && truncate && append_arg && truncate_arg { + + if let Some((Argument::Set(true), _)) = options.get(&OpenOption::Append) + && let Some((Argument::Set(true), _)) = options.get(&OpenOption::Truncate) + { span_lint( cx, NONSENSICAL_OPEN_OPTIONS, @@ -175,4 +178,29 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "file opened with `append` and `truncate`", ); } + + if let Some((Argument::Set(true), create_span)) = options.get(&OpenOption::Create) + && let None = options.get(&OpenOption::Truncate) + && let None | Some((Argument::Set(false), _)) = options.get(&OpenOption::Append) + { + span_lint_and_then( + cx, + SUSPICIOUS_OPEN_OPTIONS, + *create_span, + "file opened with `create`, but `truncate` behavior not defined", + |diag| { + diag.span_suggestion( + create_span.shrink_to_hi(), + "add", + ".truncate(true)".to_string(), + rustc_errors::Applicability::MaybeIncorrect, + ) + .help("if you intend to overwrite an existing file entirely, call `.truncate(true)`") + .help( + "if you instead know that you may want to keep some parts of the old file, call `.truncate(false)`", + ) + .help("alternatively, use `.append(true)` to append to the file instead of overwriting it"); + }, + ); + } } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 756dbe62d84..88e2af15658 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -97,7 +97,7 @@ pub(super) fn check( }; let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); - let suggestion = format!("try using {method_hint} instead"); + let suggestion = format!("consider using {method_hint}"); let msg = format!("called `{current_method}` on an `Option` value"); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs index 91e39d5a1cd..4e424d4c066 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_ERR_OK, expr.span, msg, - "try using `ok_or` instead", + "consider using `ok_or`", format!("{self_snippet}.ok_or({err_snippet})"), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs index ff4d8cc9e3e..193deafccf6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs @@ -72,7 +72,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_NONE, expr.span, msg, - "try using `map` instead", + "consider using `map`", format!("{self_snippet}.map({arg_snippet} {func_snippet})"), Applicability::MachineApplicable, ); @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( OPTION_MAP_OR_NONE, expr.span, msg, - "try using `and_then` instead", + "consider using `and_then`", format!("{self_snippet}.and_then({func_snippet})"), Applicability::MachineApplicable, ); @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( RESULT_MAP_OR_INTO_OPTION, expr.span, msg, - "try using `ok` instead", + "consider using `ok`", format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs index bc16a112816..3b0dc506305 100644 --- a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( RESULT_MAP_OR_INTO_OPTION, expr.span, msg, - "try using `ok` instead", + "consider using `ok`", format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 6339011c92f..ef1baa6c988 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -63,7 +63,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "use `any()` instead", + "consider using", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, expr.span, &msg, - "use `!_.any()` instead", + "consider using", format!( "!{iter}.any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -118,7 +118,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "use `contains()` instead", + "consider using", format!("contains({find_arg})"), applicability, ); @@ -132,7 +132,7 @@ pub(super) fn check<'tcx>( SEARCH_IS_SOME, expr.span, &msg, - "use `!_.contains()` instead", + "consider using", format!("!{string}.contains({find_arg})"), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs index 3983f0c0cab..363b1f2b812 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs @@ -57,7 +57,7 @@ pub(super) fn check( SINGLE_CHAR_PATTERN, arg.span, "single-character string constant used as pattern", - "try using a `char` instead", + "consider using a `char`", hint, applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs index e2b389e96da..c3ad4db3875 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( UNNECESSARY_JOIN, span.with_hi(expr.span.hi()), r#"called `.collect::<Vec<String>>().join("")` on an iterator"#, - "try using", + "consider using", "collect::<String>()".to_owned(), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 696e5e74d60..6911da69b94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -203,7 +203,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort_by_key here instead", + "consider using `sort_by_key`", "try", format!( "{}.sort{}_by_key(|{}| {})", @@ -226,7 +226,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_SORT_BY, expr.span, - "use Vec::sort here instead", + "consider using `sort`", "try", format!( "{}.sort{}()", diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index 66727e5a29d..514015af045 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{get_parent_expr, is_diag_trait_item, match_def_path, paths, peel_blocks}; +use clippy_utils::{ + get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs, +}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -108,9 +110,12 @@ fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { match arg.kind { - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) // If it's a closure, we need to check what is called. - let closure_body = cx.tcx.hir().body(body); + if let closure_body = cx.tcx.hir().body(body) + && let [param] = closure_body.params + && let hir::PatKind::Binding(_, local_id, ..) = strip_pat_refs(param.pat).kind => + { let closure_expr = peel_blocks(closure_body.value); match closure_expr.kind { hir::ExprKind::MethodCall(method, obj, [], _) => { @@ -122,14 +127,17 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) + && path_to_local_id(obj, local_id) { true } else { false } }, - hir::ExprKind::Call(call, [_]) => { - if let hir::ExprKind::Path(qpath) = call.kind { + hir::ExprKind::Call(call, [recv]) => { + if let hir::ExprKind::Path(qpath) = call.kind + && path_to_local_id(recv, local_id) + { check_qpath(cx, qpath, call.hir_id) } else { false 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 64ef709e2fa..d2eef6ae433 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 @@ -5,16 +5,15 @@ use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, - PatKind, QPath, + PatKind, }; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::associated_body; -use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; @@ -234,12 +233,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor { - cx, - used_fn_def_ids: &mut self.used_fn_def_ids, - }); + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + // #11182; do not lint if mutability is required elsewhere + if let ExprKind::Path(..) = expr.kind + && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(expr).kind() + && let Some(def_id) = def_id.as_local() + { + if let Node::Expr(e) = parent + && let ExprKind::Call(call, _) = e.kind + && call.hir_id == expr.hir_id + { + return; + } + // We don't need to check each argument individually as you cannot coerce a function + // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's + // passed as a `fn`-like argument (or is unified) and should ignore every "unused" + // argument entirely + self.used_fn_def_ids.insert(def_id); + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { for (fn_def_id, unused) in self .fn_def_ids_to_maybe_unused_mut .iter() @@ -501,48 +517,3 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } } - -/// A final pass to check for paths referencing this function that require the argument to be -/// `&mut`, basically if the function is ever used as a `fn`-like argument. -struct FnNeedsMutVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - used_fn_def_ids: &'a mut FxHashSet<LocalDefId>, -} - -impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> { - type NestedFilter = OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) { - walk_qpath(self, qpath, hir_id); - - let Self { cx, used_fn_def_ids } = self; - - // #11182; do not lint if mutability is required elsewhere - if let Node::Expr(expr) = cx.tcx.hir_node(hir_id) - && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) - && let ty::FnDef(def_id, _) = cx - .tcx - .typeck(cx.tcx.hir().enclosing_body_owner(hir_id)) - .expr_ty(expr) - .kind() - && let Some(def_id) = def_id.as_local() - { - if let Node::Expr(e) = parent - && let ExprKind::Call(call, _) = e.kind - && call.hir_id == expr.hir_id - { - return; - } - - // We don't need to check each argument individually as you cannot coerce a function - // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's - // passed as a `fn`-like argument (or is unified) and should ignore every "unused" - // argument entirely - used_fn_def_ids.insert(def_id); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 6bbe427ea29..0d234f7f9b5 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,16 +1,18 @@ 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::{get_parent_node, is_lint_allowed, peel_blocks}; +use clippy_utils::{any_parent_is_automatically_derived, get_parent_node, is_lint_allowed, path_to_local, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, ItemKind, Node, PatKind, Stmt, StmtKind, UnsafeSource, + is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, Node, PatKind, Stmt, + StmtKind, UnsafeSource, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; +use rustc_span::Span; use std::ops::Deref; declare_clippy_lint! { @@ -74,94 +76,125 @@ declare_clippy_lint! { "outer expressions with no effect" } -declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); +#[derive(Default)] +pub struct NoEffect { + underscore_bindings: HirIdMap<Span>, + local_bindings: Vec<Vec<HirId>>, +} + +impl_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if check_no_effect(cx, stmt) { + if self.check_no_effect(cx, stmt) { return; } check_unnecessary_operation(cx, stmt); } -} -fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { - if let StmtKind::Semi(expr) = stmt.kind { - // move `expr.span.from_expansion()` ahead - if expr.span.from_expansion() { - return false; + fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) { + self.local_bindings.push(Vec::default()); + } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) { + for hir_id in self.local_bindings.pop().unwrap() { + if let Some(span) = self.underscore_bindings.remove(&hir_id) { + span_lint_hir( + cx, + NO_EFFECT_UNDERSCORE_BINDING, + hir_id, + span, + "binding to `_` prefixed variable with no side-effect", + ); + } } - let expr = peel_blocks(expr); + } - if is_operator_overridden(cx, expr) { - // Return `true`, to prevent `check_unnecessary_operation` from - // linting on this statement as well. - return true; + fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if let Some(def_id) = path_to_local(expr) { + self.underscore_bindings.remove(&def_id); } - if has_no_effect(cx, expr) { - span_lint_hir_and_then( - cx, - NO_EFFECT, - expr.hir_id, - stmt.span, - "statement with no effect", - |diag| { - for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { - if let Node::Item(item) = parent.1 - && let ItemKind::Fn(..) = item.kind - && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) - && let [.., final_stmt] = block.stmts - && final_stmt.hir_id == stmt.hir_id - { - let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = cx - .tcx - .fn_sig(item.owner_id) - .instantiate_identity() - .output() - .skip_binder(); + } +} + +impl NoEffect { + fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { + if let StmtKind::Semi(expr) = stmt.kind { + // move `expr.span.from_expansion()` ahead + if expr.span.from_expansion() { + return false; + } + let expr = peel_blocks(expr); - // Remove `impl Future<Output = T>` to get `T` - if cx.tcx.ty_is_opaque_future(ret_ty) - && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + if is_operator_overridden(cx, expr) { + // Return `true`, to prevent `check_unnecessary_operation` from + // linting on this statement as well. + return true; + } + if has_no_effect(cx, expr) { + span_lint_hir_and_then( + cx, + NO_EFFECT, + expr.hir_id, + stmt.span, + "statement with no effect", + |diag| { + for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { + if let Node::Item(item) = parent.1 + && let ItemKind::Fn(..) = item.kind + && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) + && let [.., final_stmt] = block.stmts + && final_stmt.hir_id == stmt.hir_id { - ret_ty = true_ret_ty; - } + let expr_ty = cx.typeck_results().expr_ty(expr); + let mut ret_ty = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); + + // Remove `impl Future<Output = T>` to get `T` + if cx.tcx.ty_is_opaque_future(ret_ty) + && let Some(true_ret_ty) = + cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + { + ret_ty = true_ret_ty; + } - if !ret_ty.is_unit() && ret_ty == expr_ty { - diag.span_suggestion( - stmt.span.shrink_to_lo(), - "did you mean to return it?", - "return ", - Applicability::MaybeIncorrect, - ); + if !ret_ty.is_unit() && ret_ty == expr_ty { + diag.span_suggestion( + stmt.span.shrink_to_lo(), + "did you mean to return it?", + "return ", + Applicability::MaybeIncorrect, + ); + } } } - } - }, - ); - return true; - } - } else if let StmtKind::Local(local) = stmt.kind { - if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) - && let Some(init) = local.init - && local.els.is_none() - && !local.pat.span.from_expansion() - && has_no_effect(cx, init) - && let PatKind::Binding(_, _, ident, _) = local.pat.kind - && ident.name.to_ident_string().starts_with('_') - { - span_lint_hir( - cx, - NO_EFFECT_UNDERSCORE_BINDING, - init.hir_id, - stmt.span, - "binding to `_` prefixed variable with no side-effect", - ); - return true; + }, + ); + return true; + } + } else if let StmtKind::Local(local) = stmt.kind { + if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) + && let Some(init) = local.init + && local.els.is_none() + && !local.pat.span.from_expansion() + && 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) + { + if let Some(l) = self.local_bindings.last_mut() { + l.push(hir_id); + self.underscore_bindings.insert(hir_id, ident.span); + } + return true; + } } + false } - false } fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 929efb6c574..96ea063aa74 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,11 +1,11 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::consts::{constant, constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::type_diagnostic_name; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -88,37 +88,44 @@ impl ArithmeticSideEffects { } /// Verifies built-in types that have specific allowed operations - fn has_specific_allowed_type_and_operation( - cx: &LateContext<'_>, - lhs_ty: Ty<'_>, + fn has_specific_allowed_type_and_operation<'tcx>( + cx: &LateContext<'tcx>, + lhs_ty: Ty<'tcx>, op: &Spanned<hir::BinOpKind>, - rhs_ty: Ty<'_>, + rhs_ty: Ty<'tcx>, ) -> bool { let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem); - let is_non_zero_u = |symbol: Option<Symbol>| { - matches!( - symbol, - Some( - sym::NonZeroU128 - | sym::NonZeroU16 - | sym::NonZeroU32 - | sym::NonZeroU64 - | sym::NonZeroU8 - | sym::NonZeroUsize - ) - ) + let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| { + let tcx = cx.tcx; + + let ty::Adt(adt, substs) = ty.kind() else { return false }; + + if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + return false; + }; + + let int_type = substs.type_at(0); + let unsigned_int_types = [ + tcx.types.u8, + tcx.types.u16, + tcx.types.u32, + tcx.types.u64, + tcx.types.u128, + tcx.types.usize, + ]; + + unsigned_int_types.contains(&int_type) }; let is_sat_or_wrap = |ty: Ty<'_>| { - let is_sat = type_diagnostic_name(cx, ty) == Some(sym::Saturating); - let is_wrap = type_diagnostic_name(cx, ty) == Some(sym::Wrapping); - is_sat || is_wrap + is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping) }; - // If the RHS is NonZeroU*, then division or module by zero will never occur - if is_non_zero_u(type_diagnostic_name(cx, rhs_ty)) && is_div_or_rem { + // If the RHS is `NonZero<u*>`, then division or module by zero will never occur. + if is_non_zero_u(cx, rhs_ty) && is_div_or_rem { return true; } - // `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module + + // `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module. if is_sat_or_wrap(lhs_ty) { return !is_div_or_rem; } diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs index 9db2e24630a..a69989e400b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs +++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use super::PTR_EQ; -static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -26,13 +25,14 @@ pub(super) fn check<'tcx>( && let Some(left_snip) = snippet_opt(cx, left_var.span) && let Some(right_snip) = snippet_opt(cx, right_var.span) { + let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_sugg( cx, PTR_EQ, expr.span, - LINT_MSG, + &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", - format!("std::ptr::eq({left_snip}, {right_snip})"), + format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs index 00465ce4381..88b5a6cfe2a 100644 --- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs +++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields { }; let is_visible = |field: &FieldDef<'_>| match self.behavior { - PubUnderscoreFieldsBehaviour::PublicallyExported => cx.effective_visibilities.is_reachable(field.def_id), + PubUnderscoreFieldsBehaviour::PubliclyExported => cx.effective_visibilities.is_reachable(field.def_id), PubUnderscoreFieldsBehaviour::AllPubFields => { // If there is a visibility span then the field is marked pub in some way. !field.vis_span.is_empty() diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 62f3c09aa7e..650324d4249 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_enclosing_block; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; -use core::ops::ControlFlow; -use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; + +use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -49,57 +51,40 @@ declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]); impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &hir::Block<'tcx>) { - for (idx, stmt) in block.stmts.iter().enumerate() { - if !stmt.span.from_expansion() - // matches `let v = Vec::new();` - && let StmtKind::Local(local) = stmt.kind - && let Local { pat, init: Some(init), .. } = local - && let PatKind::Binding(_, _, ident, _) = pat.kind + for stmt in block.stmts { + if stmt.span.from_expansion() { + return; + } + + if let StmtKind::Local(local) = stmt.kind + && let Local { + pat, init: Some(init), .. + } = local + && let PatKind::Binding(_, id, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - let visitor = |expr: &Expr<'_>| { - if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { - ident: read_or_read_exact, - .. - } = *path - && matches!(read_or_read_exact.as_str(), "read" | "read_exact") - && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind - && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind - && let [inner_seg] = inner_path.segments - && ident.name == inner_seg.ident.name - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + let mut visitor = ReadVecVisitor { + local_id: id, + read_zero_expr: None, + has_resize: false, }; - let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { - // case { .. stmt; stmt; .. } - (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) - } else if let Some(e) = block.expr { - // case { .. stmt; expr } - (for_each_expr(e, visitor).is_some(), e.span) - } else { + let Some(enclosing_block) = get_enclosing_block(cx, id) else { return; }; + visitor.visit_block(enclosing_block); - if read_found && !next_stmt_span.from_expansion() { + if let Some(expr) = visitor.read_zero_expr { let applicability = Applicability::MaybeIncorrect; match vec_init_kind { VecInitKind::WithConstCapacity(len) => { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", - format!( - "{}.resize({len}, 0); {}", - ident.as_str(), - snippet(cx, next_stmt_span, "..") - ), + format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), applicability, ); }, @@ -108,25 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { span_lint_and_sugg( cx, READ_ZERO_BYTE_VEC, - next_stmt_span, + expr.span, "reading zero byte data to `Vec`", "try", format!( "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), - snippet(cx, next_stmt_span, "..") + snippet(cx, expr.span, "..") ), applicability, ); }, _ => { - span_lint( - cx, - READ_ZERO_BYTE_VEC, - next_stmt_span, - "reading zero byte data to `Vec`", - ); + span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`"); }, } } @@ -134,3 +114,47 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } } } + +struct ReadVecVisitor<'tcx> { + local_id: HirId, + read_zero_expr: Option<&'tcx Expr<'tcx>>, + has_resize: bool, +} + +impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { + let PathSegment { ident, .. } = *path; + + match ident.as_str() { + "read" | "read_exact" => { + let [arg] = args else { return }; + if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind + && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind + && let [inner_seg] = inner_path.segments + && let Res::Local(res_id) = inner_seg.res + && self.local_id == res_id + { + self.read_zero_expr = Some(e); + return; + } + }, + "resize" => { + // If the Vec is resized, then it's a valid read + if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind + && let Res::Local(res_id) = inner_path.res + && self.local_id == res_id + { + self.has_resize = true; + return; + } + }, + _ => {}, + } + } + + if !self.has_resize && self.read_zero_expr.is_none() { + walk_expr(self, e); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 2cd3e57f885..6540626f7d5 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::{ExpnKind, MacroKind, Span}; declare_clippy_lint! { /// ### What it does @@ -39,6 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if !block.span.from_expansion() && let Some(expr) = block.expr + && !from_attr_macro(expr.span) && let t_expr = cx.typeck_results().expr_ty(expr) && t_expr.is_unit() && let mut app = Applicability::MachineApplicable @@ -63,3 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { } } } + +fn from_attr_macro(span: Span) -> bool { + matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Attr, _)) +} diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 8e181c3ccc7..03877420774 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::{is_from_proc_macro, is_in_test_function}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; @@ -88,16 +88,18 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn { }; cx.tcx.hir().visit_all_item_likes_in_crate(&mut v); - for usage in self.def_id_to_usage.values() { + for (&def_id, usage) in &self.def_id_to_usage { let single_call_fn_span = usage.0; if let [caller_span] = *usage.1 { - span_lint_and_help( + span_lint_hir_and_then( cx, SINGLE_CALL_FN, + cx.tcx.local_def_id_to_hir_id(def_id), single_call_fn_span, "this function is only used once", - Some(caller_span), - "used here", + |diag| { + diag.span_help(caller_span, "used here"); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index e4054393d0a..768623b5d03 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -390,6 +390,14 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &' } } +fn get_ty_res(ty: Ty<'_>) -> Option<Res> { + match ty.kind { + TyKind::Path(QPath::Resolved(_, path)) => Some(path.res), + TyKind::Path(QPath::TypeRelative(ty, _)) => get_ty_res(*ty), + _ => None, + } +} + // FIXME: ComparableTraitRef does not support nested bounds needed for associated_type_bounds fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ComparableTraitRef( @@ -401,10 +409,8 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { .filter_map(|segment| { // get trait bound type arguments Some(segment.args?.args.iter().filter_map(|arg| { - if let GenericArg::Type(ty) = arg - && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - { - return Some(path.res); + if let GenericArg::Type(ty) = arg { + return get_ty_res(**ty); } None })) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs index 7d31c375f8c..2a6c2481254 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::{std_or_core, sugg}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; @@ -25,6 +25,7 @@ pub(super) fn check<'tcx>( e.span, &format!("transmute from a `{from_ty}` to a `char`"), |diag| { + let Some(top_crate) = std_or_core(cx) else { return }; let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(_) = from_ty.kind() { arg.as_ty(ast::UintTy::U32.name_str()) @@ -34,7 +35,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({arg}).unwrap()"), + format!("{top_crate}::char::from_u32({arg}).unwrap()"), Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 5df645491ff..97068efd43c 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -16,40 +16,55 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - let (ty::Int(_) | ty::Uint(_), Some(to_ty_adt)) = (&from_ty.kind(), to_ty.ty_adt_def()) else { + let tcx = cx.tcx; + + let (ty::Int(_) | ty::Uint(_), ty::Adt(adt, substs)) = (&from_ty.kind(), to_ty.kind()) else { return false; }; - let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_adt.did()) else { + + if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { return false; }; - if !matches!( - to_type_sym, - sym::NonZeroU8 - | sym::NonZeroU16 - | sym::NonZeroU32 - | sym::NonZeroU64 - | sym::NonZeroU128 - | sym::NonZeroI8 - | sym::NonZeroI16 - | sym::NonZeroI32 - | sym::NonZeroI64 - | sym::NonZeroI128 - ) { + // FIXME: This can be simplified once `NonZero<T>` is stable. + let coercable_types = [ + ("NonZeroU8", tcx.types.u8), + ("NonZeroU16", tcx.types.u16), + ("NonZeroU32", tcx.types.u32), + ("NonZeroU64", tcx.types.u64), + ("NonZeroU128", tcx.types.u128), + ("NonZeroUsize", tcx.types.usize), + ("NonZeroI8", tcx.types.i8), + ("NonZeroI16", tcx.types.i16), + ("NonZeroI32", tcx.types.i32), + ("NonZeroI64", tcx.types.i64), + ("NonZeroI128", tcx.types.i128), + ("NonZeroIsize", tcx.types.isize), + ]; + + let int_type = substs.type_at(0); + + let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { + if *t == int_type && *t == from_ty { + Some(nonzero_alias) + } else { + None + } + }) else { return false; - } + }; span_lint_and_then( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - &format!("transmute from a `{from_ty}` to a `{to_type_sym}`"), + &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( e.span, "consider using", - format!("{to_type_sym}::{}({arg})", sym::new_unchecked), + format!("{nonzero_alias}::{}({arg})", sym::new_unchecked), Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 98e9ea2d775..6c885ebdea1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,7 +1,7 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; +use clippy_utils::{std_or_core, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -25,6 +25,8 @@ pub(super) fn check<'tcx>( && let ty::Uint(ty::UintTy::U8) = slice_ty.kind() && from_mutbl == to_mutbl { + let Some(top_crate) = std_or_core(cx) else { return true }; + let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" }; let snippet = snippet(cx, arg.span, ".."); @@ -36,9 +38,9 @@ pub(super) fn check<'tcx>( &format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("std::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") } else { - format!("std::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") }, Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index b418db53ea4..209035804e4 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -167,7 +167,15 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca false } }, - ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => { + ExprKind::MethodCall(segment, receiver, &[_arg], _) if segment.ident.name == name.name => { + if let Some(ty) = cx.typeck_results().expr_ty_opt(receiver) + && let Some(ty_id) = get_ty_def_id(ty) + && self_arg != ty_id + { + // Since this called on a different type, the lint should not be + // triggered here. + return; + } if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) && trait_id == trait_def_id diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 1de9adfcb96..adc66e15ff5 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths}; +use hir::{ExprKind, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -45,126 +46,219 @@ declare_clippy_lint! { declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]); +#[derive(Copy, Clone)] +enum IoOp { + AsyncWrite(bool), + AsyncRead(bool), + SyncRead(bool), + SyncWrite(bool), +} + impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { - fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else { - return; - }; + /// We perform the check on the block level. + /// If we want to catch match and if expressions that act as returns of the block + /// we need to check them at `check_expr` or `check_block` as they are not stmts + /// but we can't check them at `check_expr` because we need the broader context + /// because we should do this only for the final expression of the block, and not for + /// `StmtKind::Local` which binds values => the io amount is used. + /// + /// To check for unused io amount in stmts, we only consider `StmtKind::Semi`. + /// `StmtKind::Local` is not considered because it binds values => the io amount is used. + /// `StmtKind::Expr` is not considered because requires unit type => the io amount is used. + /// `StmtKind::Item` is not considered because it's not an expression. + /// + /// We then check the individual expressions via `check_expr`. We use the same logic for + /// semi expressions and the final expression as we need to check match and if expressions + /// for binding of the io amount to `Ok(_)`. + /// + /// We explicitly check for the match source to be Normal as it needs special logic + /// to consider the arms, and we want to avoid breaking the logic for situations where things + /// get desugared to match. + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) { + for stmt in block.stmts { + if let hir::StmtKind::Semi(exp) = stmt.kind { + check_expr(cx, exp); + } + } - match expr.kind { - hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => { - if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind { - if matches!( - func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) - ) { - check_map_error(cx, arg_0, expr); + if let Some(exp) = block.expr + && matches!(exp.kind, hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, _)) + { + check_expr(cx, exp); + } + } +} + +fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { + match expr.kind { + hir::ExprKind::If(cond, _, _) + if let ExprKind::Let(hir::Let { pat, init, .. }) = cond.kind + && pattern_is_ignored_ok(cx, pat) + && let Some(op) = should_lint(cx, init) => + { + emit_lint(cx, cond.span, op, &[pat.span]); + }, + hir::ExprKind::Match(expr, arms, hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { + let found_arms: Vec<_> = arms + .iter() + .filter_map(|arm| { + if pattern_is_ignored_ok(cx, arm.pat) { + Some(arm.span) + } else { + None } - } else { - check_map_error(cx, res, expr); - } - }, - hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() { - "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" | "is_ok" | "is_err" => { - check_map_error(cx, arg_0, expr); - }, - _ => (), - }, - _ => (), + }) + .collect(); + if !found_arms.is_empty() { + emit_lint(cx, expr.span, op, found_arms.as_slice()); + } + }, + _ if let Some(op) = should_lint(cx, expr) => { + emit_lint(cx, expr.span, op, &[]); + }, + _ => {}, + }; +} + +fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option<IoOp> { + inner = unpack_match(inner); + inner = unpack_try(inner); + inner = unpack_call_chain(inner); + inner = unpack_await(inner); + // we type-check it to get whether it's a read/write or their vectorized forms + // and keep only the ones that are produce io amount + check_io_mode(cx, inner) +} + +fn pattern_is_ignored_ok(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> bool { + // the if checks whether we are in a result Ok( ) pattern + // and the return checks whether it is unhandled + + if let PatKind::TupleStruct(ref path, inner_pat, ddp) = pat.kind + // we check against Result::Ok to avoid linting on Err(_) or something else. + && is_res_lang_ctor(cx, cx.qpath_res(path, pat.hir_id), hir::LangItem::ResultOk) + { + return match (inner_pat, ddp.as_opt_usize()) { + // Ok(_) pattern + ([inner_pat], None) if matches!(inner_pat.kind, PatKind::Wild) => true, + // Ok(..) pattern + ([], Some(0)) => true, + _ => false, + }; + } + false +} + +fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind { + if matches!( + path.ident.as_str(), + "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" + ) { + expr = receiver; + } else { + break; } } + expr +} + +fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind + && matches!( + func.kind, + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) + ) + { + expr = arg_0; + } + expr +} + +fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + while let hir::ExprKind::Match(res, _, _) = expr.kind { + expr = res; + } + expr } /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. -fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> { +fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) ) { - return Some(arg_0); + return arg_0; } } } - - None + expr } -fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { - let mut call = call; - while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind { - if matches!(path.ident.as_str(), "or" | "or_else" | "ok") { - call = receiver; - } else { - break; - } - } +/// Check whether the current expr is a function call for an IO operation +fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> { + let hir::ExprKind::MethodCall(path, ..) = call.kind else { + return None; + }; - if let Some(call) = try_remove_await(call) { - check_method_call(cx, call, expr, true); - } else { - check_method_call(cx, call, expr, false); + let vectorized = match path.ident.as_str() { + "write_vectored" | "read_vectored" => true, + "write" | "read" => false, + _ => { + return None; + }, + }; + + match ( + is_trait_method(cx, call, sym::IoRead), + is_trait_method(cx, call, sym::IoWrite), + match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) + || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT), + match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) + || match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT), + ) { + (true, _, _, _) => Some(IoOp::SyncRead(vectorized)), + (_, true, _, _) => Some(IoOp::SyncWrite(vectorized)), + (_, _, true, _) => Some(IoOp::AsyncRead(vectorized)), + (_, _, _, true) => Some(IoOp::AsyncWrite(vectorized)), + _ => None, } } -fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) { - if let hir::ExprKind::MethodCall(path, ..) = call.kind { - let symbol = path.ident.as_str(); - let read_trait = if is_await { - match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) - || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT) - } else { - is_trait_method(cx, call, sym::IoRead) - }; - let write_trait = if is_await { - match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT) - || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) - } else { - is_trait_method(cx, call, sym::IoWrite) - }; +fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) { + let (msg, help) = match op { + IoOp::AsyncRead(false) => ( + "read amount is not handled", + Some("use `AsyncReadExt::read_exact` instead, or handle partial reads"), + ), + IoOp::SyncRead(false) => ( + "read amount is not handled", + Some("use `Read::read_exact` instead, or handle partial reads"), + ), + IoOp::SyncWrite(false) => ( + "written amount is not handled", + Some("use `Write::write_all` instead, or handle partial writes"), + ), + IoOp::AsyncWrite(false) => ( + "written amount is not handled", + Some("use `AsyncWriteExt::write_all` instead, or handle partial writes"), + ), + IoOp::SyncRead(true) | IoOp::AsyncRead(true) => ("read amount is not handled", None), + IoOp::SyncWrite(true) | IoOp::AsyncWrite(true) => ("written amount is not handled", None), + }; - match (read_trait, write_trait, symbol, is_await) { - (true, _, "read", false) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "read amount is not handled", - None, - "use `Read::read_exact` instead, or handle partial reads", - ), - (true, _, "read", true) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "read amount is not handled", - None, - "use `AsyncReadExt::read_exact` instead, or handle partial reads", - ), - (true, _, "read_vectored", _) => { - span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled"); - }, - (_, true, "write", false) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "written amount is not handled", - None, - "use `Write::write_all` instead, or handle partial writes", - ), - (_, true, "write", true) => span_lint_and_help( - cx, - UNUSED_IO_AMOUNT, - expr.span, - "written amount is not handled", - None, - "use `AsyncWriteExt::write_all` instead, or handle partial writes", - ), - (_, true, "write_vectored", _) => { - span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled"); - }, - _ => (), + span_lint_and_then(cx, UNUSED_IO_AMOUNT, span, msg, |diag| { + if let Some(help_str) = help { + diag.help(help_str); } - } + for span in wild_cards { + diag.span_note( + *span, + "the result is consumed here, but the amount of I/O bytes remains unhandled", + ); + } + }); } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 5ddedb24b15..4822970e47e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { ident.span, "non-standard lint formulation", None, - &format!("try using `{}` instead", formulation.correction), + &format!("consider using `{}`", formulation.correction), ); } return; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 4fb615e1d57..c62ae8d718d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -71,7 +71,9 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Str, ] .iter() - .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied()); + .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter()) + .flatten() + .copied(); for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { let lang_item_path = cx.get_def_path(item_def_id); if path_syms.starts_with(&lang_item_path) { diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index ad8619f0d3d..2d0c2cf1253 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -1,5 +1,6 @@ use rustc_ast::{ast, attr}; use rustc_errors::Applicability; +use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; use rustc_span::sym; use std::str::FromStr; @@ -159,3 +160,14 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { .filter_map(ast::Attribute::meta_item_list) .any(|l| attr::list_contains_name(&l, sym::hidden)) } + +pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { + adt.is_variant_list_non_exhaustive() + || tcx.has_attr(adt.did(), sym::non_exhaustive) + || adt.variants().iter().any(|variant_def| { + variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive) + }) + || adt + .all_fields() + .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive)) +} diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 979b117db25..4fa93ad23c3 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -134,7 +134,7 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + use TokenKind::{Semi, Whitespace}; if left.stmts.len() != right.stmts.len() { return false; } @@ -177,7 +177,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) { return false; } @@ -212,7 +212,7 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + !matches!(t, Whitespace | Semi) }) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ebe520b27eb..4e499ff4cc6 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -536,7 +536,12 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It "f32" => SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), #[allow(trivial_casts)] - _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(), + _ => { + return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]) + .into_iter() + .flatten() + .copied(); + }, }; tcx.incoherent_impls(ty).into_iter().flatten().copied() @@ -1712,7 +1717,6 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), - PatKind::Lit(..) | PatKind::Range(..) => true, PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set @@ -1736,7 +1740,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Err(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) => true, } } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 0a820a1754c..0051f784514 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -26,6 +26,7 @@ pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"]; +pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates @@ -50,6 +51,7 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; +pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -89,9 +91,15 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; #[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 pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 59ebe685c11..11bb16ff6c5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -219,7 +219,8 @@ pub fn implements_trait<'tcx>( /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. /// -/// The `callee_id` argument is used to determine whether this is a function call in a `const fn` environment, used for checking const traits. +/// The `callee_id` argument is used to determine whether this is a function call in a `const fn` +/// environment, used for checking const traits. pub fn implements_trait_with_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 2589d46e7da..d2d56e59ee3 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-01-11" +channel = "nightly-2024-01-25" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr new file mode 100644 index 00000000000..8f0ca764924 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.stderr @@ -0,0 +1,6 @@ +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 + | + = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]` + +error: could not compile `multiple-crate-versions` (bin "multiple-crate-versions") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml new file mode 100644 index 00000000000..d39ad6c909a --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/Cargo.toml @@ -0,0 +1,14 @@ +# Should not lint for dev or build dependencies. See issue 5041. + +[package] +# purposefully separated by - instead of _ +name = "multiple-crate-versions" +version = "0.1.0" +publish = false + +[workspace] + +# One of the versions of winapi is only a dev dependency: allowed +[dependencies] +winapi = "0.2" +ansi_term = "=0.11.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs new file mode 100644 index 00000000000..4bc61dd6299 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12145_with_dashes/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml new file mode 100644 index 00000000000..79317659ac0 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "multiple_crate_versions" +version = "0.1.0" +publish = false + +[workspace] + +[dependencies] +winapi = "0.2" +ansi_term = "=0.11.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml new file mode 100644 index 00000000000..121361de2fe --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/clippy.toml @@ -0,0 +1 @@ +allowed-duplicate-crates = ["winapi"] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs new file mode 100644 index 00000000000..4bc61dd6299 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/12176_allow_duplicate_crates/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/check_formulation.stderr b/src/tools/clippy/tests/ui-internal/check_formulation.stderr index 96fa617601f..42a872d9a83 100644 --- a/src/tools/clippy/tests/ui-internal/check_formulation.stderr +++ b/src/tools/clippy/tests/ui-internal/check_formulation.stderr @@ -4,7 +4,7 @@ error: non-standard lint formulation LL | /// Check for lint formulations that are correct | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try using `Checks for` instead + = help: consider using `Checks for` = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]` @@ -14,7 +14,7 @@ error: non-standard lint formulation LL | /// Detects uses of incorrect formulations | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try using `Checks for` instead + = help: consider using `Checks for` error: aborting due to 2 previous errors 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 03556823a8f..5ca183d41a9 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> $DIR/disallow_struct_span_lint.rs:14:5 + --> $DIR/disallow_span_lint.rs:14:5 | LL | cx.span_lint(lint, span, msg, |_| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,10 +8,10 @@ LL | cx.span_lint(lint, span, msg, |_| {}); = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> $DIR/disallow_struct_span_lint.rs:24:5 + --> $DIR/disallow_span_lint.rs:24:5 | LL | tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml index 94a0d3554bc..9e472bd14ba 100644 --- a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml @@ -1 +1 @@ -pub-underscore-fields-behavior = "PublicallyExported" \ No newline at end of file +pub-underscore-fields-behavior = "PubliclyExported" diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml index b77b4580051..2b63f6e5c26 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/clippy.toml @@ -3,6 +3,9 @@ foobar = 42 # so is this one barfoo = 53 +# when using underscores instead of dashes, suggest the correct one +allow_mixed_uninlined_format_args = true + # that one is ignored [third-party] clippy-feature = "nightly" diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index 38009627757..49139b60a9f 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1,3 +1,4 @@ +//@no-rustfix //@error-in-other-file: unknown field `foobar`, expected one of fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index ed4fb84df1a..fc683e514ba 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -11,6 +11,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-private-module-inception allow-unwrap-in-tests allowed-dotfiles + allowed-duplicate-crates allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed @@ -87,6 +88,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-private-module-inception allow-unwrap-in-tests allowed-dotfiles + allowed-duplicate-crates allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed @@ -150,5 +152,82 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect LL | barfoo = 53 | ^^^^^^ -error: aborting due to 2 previous errors +error: error reading Clippy's configuration file: unknown field `allow_mixed_uninlined_format_args`, expected one of + absolute-paths-allowed-crates + absolute-paths-max-segments + accept-comment-above-attributes + accept-comment-above-statement + allow-dbg-in-tests + allow-expect-in-tests + allow-mixed-uninlined-format-args + allow-one-hash-in-raw-strings + allow-print-in-tests + allow-private-module-inception + allow-unwrap-in-tests + allowed-dotfiles + allowed-duplicate-crates + allowed-idents-below-min-chars + allowed-scripts + arithmetic-side-effects-allowed + arithmetic-side-effects-allowed-binary + arithmetic-side-effects-allowed-unary + array-size-threshold + avoid-breaking-exported-api + await-holding-invalid-types + blacklisted-names + cargo-ignore-publish + check-private-items + cognitive-complexity-threshold + cyclomatic-complexity-threshold + disallowed-macros + disallowed-methods + disallowed-names + disallowed-types + doc-valid-idents + enable-raw-pointer-heuristic-for-send + enforce-iter-loop-reborrow + enforced-import-renames + enum-variant-name-threshold + enum-variant-size-threshold + excessive-nesting-threshold + future-size-threshold + ignore-interior-mutability + large-error-threshold + literal-representation-threshold + matches-for-let-else + max-fn-params-bools + max-include-file-size + max-struct-bools + max-suggested-slice-pattern-length + max-trait-bounds + min-ident-chars-threshold + missing-docs-in-crate-items + msrv + pass-by-value-size-limit + pub-underscore-fields-behavior + semicolon-inside-block-ignore-singleline + semicolon-outside-block-ignore-multiline + single-char-binding-names-threshold + stack-size-threshold + standard-macro-braces + struct-field-name-threshold + suppress-restriction-lint-in-const + third-party + too-large-for-stack + too-many-arguments-threshold + too-many-lines-threshold + trivial-copy-size-limit + type-complexity-threshold + unnecessary-box-size + unreadable-literal-lint-fractions + upper-case-acronyms-aggressive + vec-box-size-threshold + verbose-bit-mask-threshold + warn-on-all-wildcard-imports + --> $DIR/$DIR/clippy.toml:7:1 + | +LL | allow_mixed_uninlined_format_args = true + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: perhaps you meant: `allow-mixed-uninlined-format-args` + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs index c5879557516..ac544737099 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, - TraitItem, Type, + parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, + Signature, TraitItem, Type, }; #[proc_macro_attribute] @@ -95,3 +95,33 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea TokenStream::from(quote!(#item)) } + +#[proc_macro_attribute] +pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut item = parse_macro_input!(item as ItemFn); + let span = item.block.brace_token.span; + + if item.sig.asyncness.is_some() { + item.sig.asyncness = None; + } + + let crate_name = quote! { fake_crate }; + let block = item.block; + item.block = syn::parse_quote_spanned! { + span => + { + #crate_name::block_on(async { + #block + }) + } + }; + + quote! { + mod #crate_name { + pub fn block_on<F: ::std::future::Future>(_fut: F) {} + } + + #item + } + .into() +} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index 2ab441bbd0c..efef60567a9 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -85,4 +85,18 @@ fn block_in_match_expr(num: i32) -> i32 { } } +// issue #12162 +macro_rules! timed { + ($name:expr, $body:expr $(,)?) => {{ + let __scope = (); + $body + }}; +} + +fn issue_12162() { + if timed!("check this!", false) { + println!(); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index dd5ae4fb486..8bd8a939eb1 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -85,4 +85,18 @@ fn block_in_match_expr(num: i32) -> i32 { } } +// issue #12162 +macro_rules! timed { + ($name:expr, $body:expr $(,)?) => {{ + let __scope = (); + $body + }}; +} + +fn issue_12162() { + if timed!("check this!", false) { + println!(); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs index 44f8b2eabce..9af81f6f7cd 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs @@ -9,17 +9,16 @@ fn simple_examples() { // Simple if true { - //~^ ERROR: all if blocks contain the same code at the start println!("Hello World!"); println!("I'm branch nr: 1"); } else { println!("Hello World!"); println!("I'm branch nr: 2"); } + //~^^^^^^^ ERROR: all if blocks contain the same code at the start // Else if if x == 0 { - //~^ ERROR: all if blocks contain the same code at the start let y = 9; println!("The value y was set to: `{}`", y); let _z = y; @@ -38,6 +37,7 @@ fn simple_examples() { println!("Ha, Pascal allows you to start the array where you want") } + //~^^^^^^^^^^^^^^^^^^^ ERROR: all if blocks contain the same code at the start // Return a value let _ = if x == 7 { @@ -60,7 +60,6 @@ fn simple_but_suggestion_is_invalid() { // Can't be automatically moved because used_value_name is getting used again let used_value_name = 19; if x == 10 { - //~^ ERROR: all if blocks contain the same code at the start let used_value_name = "Different type"; println!("Str: {}", used_value_name); let _ = 1; @@ -69,6 +68,7 @@ fn simple_but_suggestion_is_invalid() { println!("Str: {}", used_value_name); let _ = 2; } + //~^^^^^^^^^ ERROR: all if blocks contain the same code at the start let _ = used_value_name; // This can be automatically moved as `can_be_overridden` is not used again @@ -101,11 +101,11 @@ fn check_if_same_than_else_mask() { } if x == 2019 { - //~^ ERROR: this `if` has identical blocks println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } else { println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } + //~^^^^^ ERROR: this `if` has identical blocks } #[allow(clippy::vec_init_then_push)] diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr index 9d4d42fb689..317d1577226 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -2,7 +2,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:11:5 | LL | / if true { -LL | | LL | | println!("Hello World!"); | |_________________________________^ | @@ -21,7 +20,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:21:5 | LL | / if x == 0 { -LL | | LL | | let y = 9; LL | | println!("The value y was set to: `{}`", y); LL | | let _z = y; @@ -54,7 +52,6 @@ error: all if blocks contain the same code at the start --> $DIR/shared_at_top.rs:62:5 | LL | / if x == 10 { -LL | | LL | | let used_value_name = "Different type"; LL | | println!("Str: {}", used_value_name); | |_____________________________________________^ @@ -105,13 +102,12 @@ error: this `if` has identical blocks | LL | if x == 2019 { | __________________^ -LL | | LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); LL | | } else { | |_____^ | note: same as this - --> $DIR/shared_at_top.rs:106:12 + --> $DIR/shared_at_top.rs:105:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs index 2aeacb89c0c..b63819d7c39 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs @@ -107,9 +107,9 @@ fn valid_examples() { // Let's test empty blocks if false { - //~^ ERROR: this `if` has identical blocks } else { } + //~^^^ ERROR: this `if` has identical blocks } /// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint @@ -119,7 +119,6 @@ fn trigger_other_lint() { // Same block if x == 0 { - //~^ ERROR: this `if` has identical blocks let u = 19; println!("How are u today?"); let _ = "This is a string"; @@ -128,6 +127,7 @@ fn trigger_other_lint() { println!("How are u today?"); let _ = "This is a string"; } + //~^^^^^^^^^ ERROR: this `if` has identical blocks // Only same expression let _ = if x == 6 { 7 } else { 7 }; @@ -138,28 +138,24 @@ fn trigger_other_lint() { println!("Well I'm the most important block"); "I'm a pretty string" } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below if y == 90 { "=^.^=" } else { ":D" } } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); if y == 90 { "=^.^=" } else { ":D" } }; + //~^^^^^^^^^ ERROR: this `if` has identical blocks if x == 0 { println!("I'm single"); } else if x == 68 { - //~^ ERROR: this `if` has identical blocks println!("I'm a doppelgänger"); - // Don't listen to my clone below } else { - // Don't listen to my clone above println!("I'm a doppelgänger"); } + //~^^^^^ ERROR: this `if` has identical blocks } fn main() {} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr index fcbf12235aa..0daf2ff6967 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr @@ -3,12 +3,11 @@ error: this `if` has identical blocks | LL | if false { | ______________^ -LL | | LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:111:12 + --> $DIR/valid_if_blocks.rs:110:12 | LL | } else { | ____________^ @@ -25,7 +24,6 @@ error: this `if` has identical blocks | LL | if x == 0 { | _______________^ -LL | | LL | | let u = 19; LL | | println!("How are u today?"); LL | | let _ = "This is a string"; @@ -33,7 +31,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:126:12 + --> $DIR/valid_if_blocks.rs:125:12 | LL | } else { | ____________^ @@ -60,20 +58,17 @@ error: this `if` has identical blocks | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:146:12 + --> $DIR/valid_if_blocks.rs:144:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | LL | | if y == 90 { "=^.^=" } else { ":D" } @@ -81,22 +76,19 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/valid_if_blocks.rs:155:23 + --> $DIR/valid_if_blocks.rs:153:23 | LL | } else if x == 68 { | _______________________^ -LL | | LL | | println!("I'm a doppelgänger"); -LL | | // Don't listen to my clone below LL | | } else { | |_____^ | note: same as this - --> $DIR/valid_if_blocks.rs:159:12 + --> $DIR/valid_if_blocks.rs:155:12 | LL | } else { | ____________^ -LL | | // Don't listen to my clone above LL | | println!("I'm a doppelgänger"); LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr index 00b65f00d78..67589d1a8ab 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr @@ -2,7 +2,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/ice-9041.rs:5:19 | LL | things.iter().find(|p| is_thing_ready(p)).is_some() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|p| is_thing_ready(&p))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|p| is_thing_ready(&p))` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed new file mode 100644 index 00000000000..7300bd9bd2a --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty<usize>, +} + +fn main() { + // Do lint. + let _ = core::iter::empty::<usize>(); + let _foo: core::iter::Empty<usize> = core::iter::empty(); + + // Do not lint. + let _ = Iter::default(); +} diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs new file mode 100644 index 00000000000..0bc5c7169d1 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs @@ -0,0 +1,28 @@ +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[derive(Default)] +struct Iter { + iter: core::iter::Empty<usize>, +} + +fn main() { + // Do lint. + let _ = core::iter::Empty::<usize>::default(); + let _foo: core::iter::Empty<usize> = core::iter::Empty::default(); + + // Do not lint. + let _ = Iter::default(); +} diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr new file mode 100644 index 00000000000..747a31ecbf3 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr @@ -0,0 +1,17 @@ +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:23:13 + | +LL | let _ = core::iter::Empty::<usize>::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty::<usize>()` + | + = note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` + +error: `core::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty_no_std.rs:24:42 + | +LL | let _foo: core::iter::Empty<usize> = core::iter::Empty::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed index c364c683057..e7038082c08 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -216,4 +216,44 @@ mod type_already_inferred { } } +mod issue12159 { + #![allow(non_upper_case_globals, clippy::exhaustive_structs)] + pub struct Foo; + + static F: i32 = 1; + impl Foo { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + + const fn consts() { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs index ffa7b961d1c..d8eeda70491 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -216,4 +216,44 @@ mod type_already_inferred { } } +mod issue12159 { + #![allow(non_upper_case_globals, clippy::exhaustive_structs)] + pub struct Foo; + + static F: i32 = 1; + impl Foo { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + + const fn consts() { + const LIFE_u8: u8 = 42; + const LIFE_i8: i8 = 42; + const LIFE_u16: u16 = 42; + const LIFE_i16: i16 = 42; + const LIFE_u32: u32 = 42; + const LIFE_i32: i32 = 42; + const LIFE_u64: u64 = 42; + const LIFE_i64: i64 = 42; + const LIFE_u128: u128 = 42; + const LIFE_i128: i128 = 42; + const LIFE_usize: usize = 42; + const LIFE_isize: isize = 42; + const LIFE_f32: f32 = 42.; + const LIFE_f64: f64 = 42.; + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed index a7f5d3ec7cd..aa7a95405e0 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed @@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn { #[derive(PartialEq)] struct InternalTy; +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct MissingEqNonExhaustive { + foo: u32, + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub struct MissingEqNonExhaustive1 { + foo: u32, + #[non_exhaustive] + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum MissingEqNonExhaustive2 { + Foo, + Bar, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub enum MissingEqNonExhaustive3 { + Foo, + #[non_exhaustive] + Bar, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs index 476d2aee23a..90ac7a7989e 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs @@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn { #[derive(PartialEq)] struct InternalTy; +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct MissingEqNonExhaustive { + foo: u32, + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub struct MissingEqNonExhaustive1 { + foo: u32, + #[non_exhaustive] + bar: String, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub enum MissingEqNonExhaustive2 { + Foo, + Bar, +} + +// This is a `non_exhaustive` type so should not warn. +#[derive(Debug, PartialEq)] +pub enum MissingEqNonExhaustive3 { + Foo, + #[non_exhaustive] + Bar, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index bff46e55722..16f7bafd44b 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -64,7 +64,7 @@ fn test_units() { /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry /// WebGL WebGL2 WebGPU /// TensorFlow /// TrueType diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 4e162a97dee..4058b2bad74 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -64,7 +64,7 @@ fn test_units() { /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry /// WebGL WebGL2 WebGPU /// TensorFlow /// TrueType diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index 18d285693e6..4a68505ee0b 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -89,4 +89,12 @@ fn msrv_1_41() { } } +fn issue_12138() { + struct Hello; + + impl From<Hello> for () { + fn from(val: Hello) {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index 779ef709e92..bf3ed0c2b64 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -89,4 +89,12 @@ fn msrv_1_41() { } } +fn issue_12138() { + struct Hello; + + impl Into<()> for Hello { + fn into(self) {} + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index 784843ce5fd..f1370ed844f 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -86,5 +86,19 @@ LL ~ fn from(val: Vec<T>) -> Self { LL ~ FromOverInto(val) | -error: aborting due to 6 previous errors +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into.rs:95:5 + | +LL | impl Into<()> for Hello { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see + https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence +help: replace the `Into` implementation with `From<issue_12138::Hello>` + | +LL ~ impl From<Hello> for () { +LL ~ fn from(val: Hello) {} + | + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs index e84b20e9fef..d53e1383d84 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -21,7 +21,6 @@ fn foo() -> bool { fn if_same_then_else() { if true { - //~^ ERROR: this `if` has identical blocks Foo { bar: 42 }; 0..10; ..; @@ -38,6 +37,7 @@ fn if_same_then_else() { 0..=10; foo(); } + //~^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { Foo { bar: 42 }; @@ -64,19 +64,11 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 0.0 - } else { - 0.0 - }; + let _ = if true { 0.0 } else { 0.0 }; + //~^ ERROR: this `if` has identical blocks - let _ = if true { - //~^ ERROR: this `if` has identical blocks - -0.0 - } else { - -0.0 - }; + let _ = if true { -0.0 } else { -0.0 }; + //~^ ERROR: this `if` has identical blocks let _ = if true { 0.0 } else { -0.0 }; @@ -87,15 +79,10 @@ fn if_same_then_else() { foo(); } - let _ = if true { - //~^ ERROR: this `if` has identical blocks - 42 - } else { - 42 - }; + let _ = if true { 42 } else { 42 }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks let bar = if true { 42 } else { 43 }; while foo() { @@ -110,6 +97,7 @@ fn if_same_then_else() { } bar + 1; } + //~^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { let _ = match 42 { diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr index fb33e94e6c3..281f30f88b4 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:32:12 + --> $DIR/if_same_then_else.rs:31:12 | LL | } else { | ____________^ @@ -29,75 +29,54 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:70:12 + --> $DIR/if_same_then_else.rs:67:34 | -LL | } else { - | ____________^ -LL | | 0.0 -LL | | }; - | |_____^ +LL | let _ = if true { 0.0 } else { 0.0 }; + | ^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:74:21 + --> $DIR/if_same_then_else.rs:70:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | -0.0 -LL | | } else { - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:77:12 + --> $DIR/if_same_then_else.rs:70:35 | -LL | } else { - | ____________^ -LL | | -0.0 -LL | | }; - | |_____^ +LL | let _ = if true { -0.0 } else { -0.0 }; + | ^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:90:21 + --> $DIR/if_same_then_else.rs:82:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | 42 -LL | | } else { - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ | note: same as this - --> $DIR/if_same_then_else.rs:93:12 + --> $DIR/if_same_then_else.rs:82:33 | -LL | } else { - | ____________^ -LL | | 42 -LL | | }; - | |_____^ +LL | let _ = if true { 42 } else { 42 }; + | ^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:97:13 + --> $DIR/if_same_then_else.rs:85:13 | LL | if true { | _____________^ -LL | | LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:105:12 + --> $DIR/if_same_then_else.rs:92:12 | LL | } else { | ____________^ @@ -110,7 +89,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:250:14 + --> $DIR/if_same_then_else.rs:238:14 | LL | if x { | ______________^ @@ -119,7 +98,7 @@ LL | | } else { | |_________^ | note: same as this - --> $DIR/if_same_then_else.rs:252:16 + --> $DIR/if_same_then_else.rs:240:16 | LL | } else { | ________________^ diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs index 0b171f21d0c..e23c77b0827 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -13,7 +13,6 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { - //~^ ERROR: this `if` has identical blocks for _ in &[42] { let foo: &Option<_> = &Some::<u8>(42); if foo.is_some() { @@ -32,20 +31,21 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } + //~^^^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let Some(a) = Some(42) {} } else { if let Some(a) = Some(42) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks if let (1, .., 3) = (1, 2, 3) {} } else { if let (1, .., 3) = (1, 2, 3) {} } + //~^^^^^ ERROR: this `if` has identical blocks if true { if let (1, .., 3) = (1, 2, 3) {} @@ -90,19 +90,15 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } // Same NaNs - let _ = if true { - //~^ ERROR: this `if` has identical blocks - f32::NAN - } else { - f32::NAN - }; + let _ = if true { f32::NAN } else { f32::NAN }; + //~^ ERROR: this `if` has identical blocks if true { - //~^ ERROR: this `if` has identical blocks Ok("foo")?; } else { Ok("foo")?; } + //~^^^^^ ERROR: this `if` has identical blocks if true { let foo = ""; @@ -122,13 +118,13 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = "bar"; return Ok(&foo[0..]); } else if true { - //~^ ERROR: this `if` has identical blocks let foo = ""; return Ok(&foo[0..]); } else { let foo = ""; return Ok(&foo[0..]); } + //~^^^^^^^ ERROR: this `if` has identical blocks // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559. if true { diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr index fe68ef2711b..4e7a7c87dc5 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr @@ -3,16 +3,16 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::<u8>(42); +LL | | if foo.is_some() { ... | LL | | } LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:25:12 + --> $DIR/if_same_then_else2.rs:24:12 | LL | } else { | ____________^ @@ -31,13 +31,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:39:12 + --> $DIR/if_same_then_else2.rs:38:12 | LL | } else { | ____________^ @@ -50,13 +49,12 @@ error: this `if` has identical blocks | LL | if true { | _____________^ -LL | | LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:46:12 + --> $DIR/if_same_then_else2.rs:45:12 | LL | } else { | ____________^ @@ -67,34 +65,26 @@ LL | | } error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:93:21 | -LL | let _ = if true { - | _____________________^ -LL | | -LL | | f32::NAN -LL | | } else { - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ | note: same as this - --> $DIR/if_same_then_else2.rs:96:12 + --> $DIR/if_same_then_else2.rs:93:39 | -LL | } else { - | ____________^ -LL | | f32::NAN -LL | | }; - | |_____^ +LL | let _ = if true { f32::NAN } else { f32::NAN }; + | ^^^^^^^^^^^^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:100:13 + --> $DIR/if_same_then_else2.rs:96:13 | LL | if true { | _____________^ -LL | | LL | | Ok("foo")?; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:103:12 + --> $DIR/if_same_then_else2.rs:98:12 | LL | } else { | ____________^ @@ -103,18 +93,17 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:124:20 + --> $DIR/if_same_then_else2.rs:120:20 | LL | } else if true { | ____________________^ -LL | | LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:128:12 + --> $DIR/if_same_then_else2.rs:123:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.fixed b/src/tools/clippy/tests/ui/ineffective_open_options.fixed index 3af8f3c5aaa..88489dc46bb 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.fixed +++ b/src/tools/clippy/tests/ui/ineffective_open_options.fixed @@ -26,16 +26,23 @@ fn main() { .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(true) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(false) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); - let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); + let file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open("dump.json") + .unwrap(); } diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.rs b/src/tools/clippy/tests/ui/ineffective_open_options.rs index 4eaf6293c40..db8bca3e2ac 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.rs +++ b/src/tools/clippy/tests/ui/ineffective_open_options.rs @@ -26,16 +26,23 @@ fn main() { .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(true) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new() .create(true) + .truncate(true) .write(false) .append(false) .open("dump.json") .unwrap(); let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); - let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); + let file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open("dump.json") + .unwrap(); } diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.stderr b/src/tools/clippy/tests/ui/join_absolute_paths.stderr index 0c2f89d9978..ab4d189ca3a 100644 --- a/src/tools/clippy/tests/ui/join_absolute_paths.stderr +++ b/src/tools/clippy/tests/ui/join_absolute_paths.stderr @@ -11,7 +11,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("sh"); | ~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("/sh"); | ~~~~~~~~~~~~~~~~~~~~ @@ -27,7 +27,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("\user"); | ~~~~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("\\user"); | ~~~~~~~~~~~~~~~~~~~~~~~ @@ -43,7 +43,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join("sh"); | ~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from("/sh"); | ~~~~~~~~~~~~~~~~~~~~ @@ -59,7 +59,7 @@ help: if this is unintentional, try removing the starting separator | LL | path.join(r#"sh"#); | ~~~~~~~ -help: if this is intentional, try using `Path::new` instead +help: if this is intentional, consider using `Path::new` | LL | PathBuf::from(r#"/sh"#); | ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr index b277d22e59b..89df6cdbedb 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr @@ -17,7 +17,7 @@ error: called `map_or(Err(_), Ok)` on an `Option` value --> $DIR/manual_ok_or.rs:14:5 | LL | foo.map_or(Err("error"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `foo.ok_or("error")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `foo.ok_or("error")` | = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr index dc36a5ee7c6..3ce108b1ca8 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr @@ -2,7 +2,7 @@ error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:6:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` | = note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]` @@ -11,13 +11,13 @@ error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:7:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:8:13 | LL | let _ = 1u8.checked_add(1).unwrap_or(255); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u8.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u8.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:9:13 @@ -26,49 +26,49 @@ LL | let _ = 1u128 | _____________^ LL | | .checked_add(1) LL | | .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); - | |_______________________________________________________________________^ help: try using `saturating_add`: `1u128.saturating_add(1)` + | |_______________________________________________________________________^ help: consider using `saturating_add`: `1u128.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:14:13 | LL | let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_mul`: `1u32.saturating_mul(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `1u32.saturating_mul(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:16:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:17:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:18:13 | LL | let _ = 1u8.checked_sub(1).unwrap_or(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u8.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u8.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:22:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:23:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:24:13 | LL | let _ = 1i8.checked_add(1).unwrap_or(127); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:25:13 @@ -77,25 +77,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_add(1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); - | |_______________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(1)` + | |_______________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:28:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:29:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:30:13 | LL | let _ = 1i8.checked_add(-1).unwrap_or(-128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:31:13 @@ -104,25 +104,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_add(-1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); - | |________________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(-1)` + | |________________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:38:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:39:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:40:13 | LL | let _ = 1i8.checked_sub(1).unwrap_or(-128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:41:13 @@ -131,25 +131,25 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_sub(1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); - | |________________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(1)` + | |________________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:44:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:45:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:46:13 | LL | let _ = 1i8.checked_sub(-1).unwrap_or(127); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(-1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(-1)` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:47:13 @@ -158,7 +158,7 @@ LL | let _ = 1i128 | _____________^ LL | | .checked_sub(-1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); - | |_______________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(-1)` + | |_______________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(-1)` error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index 08b155a1aea..395eea69294 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -69,15 +69,48 @@ fn main() { //~^ ERROR: you are explicitly cloning with `.map()` let y = x.cloned(); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method let y = x.cloned(); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + let x: Option<u32> = Some(0); + let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Option<u32> = Some(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // Testing with `Result` now. let x: Result<String, ()> = Ok(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.cloned(); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method let y = x.cloned(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + let x: Result<u32, ()> = Ok(0); + let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + let y = x.copied(); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Result<u32, ()> = Ok(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // We ensure that no warning is emitted here because `useless_asref` is taking over. let x = Some(String::new()); diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index 901d9b278b4..82a103edf5a 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -69,15 +69,48 @@ fn main() { //~^ ERROR: you are explicitly cloning with `.map()` let y = x.map(Clone::clone); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method let y = x.map(String::clone); //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + let x: Option<u32> = Some(0); + let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. + let y = x.map(|x| u32::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Option<u32> = Some(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // Testing with `Result` now. let x: Result<String, ()> = Ok(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.map(|x| String::clone(x)); //~^ ERROR: you are explicitly cloning with `.map()` - let y = x.map(|x| String::clone(x)); + //~| HELP: consider calling the dedicated `cloned` method + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `cloned` method + + let x: Result<u32, ()> = Ok(0); + let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. + let y = x.map(|x| u32::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + let y = x.map(|x| Clone::clone(x)); + //~^ ERROR: you are explicitly cloning with `.map()` + //~| HELP: consider calling the dedicated `copied` method + + // Should not suggest `copied` or `cloned` here since `T` is not a reference. + let x: Result<u32, ()> = Ok(0); + let y = x.map(|x| u32::clone(&x)); + let y = x.map(|x| Clone::clone(&x)); // We ensure that no warning is emitted here because `useless_asref` is taking over. let x = Some(String::new()); diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr index 9d7e9317b58..2c86a67fab8 100644 --- a/src/tools/clippy/tests/ui/map_clone.stderr +++ b/src/tools/clippy/tests/ui/map_clone.stderr @@ -50,22 +50,46 @@ LL | let y = x.map(Clone::clone); | ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> $DIR/map_clone.rs:72:13 + --> $DIR/map_clone.rs:73:13 | LL | let y = x.map(String::clone); | ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> $DIR/map_clone.rs:78:13 + --> $DIR/map_clone.rs:79:13 | -LL | let y = x.map(|x| String::clone(x)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` +LL | let y = x.map(|x| u32::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> $DIR/map_clone.rs:80:13 + --> $DIR/map_clone.rs:82:13 + | +LL | let y = x.map(|x| Clone::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` + +error: you are explicitly cloning with `.map()` + --> $DIR/map_clone.rs:94:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` -error: aborting due to 11 previous errors +error: you are explicitly cloning with `.map()` + --> $DIR/map_clone.rs:97:13 + | +LL | let y = x.map(|x| Clone::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` + +error: you are explicitly cloning with `.map()` + --> $DIR/map_clone.rs:103:13 + | +LL | let y = x.map(|x| u32::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` + +error: you are explicitly cloning with `.map()` + --> $DIR/map_clone.rs:106:13 + | +LL | let y = x.map(|x| Clone::clone(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 525a355f403..3428ff45906 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -13,7 +13,6 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { 42 => { - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm foo(); let mut a = 42 + [23].len() as i32; if true { @@ -32,6 +31,7 @@ fn match_same_arms() { a }, }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { 42 => foo(), @@ -146,13 +146,13 @@ fn match_same_arms() { empty!(0); }, 1 => { - //~^ ERROR: this match arm has an identical body to another arm empty!(0); }, x => { empty!(x); }, } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 40b20c7e16d..512ca7413a7 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -2,9 +2,9 @@ error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { -LL | | LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; +LL | | if true { ... | LL | | a LL | | }, @@ -12,7 +12,7 @@ LL | | }, | = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:25:9 + --> $DIR/match_same_arms2.rs:24:9 | LL | / _ => { LL | | foo(); @@ -122,7 +122,6 @@ LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` | _________| | | -LL | | LL | | empty!(0); LL | | }, | |_________^ diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed new file mode 100644 index 00000000000..c970f2ba281 --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = an_option.take(); + let an_option = &mut Some(1); + let _ = an_option.take(); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = core::mem::take(&mut refstr); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = core::mem::take(&mut slice); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option<u8>, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = f.0.take(); + let _ = (*f).take(); + let _ = b.opt.take(); + // replace with default + let _ = mem::replace(&mut b.val, u8::default()); +} diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.rs b/src/tools/clippy/tests/ui/mem_replace_no_std.rs new file mode 100644 index 00000000000..673d5c7b4f4 --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.rs @@ -0,0 +1,82 @@ +#![allow(unused)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] +#![feature(lang_items)] +#![no_std] + +use core::mem; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn replace_option_with_none() { + let mut an_option = Some(1); + let _ = mem::replace(&mut an_option, None); + let an_option = &mut Some(1); + let _ = mem::replace(an_option, None); +} + +fn replace_with_default() { + let mut refstr = "hello"; + let _ = mem::replace(&mut refstr, ""); + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = mem::replace(&mut slice, &[]); +} + +// lint is disabled for primitives because in this case `take` +// has no clear benefit over `replace` and sometimes is harder to read +fn dont_lint_primitive() { + let mut pbool = true; + let _ = mem::replace(&mut pbool, false); + + let mut pint = 5; + let _ = mem::replace(&mut pint, 0); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); + dont_lint_primitive(); +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> core::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> core::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option<u8>, + val: u8, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1), val: 12 }; + + // replace option with none + let _ = mem::replace(&mut f.0, None); + let _ = mem::replace(&mut *f, None); + let _ = mem::replace(&mut b.opt, None); + // replace with default + let _ = mem::replace(&mut b.val, u8::default()); +} diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr new file mode 100644 index 00000000000..744fb5a1587 --- /dev/null +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr @@ -0,0 +1,50 @@ +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:24:13 + | +LL | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:26:13 + | +LL | let _ = mem::replace(an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + +error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` + --> $DIR/mem_replace_no_std.rs:31:13 + | +LL | let _ = mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` + +error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` + --> $DIR/mem_replace_no_std.rs:34:13 + | +LL | let _ = mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:77:13 + | +LL | let _ = mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:78:13 + | +LL | let _ = mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace_no_std.rs:79:13 + | +LL | let _ = mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 777b1e52c2d..dabeda72f0c 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -181,6 +181,8 @@ fn main() { //~^ ERROR: binding to `_` prefixed variable with no side-effect let _cat = [2, 4, 6, 8][2]; //~^ ERROR: binding to `_` prefixed variable with no side-effect + let _issue_12166 = 42; + let underscore_variable_above_can_be_used_dont_lint = _issue_12166; #[allow(clippy::no_effect)] 0; diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index f5ba234b4cb..8140ba1feee 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -152,31 +152,31 @@ LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:175:5 + --> $DIR/no_effect.rs:175:9 | LL | let _unused = 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:178:5 + --> $DIR/no_effect.rs:178:9 | LL | let _penguin = || println!("Some helpful closure"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:180:5 + --> $DIR/no_effect.rs:180:9 | LL | let _duck = Struct { field: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:182:5 + --> $DIR/no_effect.rs:182:9 | LL | let _cat = [2, 4, 6, 8][2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/open_options.rs b/src/tools/clippy/tests/ui/open_options.rs index 0cdc5bf2bb5..4acb3780df4 100644 --- a/src/tools/clippy/tests/ui/open_options.rs +++ b/src/tools/clippy/tests/ui/open_options.rs @@ -1,7 +1,18 @@ +#![allow(unused_must_use)] +#![warn(clippy::nonsensical_open_options)] + use std::fs::OpenOptions; -#[allow(unused_must_use)] -#[warn(clippy::nonsensical_open_options)] +trait OpenOptionsExt { + fn truncate_write(&mut self, opt: bool) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn truncate_write(&mut self, opt: bool) -> &mut Self { + self.truncate(opt).write(opt) + } +} + fn main() { OpenOptions::new().read(true).truncate(true).open("foo.txt"); //~^ ERROR: file opened with `truncate` and `read` @@ -11,12 +22,31 @@ fn main() { OpenOptions::new().read(true).read(false).open("foo.txt"); //~^ ERROR: the method `read` is called more than once - OpenOptions::new().create(true).create(false).open("foo.txt"); - //~^ ERROR: the method `create` is called more than once + OpenOptions::new() + .create(true) + .truncate(true) // Ensure we don't trigger suspicious open options by having create without truncate + .create(false) + //~^ ERROR: the method `create` is called more than once + .open("foo.txt"); OpenOptions::new().write(true).write(false).open("foo.txt"); //~^ ERROR: the method `write` is called more than once OpenOptions::new().append(true).append(false).open("foo.txt"); //~^ ERROR: the method `append` is called more than once OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); //~^ ERROR: the method `truncate` is called more than once + + std::fs::File::options().read(true).read(false).open("foo.txt"); + //~^ ERROR: the method `read` is called more than once + + let mut options = std::fs::OpenOptions::new(); + options.read(true); + options.read(false); + // Possible future improvement: recognize open options method call chains across statements. + options.open("foo.txt"); + + let mut options = std::fs::OpenOptions::new(); + options.truncate(true); + options.create(true).open("foo.txt"); + + OpenOptions::new().create(true).truncate_write(true).open("foo.txt"); } diff --git a/src/tools/clippy/tests/ui/open_options.stderr b/src/tools/clippy/tests/ui/open_options.stderr index 7ac826f52fa..4f84d1d09f9 100644 --- a/src/tools/clippy/tests/ui/open_options.stderr +++ b/src/tools/clippy/tests/ui/open_options.stderr @@ -1,5 +1,5 @@ error: file opened with `truncate` and `read` - --> $DIR/open_options.rs:6:5 + --> $DIR/open_options.rs:17:5 | LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,40 +8,46 @@ LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); = help: to override `-D warnings` add `#[allow(clippy::nonsensical_open_options)]` error: file opened with `append` and `truncate` - --> $DIR/open_options.rs:9:5 + --> $DIR/open_options.rs:20:5 | LL | OpenOptions::new().append(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method `read` is called more than once - --> $DIR/open_options.rs:12:5 + --> $DIR/open_options.rs:23:35 | LL | OpenOptions::new().read(true).read(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: the method `create` is called more than once - --> $DIR/open_options.rs:14:5 + --> $DIR/open_options.rs:28:10 | -LL | OpenOptions::new().create(true).create(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | .create(false) + | ^^^^^^^^^^^^^ error: the method `write` is called more than once - --> $DIR/open_options.rs:16:5 + --> $DIR/open_options.rs:31:36 | LL | OpenOptions::new().write(true).write(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: the method `append` is called more than once - --> $DIR/open_options.rs:18:5 + --> $DIR/open_options.rs:33:37 | LL | OpenOptions::new().append(true).append(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: the method `truncate` is called more than once - --> $DIR/open_options.rs:20:5 + --> $DIR/open_options.rs:35:39 | LL | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ + +error: the method `read` is called more than once + --> $DIR/open_options.rs:38:41 + | +LL | std::fs::File::options().read(true).read(false).open("foo.txt"); + | ^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/open_options_fixable.fixed b/src/tools/clippy/tests/ui/open_options_fixable.fixed new file mode 100644 index 00000000000..90a129a9bdf --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.fixed @@ -0,0 +1,7 @@ +use std::fs::OpenOptions; +#[allow(unused_must_use)] +#[warn(clippy::suspicious_open_options)] +fn main() { + OpenOptions::new().create(true).truncate(true).open("foo.txt"); + //~^ ERROR: file opened with `create`, but `truncate` behavior not defined +} diff --git a/src/tools/clippy/tests/ui/open_options_fixable.rs b/src/tools/clippy/tests/ui/open_options_fixable.rs new file mode 100644 index 00000000000..3a9e522ba15 --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.rs @@ -0,0 +1,7 @@ +use std::fs::OpenOptions; +#[allow(unused_must_use)] +#[warn(clippy::suspicious_open_options)] +fn main() { + OpenOptions::new().create(true).open("foo.txt"); + //~^ ERROR: file opened with `create`, but `truncate` behavior not defined +} diff --git a/src/tools/clippy/tests/ui/open_options_fixable.stderr b/src/tools/clippy/tests/ui/open_options_fixable.stderr new file mode 100644 index 00000000000..e327661713b --- /dev/null +++ b/src/tools/clippy/tests/ui/open_options_fixable.stderr @@ -0,0 +1,14 @@ +error: file opened with `create`, but `truncate` behavior not defined + --> $DIR/open_options_fixable.rs:5:24 + | +LL | OpenOptions::new().create(true).open("foo.txt"); + | ^^^^^^^^^^^^- help: add: `.truncate(true)` + | + = help: if you intend to overwrite an existing file entirely, call `.truncate(true)` + = help: if you instead know that you may want to keep some parts of the old file, call `.truncate(false)` + = help: alternatively, use `.append(true)` to append to the file instead of overwriting it + = note: `-D clippy::suspicious-open-options` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_open_options)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr index 9d173e409ab..036b8c749e4 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr @@ -2,7 +2,7 @@ error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:11:13 | LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.clone().as_deref()` | = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` @@ -15,103 +15,103 @@ LL | let _ = opt.clone() LL | | .as_ref().map( LL | | Deref::deref LL | | ) - | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` + | |_________^ help: consider using as_deref: `opt.clone().as_deref()` error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value --> $DIR/option_as_ref_deref.rs:20:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_ref().map(String::as_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(|x| x.as_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:23:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(String::as_mut_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:24:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(CString::as_c_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:26:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(CString::new(vec![]).unwrap()).as_deref()` error: called `.as_ref().map(OsString::as_os_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:27:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(OsString::new()).as_deref()` error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value --> $DIR/option_as_ref_deref.rs:28:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(PathBuf::new()).as_deref()` error: called `.as_ref().map(Vec::as_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:29:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(Vec::<()>::new()).as_deref()` error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:30:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `Some(Vec::<()>::new()).as_deref_mut()` error: called `.as_ref().map(|x| x.deref())` on an `Option` value --> $DIR/option_as_ref_deref.rs:32:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value --> $DIR/option_as_ref_deref.rs:33:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.clone().as_deref_mut()` error: called `.as_ref().map(|x| &**x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:40:13 | LL | let _ = opt.as_ref().map(|x| &**x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| &mut **x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:41:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_ref().map(String::as_str); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr index a193e3c4c49..381601cb6b3 100644 --- a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr @@ -2,7 +2,7 @@ error: called `map_or(Err(_), Ok)` on an `Option` value --> $DIR/option_map_or_err_ok.rs:5:13 | LL | let _ = x.map_or(Err("a"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `x.ok_or("a")` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `x.ok_or("a")` | = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr index f2cfc3f9a28..d58ff83c3da 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr @@ -2,7 +2,7 @@ error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:10:26 | LL | let _: Option<i32> = opt.map_or(None, |x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `map`: `opt.map(|x| x + 1)` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` @@ -14,13 +14,13 @@ LL | let _: Option<i32> = opt.map_or(None, |x| { | __________________________^ LL | | Some(x + 1) LL | | }); - | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` + | |_________________________^ help: consider using `map`: `opt.map(|x| x + 1)` error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:17:26 | LL | let _: Option<i32> = opt.map_or(None, bar); - | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `and_then`: `opt.and_then(bar)` error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:18:26 @@ -33,7 +33,7 @@ LL | | Some(offset + height) LL | | }); | |______^ | -help: try using `and_then` instead +help: consider using `and_then` | LL ~ let _: Option<i32> = opt.and_then(|x| { LL + let offset = 0; @@ -46,7 +46,7 @@ error: called `map_or(None, Some)` on a `Result` value --> $DIR/option_map_or_none.rs:25:26 | LL | let _: Option<i32> = r.map_or(None, Some); - | ^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `r.ok()` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `r.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed new file mode 100644 index 00000000000..97c8c394c03 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = core::ptr::eq(a, b); + let _ = core::ptr::eq(a, b); + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs new file mode 100644 index 00000000000..a7ba9b4d817 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs @@ -0,0 +1,49 @@ +#![warn(clippy::ptr_eq)] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +macro_rules! mac { + ($a:expr, $b:expr) => { + $a as *const _ as usize == $b as *const _ as usize + }; +} + +macro_rules! another_mac { + ($a:expr, $b:expr) => { + $a as *const _ == $b as *const _ + }; +} + +fn main() { + let a = &[1, 2, 3]; + let b = &[1, 2, 3]; + + let _ = a as *const _ as usize == b as *const _ as usize; + let _ = a as *const _ == b as *const _; + let _ = a.as_ptr() == b as *const _; + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint + + let _ = mac!(a, b); + let _ = another_mac!(a, b); + + let a = &mut [1, 2, 3]; + let b = &mut [1, 2, 3]; + + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + let _ = a.as_mut_ptr() == b.as_mut_ptr(); + + let _ = a == b; + let _ = core::ptr::eq(a, b); +} diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr new file mode 100644 index 00000000000..3e289f5be61 --- /dev/null +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr @@ -0,0 +1,17 @@ +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:31:13 + | +LL | let _ = a as *const _ as usize == b as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + | + = note: `-D clippy::ptr-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` + +error: use `core::ptr::eq` when comparing raw pointers + --> $DIR/ptr_eq_no_std.rs:32:13 + | +LL | let _ = a as *const _ == b as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs index 76b9b981851..fd5a88a37a6 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs @@ -56,14 +56,6 @@ fn test() -> io::Result<()> { f.read(&mut buf)?; // should not lint - let mut empty = vec![]; - let mut data7 = vec![]; - f.read(&mut empty); - - // should not lint - f.read(&mut data7); - - // should not lint let mut data8 = Vec::new(); data8.resize(100, 0); f.read_exact(&mut data8)?; @@ -75,6 +67,27 @@ fn test() -> io::Result<()> { Ok(()) } +fn test_nested() -> io::Result<()> { + let cap = 1000; + let mut f = File::open("foo.txt").unwrap(); + + // Issue #9274 + // Should not lint + let mut v = Vec::new(); + { + v.resize(10, 0); + f.read(&mut v)?; + } + + let mut v = Vec::new(); + { + f.read(&mut v)?; + //~^ ERROR: reading zero byte data to `Vec` + } + + Ok(()) +} + async fn test_futures<R: AsyncRead + Unpin>(r: &mut R) { // should lint let mut data = Vec::new(); diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr index 523ecb2948d..e85aa051c34 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr @@ -2,7 +2,7 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:21:5 | LL | f.read_exact(&mut data).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)` | = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` @@ -11,19 +11,19 @@ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:27:5 | LL | f.read_exact(&mut data2)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)` error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:32:5 | LL | f.read_exact(&mut data3)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:37:5 + --> $DIR/read_zero_byte_vec.rs:37:13 | LL | let _ = f.read(&mut data4)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:43:9 @@ -38,28 +38,34 @@ LL | f.read(&mut data6) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:81:5 + --> $DIR/read_zero_byte_vec.rs:84:9 + | +LL | f.read(&mut v)?; + | ^^^^^^^^^^^^^^ + +error: reading zero byte data to `Vec` + --> $DIR/read_zero_byte_vec.rs:94:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:86:5 + --> $DIR/read_zero_byte_vec.rs:99:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:93:5 + --> $DIR/read_zero_byte_vec.rs:106:5 | LL | r.read(&mut data).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> $DIR/read_zero_byte_vec.rs:98:5 + --> $DIR/read_zero_byte_vec.rs:111:5 | LL | r.read_exact(&mut data2).await.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr index 3d6bfef48ec..201868f09ef 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr @@ -2,7 +2,7 @@ error: called `map_or(None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:5:13 | LL | let _ = opt.map_or(None, Some); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` @@ -11,13 +11,13 @@ error: called `map_or_else(|_| None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:7:13 | LL | let _ = opt.map_or_else(|_| None, Some); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` error: called `map_or_else(|_| None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:10:13 | LL | let _ = opt.map_or_else(|_| { None }, Some); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr index f519be46369..f569aab6490 100644 --- a/src/tools/clippy/tests/ui/same_item_push.stderr +++ b/src/tools/clippy/tests/ui/same_item_push.stderr @@ -4,7 +4,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) = note: `-D clippy::same-item-push` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::same_item_push)]` @@ -14,7 +14,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:36:9 @@ -22,7 +22,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(13); | ^^^ | - = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) + = help: consider using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:42:9 @@ -30,7 +30,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(VALUE); | ^^^ | - = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) + = help: consider using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:49:9 @@ -38,7 +38,7 @@ error: it looks like the same item is being pushed into this Vec LL | vec.push(item); | ^^^ | - = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + = help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index a7a47447f61..9dec8c9caf2 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -40,7 +40,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:42:20 | LL | let _ = (0..1).find(some_closure).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(some_closure)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:52:13 @@ -82,7 +82,7 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:79:13 | LL | let _ = (0..1).find(some_closure).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(some_closure)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr index f33b0430912..107f59a97d2 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr @@ -2,7 +2,7 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:9:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` @@ -11,43 +11,43 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:10:13 | LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| **y == x)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:11:13 | LL | let _ = (0..1).find(|x| *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:12:13 | LL | let _ = v.iter().find(|x| **x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:13:13 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:14:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:15:13 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:16:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:17:13 @@ -56,91 +56,91 @@ LL | let _ = (1..3) | _____________^ LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) LL | | .is_none(); - | |__________________^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + | |__________________^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` error: called `is_none()` after searching an `Iterator` with `position` --> $DIR/search_is_some_fixable_none.rs:22:13 | LL | let _ = v.iter().position(|&x| x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some_fixable_none.rs:25:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:31:13 | LL | let _ = "hello world".find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:32:13 | LL | let _ = "hello world".find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:33:13 | LL | let _ = "hello world".find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:35:13 | LL | let _ = s1.find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:36:13 | LL | let _ = s1.find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:37:13 | LL | let _ = s1.find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:39:13 | LL | let _ = s1[2..].find("world").is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains("world")` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:40:13 | LL | let _ = s1[2..].find(&s2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2)` error: called `is_none()` after calling `find()` on a string --> $DIR/search_is_some_fixable_none.rs:41:13 | LL | let _ = s1[2..].find(&s2[2..]).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2[2..])` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:57:25 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == &cc)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:73:30 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == cc)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:84:17 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:87:17 @@ -152,7 +152,7 @@ LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) LL | | .is_none(); | |______________________^ | -help: use `!_.any()` instead +help: consider using | LL ~ let _ = !vfoo LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); @@ -162,49 +162,49 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:95:17 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|a| a[0] == 42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|a| a[0] == 42)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:101:17 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:119:17 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:120:17 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:123:17 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:124:17 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:127:17 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:129:17 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:149:17 @@ -216,7 +216,7 @@ LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == LL | | .is_none(); | |______________________^ | -help: use `!_.any()` instead +help: consider using | LL ~ let _ = !vfoo LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); @@ -226,61 +226,61 @@ error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:165:17 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:170:17 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|x| (**x)[0] == 9)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:183:17 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:187:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:188:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:207:17 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| s[0].is_empty())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| s[0].is_empty())` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:208:17 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| test_string_1(&s[0]))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| test_string_1(&s[0]))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:217:17 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| fp.field.is_power_of_two())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| fp.field.is_power_of_two())` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:218:17 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_1(fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_1(fp.field))` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:219:17 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: aborting due to 43 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr index e878e62de07..e706ce64692 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr @@ -2,7 +2,7 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:9:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` @@ -11,43 +11,43 @@ error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:10:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:11:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:12:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:13:20 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 1 || x == 3 || x == 5)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 1 || x == 3 || x == 5)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:14:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:15:20 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0 || [1, 2, 3].contains(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:16:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:18:10 @@ -55,91 +55,91 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) | __________^ LL | | .is_some(); - | |__________________^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + | |__________________^ help: consider using: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` error: called `is_some()` after searching an `Iterator` with `position` --> $DIR/search_is_some_fixable_some.rs:22:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some_fixable_some.rs:25:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:30:27 | LL | let _ = "hello world".find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:31:27 | LL | let _ = "hello world".find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:32:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:34:16 | LL | let _ = s1.find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:35:16 | LL | let _ = s1.find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:36:16 | LL | let _ = s1.find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:38:21 | LL | let _ = s1[2..].find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:39:21 | LL | let _ = s1[2..].find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable_some.rs:40:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:56:44 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == &cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == &cc)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:72:49 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == cc)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == cc)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:83:29 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.foo == 1 && v.bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:88:14 @@ -147,55 +147,55 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) | ______________^ LL | | .is_some(); - | |______________________^ help: use `any()` instead: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` + | |______________________^ help: consider using: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:94:29 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|a| a[0] == 42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|a| a[0] == 42)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:100:29 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|sub| sub[1..4].len() == 3)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:118:30 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|ppp_x: &&u32| please(ppp_x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:119:50 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s.len() == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:122:26 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:123:26 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| deref_enough(*x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:126:26 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:128:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:150:14 @@ -203,91 +203,91 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) | ______________^ LL | | .is_some(); - | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` + | |______________________^ help: consider using: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:164:29 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.inner[0].bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:169:29 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| (**x)[0] == 9)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:182:29 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.by_ref(&v.bar))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:186:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:187:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:206:26 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s[0].is_empty())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s[0].is_empty())` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:207:26 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| test_string_1(&s[0]))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| test_string_1(&s[0]))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:216:26 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| fp.field.is_power_of_two())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| fp.field.is_power_of_two())` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:217:26 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_1(fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_1(fp.field))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:218:26 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_2(*fp.field))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:233:18 | LL | v.iter().find(|x: &&u32| func(x)).is_some() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| func(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| func(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:242:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref_impl(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_impl(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:245:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref_dyn(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_dyn(&x))` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:248:26 | LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` error: aborting due to 47 previous errors diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed index 15cc8d54faa..8859a68320f 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -80,6 +80,7 @@ fn main() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -104,6 +105,7 @@ fn msrv_1_54() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -124,6 +126,7 @@ fn msrv_1_55() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs index 197225ffbd5..7b72efb34ff 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs @@ -80,6 +80,7 @@ fn main() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -104,6 +105,7 @@ fn msrv_1_54() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); @@ -124,6 +126,7 @@ fn msrv_1_55() { .write(true) .read(true) .create(true) + .truncate(true) .open("foo.txt") .unwrap(); diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr index 05c11cf7f8c..b6b0d2effa8 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -14,7 +14,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> $DIR/seek_to_start_instead_of_rewind.rs:133:7 + --> $DIR/seek_to_start_instead_of_rewind.rs:136:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed index bbcc0de27d1..cdfa5d9cc78 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed @@ -1,6 +1,11 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::semicolon_if_nothing_returned)] #![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)] +#[macro_use] +extern crate proc_macro_attr; + fn get_unit() {} // the functions below trigger the lint @@ -120,3 +125,32 @@ fn let_else_stmts() { return; }; } + +mod issue12123 { + #[rustfmt::skip] + mod this_triggers { + #[fake_main] + async fn main() { + + } + } + + mod and_this { + #[fake_main] + async fn main() { + println!("hello"); + } + } + + #[rustfmt::skip] + mod maybe_this { + /** */ #[fake_main] + async fn main() { + } + } + + mod but_this_does_not { + #[fake_main] + async fn main() {} + } +} diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs index fdc9c0c33f5..315b7e4f383 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs @@ -1,6 +1,11 @@ +//@aux-build:proc_macro_attr.rs + #![warn(clippy::semicolon_if_nothing_returned)] #![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)] +#[macro_use] +extern crate proc_macro_attr; + fn get_unit() {} // the functions below trigger the lint @@ -120,3 +125,32 @@ fn let_else_stmts() { return; }; } + +mod issue12123 { + #[rustfmt::skip] + mod this_triggers { + #[fake_main] + async fn main() { + + } + } + + mod and_this { + #[fake_main] + async fn main() { + println!("hello"); + } + } + + #[rustfmt::skip] + mod maybe_this { + /** */ #[fake_main] + async fn main() { + } + } + + mod but_this_does_not { + #[fake_main] + async fn main() {} + } +} diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr index 66373a13c56..09c4d12f216 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr @@ -1,5 +1,5 @@ error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:8:5 + --> $DIR/semicolon_if_nothing_returned.rs:13:5 | LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` @@ -8,25 +8,25 @@ LL | println!("Hello") = help: to override `-D warnings` add `#[allow(clippy::semicolon_if_nothing_returned)]` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:12:5 + --> $DIR/semicolon_if_nothing_returned.rs:17:5 | LL | get_unit() | ^^^^^^^^^^ help: add a `;` here: `get_unit();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:17:5 + --> $DIR/semicolon_if_nothing_returned.rs:22:5 | LL | y = x + 1 | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:23:9 + --> $DIR/semicolon_if_nothing_returned.rs:28:9 | LL | hello() | ^^^^^^^ help: add a `;` here: `hello();` error: consider adding a `;` to the last statement for consistent formatting - --> $DIR/semicolon_if_nothing_returned.rs:34:9 + --> $DIR/semicolon_if_nothing_returned.rs:39:9 | LL | ptr::drop_in_place(s.as_mut_ptr()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());` diff --git a/src/tools/clippy/tests/ui/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs index 3cc8061647d..c20214feccc 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.rs +++ b/src/tools/clippy/tests/ui/single_call_fn.rs @@ -69,6 +69,17 @@ fn e() { #[test] fn k() {} +mod issue12182 { + #[allow(clippy::single_call_fn)] + fn print_foo(text: &str) { + println!("{text}"); + } + + fn use_print_foo() { + print_foo("foo"); + } +} + #[test] fn l() { k(); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index 781ab316d9d..664d6b5a1e9 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -2,7 +2,7 @@ error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:7:13 | LL | x.split("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` | = note: `-D clippy::single-char-pattern` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` @@ -11,235 +11,235 @@ error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:13:13 | LL | x.split("ß"); - | ^^^ help: try using a `char` instead: `'ß'` + | ^^^ help: consider using a `char`: `'ß'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:14:13 | LL | x.split("ℝ"); - | ^^^ help: try using a `char` instead: `'ℝ'` + | ^^^ help: consider using a `char`: `'ℝ'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:15:13 | LL | x.split("💣"); - | ^^^^ help: try using a `char` instead: `'💣'` + | ^^^^ help: consider using a `char`: `'💣'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:18:23 | LL | x.split_inclusive("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:19:16 | LL | x.contains("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:20:19 | LL | x.starts_with("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:21:17 | LL | x.ends_with("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:22:12 | LL | x.find("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:23:13 | LL | x.rfind("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:24:14 | LL | x.rsplit("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:25:24 | LL | x.split_terminator("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:26:25 | LL | x.rsplit_terminator("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:27:17 | LL | x.splitn(2, "x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:28:18 | LL | x.rsplitn(2, "x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:29:18 | LL | x.split_once("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:30:19 | LL | x.rsplit_once("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:31:15 | LL | x.matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:32:16 | LL | x.rmatches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:33:21 | LL | x.match_indices("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:34:22 | LL | x.rmatch_indices("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:35:26 | LL | x.trim_start_matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:36:24 | LL | x.trim_end_matches("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:37:20 | LL | x.strip_prefix("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:38:20 | LL | x.strip_suffix("x"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:39:15 | LL | x.replace("x", "y"); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:40:16 | LL | x.replacen("x", "y", 3); - | ^^^ help: try using a `char` instead: `'x'` + | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:42:13 | LL | x.split("\n"); - | ^^^^ help: try using a `char` instead: `'\n'` + | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:43:13 | LL | x.split("'"); - | ^^^ help: try using a `char` instead: `'\''` + | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:44:13 | LL | x.split("\'"); - | ^^^^ help: try using a `char` instead: `'\''` + | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:46:13 | LL | x.split("\""); - | ^^^^ help: try using a `char` instead: `'"'` + | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:51:31 | LL | x.replace(';', ",").split(","); // issue #2978 - | ^^^ help: try using a `char` instead: `','` + | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:52:19 | LL | x.starts_with("\x03"); // issue #2996 - | ^^^^^^ help: try using a `char` instead: `'\x03'` + | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:59:13 | LL | x.split(r"a"); - | ^^^^ help: try using a `char` instead: `'a'` + | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:60:13 | LL | x.split(r#"a"#); - | ^^^^^^ help: try using a `char` instead: `'a'` + | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:61:13 | LL | x.split(r###"a"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'a'` + | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:62:13 | LL | x.split(r###"'"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'\''` + | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:63:13 | LL | x.split(r###"#"###); - | ^^^^^^^^^^ help: try using a `char` instead: `'#'` + | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:65:13 | LL | x.split(r#"\"#); - | ^^^^^^ help: try using a `char` instead: `'\\'` + | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:66:13 | LL | x.split(r"\"); - | ^^^^ help: try using a `char` instead: `'\\'` + | ^^^^ help: consider using a `char`: `'\\'` error: aborting due to 40 previous errors diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index 4fca29698e0..7e2663d734f 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -118,4 +118,33 @@ fn bad_trait_object(arg0: &(dyn Any + Send)) { unimplemented!(); } -fn main() {} +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base<T> { + fn is_base(&self); +} + +trait Derived<B: Proj>: Base<B::S> + Base<()> { + fn is_derived(&self); +} + +fn f<P: Proj>(obj: &dyn Derived<P>) { + obj.is_derived(); + Base::<P::S>::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::<i32>; +} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index f67c8e35ed4..fede1671a43 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -118,4 +118,33 @@ fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { unimplemented!(); } -fn main() {} +trait Proj { + type S; +} + +impl Proj for () { + type S = (); +} + +impl Proj for i32 { + type S = i32; +} + +trait Base<T> { + fn is_base(&self); +} + +trait Derived<B: Proj>: Base<B::S> + Base<()> { + fn is_derived(&self); +} + +fn f<P: Proj>(obj: &dyn Derived<P>) { + obj.is_derived(); + Base::<P::S>::is_base(obj); + Base::<()>::is_base(obj); +} + +fn main() { + let _x: fn(_) = f::<()>; + let _x: fn(_) = f::<i32>; +} diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 32f6027e991..1796ccaf28e 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -102,19 +102,6 @@ fn crosspointer() { } } -#[warn(clippy::transmute_int_to_char)] -fn int_to_char() { - let _: char = unsafe { std::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` - let _: char = unsafe { std::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `char` - - // These shouldn't warn - const _: char = unsafe { std::mem::transmute(0_u32) }; - const _: char = unsafe { std::mem::transmute(0_i32) }; -} - #[warn(clippy::transmute_int_to_bool)] fn int_to_bool() { let _: bool = unsafe { std::mem::transmute(0_u8) }; diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index cdc733b54a9..df32d478cbf 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -88,23 +88,8 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:107:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` - | - = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` - -error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:110:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` - error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:120:28 + --> $DIR/transmute.rs:107:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -113,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:128:31 + --> $DIR/transmute.rs:115:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -122,25 +107,25 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:131:31 + --> $DIR/transmute.rs:118:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> $DIR/transmute.rs:133:31 + --> $DIR/transmute.rs:120:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> $DIR/transmute.rs:135:31 + --> $DIR/transmute.rs:122:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:156:30 + --> $DIR/transmute.rs:143:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -149,85 +134,85 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> $DIR/transmute.rs:159:30 + --> $DIR/transmute.rs:146:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> $DIR/transmute.rs:161:31 + --> $DIR/transmute.rs:148:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> $DIR/transmute.rs:163:30 + --> $DIR/transmute.rs:150:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> $DIR/transmute.rs:165:30 + --> $DIR/transmute.rs:152:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> $DIR/transmute.rs:167:31 + --> $DIR/transmute.rs:154:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> $DIR/transmute.rs:169:30 + --> $DIR/transmute.rs:156:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> $DIR/transmute.rs:171:30 + --> $DIR/transmute.rs:158:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> $DIR/transmute.rs:177:30 + --> $DIR/transmute.rs:164:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> $DIR/transmute.rs:179:30 + --> $DIR/transmute.rs:166:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> $DIR/transmute.rs:181:31 + --> $DIR/transmute.rs:168:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> $DIR/transmute.rs:183:30 + --> $DIR/transmute.rs:170:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> $DIR/transmute.rs:185:30 + --> $DIR/transmute.rs:172:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> $DIR/transmute.rs:187:31 + --> $DIR/transmute.rs:174:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:198:28 + --> $DIR/transmute.rs:185:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -236,16 +221,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:201:32 + --> $DIR/transmute.rs:188:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:203:30 + --> $DIR/transmute.rs:190:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 38 previous errors +error: aborting due to 36 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed new file mode 100644 index 00000000000..17080118175 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +fn int_to_char() { + let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs new file mode 100644 index 00000000000..5846a97e88a --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs @@ -0,0 +1,15 @@ +#![warn(clippy::transmute_int_to_char)] + +fn int_to_char() { + let _: char = unsafe { std::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { std::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { std::mem::transmute(0_u32) }; + const _: char = unsafe { std::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr new file mode 100644 index 00000000000..2297f5b4f8b --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char.rs:4:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char.rs:7:28 + | +LL | let _: char = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed new file mode 100644 index 00000000000..9ae4e11fb56 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn int_to_char() { + let _: char = unsafe { core::char::from_u32(0_u32).unwrap() }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs new file mode 100644 index 00000000000..9a2afd5bd2f --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs @@ -0,0 +1,27 @@ +#![no_std] +#![feature(lang_items)] +#![warn(clippy::transmute_int_to_char)] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn int_to_char() { + let _: char = unsafe { core::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `char` + //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + let _: char = unsafe { core::mem::transmute(0_i32) }; + //~^ ERROR: transmute from a `i32` to a `char` + + // These shouldn't warn + const _: char = unsafe { core::mem::transmute(0_u32) }; + const _: char = unsafe { core::mem::transmute(0_i32) }; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr new file mode 100644 index 00000000000..aace6968696 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr @@ -0,0 +1,17 @@ +error: transmute from a `u32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:16:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()` + | + = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute_int_to_char_no_std.rs:19:28 + | +LL | let _: char = unsafe { core::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs index e7f35c57436..bdc7b9f6478 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -12,7 +12,7 @@ fn main() { let b: &[u8] = unsafe { std::mem::transmute(a) }; //~^ ERROR: transmute from a reference to a reference let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; - let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; //~^ ERROR: transmute from a reference to a reference } } diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr index cc6b156b188..4238bc637ad 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -19,8 +19,8 @@ LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; error: transmute from a reference to a reference --> $DIR/transmute_ref_to_ref.rs:15:42 | -LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` +LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs new file mode 100644 index 00000000000..b67386f8588 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; + //~^ ERROR: transmute from a reference to a reference + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { core::mem::transmute(a) }; + //~^ ERROR: transmute from a reference to a reference + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + //~^ ERROR: transmute from a reference to a reference + } +} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr new file mode 100644 index 00000000000..ca7966ffa9e --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr @@ -0,0 +1,26 @@ +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:21:39 + | +LL | let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` + | +note: the lint level is defined here + --> $DIR/transmute_ref_to_ref_no_std.rs:3:9 + | +LL | #![deny(clippy::transmute_ptr_to_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:24:33 + | +LL | let b: &[u8] = unsafe { core::mem::transmute(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref_no_std.rs:27:42 + | +LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs index e1a2d6a90b8..7b898a6e0e7 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.rs +++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs @@ -264,6 +264,28 @@ impl S13 { } } -fn main() { - // test code goes here +struct S14 { + field: String, +} + +impl PartialEq for S14 { + fn eq(&self, other: &Self) -> bool { + // Should not warn! + self.field.eq(&other.field) + } +} + +struct S15<'a> { + field: &'a S15<'a>, } + +impl PartialEq for S15<'_> { + fn eq(&self, other: &Self) -> bool { + //~^ ERROR: function cannot return without recursing + let mine = &self.field; + let theirs = &other.field; + mine.eq(theirs) + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr index 5d82e2a9f31..094b80d4586 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr +++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr @@ -340,5 +340,22 @@ note: recursive call site LL | Self::default() | ^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: function cannot return without recursing + --> $DIR/unconditional_recursion.rs:283:5 + | +LL | / fn eq(&self, other: &Self) -> bool { +LL | | +LL | | let mine = &self.field; +LL | | let theirs = &other.field; +LL | | mine.eq(theirs) +LL | | } + | |_____^ + | +note: recursive call site + --> $DIR/unconditional_recursion.rs:287:9 + | +LL | mine.eq(theirs) + | ^^^^^^^^^^^^^^^ + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_join.stderr b/src/tools/clippy/tests/ui/unnecessary_join.stderr index 8bf2ac5fdb1..205a714b694 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_join.stderr @@ -4,7 +4,7 @@ error: called `.collect::<Vec<String>>().join("")` on an iterator LL | .collect::<Vec<String>>() | __________^ LL | | .join(""); - | |_________________^ help: try using: `collect::<String>()` + | |_________________^ help: consider using: `collect::<String>()` | = note: `-D clippy::unnecessary-join` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_join)]` @@ -15,7 +15,7 @@ error: called `.collect::<Vec<String>>().join("")` on an iterator LL | .collect::<Vec<_>>() | __________^ LL | | .join(""); - | |_________________^ help: try using: `collect::<String>()` + | |_________________^ help: consider using: `collect::<String>()` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr index 9d54c8d50e3..f4409113a45 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -1,4 +1,4 @@ -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:12:5 | LL | vec.sort_by(|a, b| a.cmp(b)); @@ -7,67 +7,67 @@ LL | vec.sort_by(|a, b| a.cmp(b)); = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` -error: use Vec::sort here instead +error: consider using `sort` --> $DIR/unnecessary_sort_by.rs:13:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:14:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:15:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:18:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs()))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:19:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b)))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:29:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:30:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:89:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:90:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:92:9 | LL | args.sort_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| std::cmp::Reverse(b.name()))` -error: use Vec::sort_by_key here instead +error: consider using `sort_by_key` --> $DIR/unnecessary_sort_by.rs:93:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs index 62aec6e9eaf..9974600dad5 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.rs +++ b/src/tools/clippy/tests/ui/unused_io_amount.rs @@ -1,4 +1,5 @@ #![allow(dead_code, clippy::needless_pass_by_ref_mut)] +#![allow(clippy::redundant_pattern_matching)] #![warn(clippy::unused_io_amount)] extern crate futures; @@ -142,4 +143,90 @@ async fn undetected_bad_async_write<W: AsyncWrite + Unpin>(w: &mut W) { future.await.unwrap(); } +fn match_okay_underscore<T: io::Read + io::Write>(s: &mut T) { + match s.write(b"test") { + //~^ ERROR: written amount is not handled + Ok(_) => todo!(), + //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled + Err(_) => todo!(), + }; + + let mut buf = [0u8; 4]; + match s.read(&mut buf) { + //~^ ERROR: read amount is not handled + Ok(_) => todo!(), + //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled + Err(_) => todo!(), + } +} + +fn match_okay_underscore_read_expr<T: io::Read + io::Write>(s: &mut T) { + match s.read(&mut [0u8; 4]) { + //~^ ERROR: read amount is not handled + Ok(_) => todo!(), + //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled + Err(_) => todo!(), + } +} + +fn match_okay_underscore_write_expr<T: io::Read + io::Write>(s: &mut T) { + match s.write(b"test") { + //~^ ERROR: written amount is not handled + Ok(_) => todo!(), + //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled + Err(_) => todo!(), + } +} + +fn returned_value_should_not_lint<T: io::Read + io::Write>(s: &mut T) -> Result<usize, std::io::Error> { + s.write(b"test") +} + +fn if_okay_underscore_read_expr<T: io::Read + io::Write>(s: &mut T) { + if let Ok(_) = s.read(&mut [0u8; 4]) { + //~^ ERROR: read amount is not handled + todo!() + } +} + +fn if_okay_underscore_write_expr<T: io::Read + io::Write>(s: &mut T) { + if let Ok(_) = s.write(b"test") { + //~^ ERROR: written amount is not handled + todo!() + } +} + +fn if_okay_dots_write_expr<T: io::Read + io::Write>(s: &mut T) { + if let Ok(..) = s.write(b"test") { + //~^ ERROR: written amount is not handled + todo!() + } +} + +fn if_okay_underscore_write_expr_true_negative<T: io::Read + io::Write>(s: &mut T) { + if let Ok(bound) = s.write(b"test") { + todo!() + } +} + +fn match_okay_underscore_true_neg<T: io::Read + io::Write>(s: &mut T) { + match s.write(b"test") { + Ok(bound) => todo!(), + Err(_) => todo!(), + }; +} + +fn true_negative<T: io::Read + io::Write>(s: &mut T) { + let mut buf = [0u8; 4]; + let read_amount = s.read(&mut buf).unwrap(); +} + +fn on_return_should_not_raise<T: io::Read + io::Write>(s: &mut T) -> io::Result<usize> { + /// this is bad code because it goes around the problem of handling the read amount + /// by returning it, which makes it impossible to know this is a resonpose from the + /// correct account. + let mut buf = [0u8; 4]; + s.read(&mut buf) +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr index f9aef596a1c..4af56d264bf 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.stderr +++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr @@ -1,5 +1,5 @@ error: written amount is not handled - --> $DIR/unused_io_amount.rs:9:5 + --> $DIR/unused_io_amount.rs:10:5 | LL | s.write(b"test")?; | ^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | s.write(b"test")?; = help: to override `-D warnings` add `#[allow(clippy::unused_io_amount)]` error: read amount is not handled - --> $DIR/unused_io_amount.rs:12:5 + --> $DIR/unused_io_amount.rs:13:5 | LL | s.read(&mut buf)?; | ^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | s.read(&mut buf)?; = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:18:5 + --> $DIR/unused_io_amount.rs:19:5 | LL | s.write(b"test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | s.write(b"test").unwrap(); = help: use `Write::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:21:5 + --> $DIR/unused_io_amount.rs:22:5 | LL | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,19 +33,19 @@ LL | s.read(&mut buf).unwrap(); = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:26:5 + --> $DIR/unused_io_amount.rs:27:5 | LL | s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: written amount is not handled - --> $DIR/unused_io_amount.rs:28:5 + --> $DIR/unused_io_amount.rs:29:5 | LL | s.write_vectored(&[io::IoSlice::new(&[])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: read amount is not handled - --> $DIR/unused_io_amount.rs:36:5 + --> $DIR/unused_io_amount.rs:37:5 | LL | reader.read(&mut result).ok()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | reader.read(&mut result).ok()?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:46:5 + --> $DIR/unused_io_amount.rs:47:5 | LL | reader.read(&mut result).or_else(|err| Err(err))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | reader.read(&mut result).or_else(|err| Err(err))?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:59:5 + --> $DIR/unused_io_amount.rs:60:5 | LL | reader.read(&mut result).or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | reader.read(&mut result).or(Err(Error::Kind))?; = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:67:5 + --> $DIR/unused_io_amount.rs:68:5 | LL | / reader LL | | @@ -82,7 +82,7 @@ LL | | .expect("error"); = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:77:5 + --> $DIR/unused_io_amount.rs:78:5 | LL | s.write(b"ok").is_ok(); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | s.write(b"ok").is_ok(); = help: use `Write::write_all` instead, or handle partial writes error: written amount is not handled - --> $DIR/unused_io_amount.rs:79:5 + --> $DIR/unused_io_amount.rs:80:5 | LL | s.write(b"err").is_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL | s.write(b"err").is_err(); = help: use `Write::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:82:5 + --> $DIR/unused_io_amount.rs:83:5 | LL | s.read(&mut buf).is_ok(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | s.read(&mut buf).is_ok(); = help: use `Read::read_exact` instead, or handle partial reads error: read amount is not handled - --> $DIR/unused_io_amount.rs:84:5 + --> $DIR/unused_io_amount.rs:85:5 | LL | s.read(&mut buf).is_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | s.read(&mut buf).is_err(); = help: use `Read::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:89:5 + --> $DIR/unused_io_amount.rs:90:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | w.write(b"hello world").await.unwrap(); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:95:5 + --> $DIR/unused_io_amount.rs:96:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,15 @@ LL | r.read(&mut buf[..]).await.unwrap(); = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:109:9 + --> $DIR/unused_io_amount.rs:104:5 + | +LL | w.write(b"hello world"); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `AsyncWriteExt::write_all` instead, or handle partial writes + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:110:9 | LL | w.write(b"hello world").await?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +146,7 @@ LL | w.write(b"hello world").await?; = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:118:9 + --> $DIR/unused_io_amount.rs:119:9 | LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +154,7 @@ LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:127:5 + --> $DIR/unused_io_amount.rs:128:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,12 +162,103 @@ LL | w.write(b"hello world").await.unwrap(); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:133:5 + --> $DIR/unused_io_amount.rs:134:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `AsyncReadExt::read_exact` instead, or handle partial reads -error: aborting due to 20 previous errors +error: written amount is not handled + --> $DIR/unused_io_amount.rs:147:11 + | +LL | match s.write(b"test") { + | ^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:149:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:155:11 + | +LL | match s.read(&mut buf) { + | ^^^^^^^^^^^^^^^^ + | + = help: use `Read::read_exact` instead, or handle partial reads +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:157:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:164:11 + | +LL | match s.read(&mut [0u8; 4]) { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Read::read_exact` instead, or handle partial reads +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:166:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:173:11 + | +LL | match s.write(b"test") { + | ^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:175:9 + | +LL | Ok(_) => todo!(), + | ^^^^^^^^^^^^^^^^ + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:186:8 + | +LL | if let Ok(_) = s.read(&mut [0u8; 4]) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Read::read_exact` instead, or handle partial reads +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:186:12 + | +LL | if let Ok(_) = s.read(&mut [0u8; 4]) { + | ^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:193:8 + | +LL | if let Ok(_) = s.write(b"test") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:193:12 + | +LL | if let Ok(_) = s.write(b"test") { + | ^^^^^ + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:200:8 + | +LL | if let Ok(..) = s.write(b"test") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes +note: the result is consumed here, but the amount of I/O bytes remains unhandled + --> $DIR/unused_io_amount.rs:200:12 + | +LL | if let Ok(..) = s.write(b"test") { + | ^^^^^^ + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index 88b95095bc0..c98f2928e03 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -144,6 +144,42 @@ fn foo() { //~^ ERROR: this call to `as_ref.map(...)` does nothing } +mod issue12135 { + pub struct Struct { + field: Option<InnerStruct>, + } + + #[derive(Clone)] + pub struct Foo; + + #[derive(Clone)] + struct InnerStruct { + x: Foo, + } + + impl InnerStruct { + fn method(&self) -> &Foo { + &self.x + } + } + + pub fn f(x: &Struct) -> Option<Foo> { + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + // https://github.com/rust-lang/rust-clippy/pull/12136#discussion_r1451565223 + #[allow(clippy::clone_on_copy)] + Some(1).clone(); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + x.field.as_ref().map(|v| v.method().clone()) + } +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index 504dc1f5cbf..f9d603f116d 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -144,6 +144,42 @@ fn foo() { //~^ ERROR: this call to `as_ref.map(...)` does nothing } +mod issue12135 { + pub struct Struct { + field: Option<InnerStruct>, + } + + #[derive(Clone)] + pub struct Foo; + + #[derive(Clone)] + struct InnerStruct { + x: Foo, + } + + impl InnerStruct { + fn method(&self) -> &Foo { + &self.x + } + } + + pub fn f(x: &Struct) -> Option<Foo> { + x.field.as_ref().map(|v| v.clone()); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.as_ref().map(Clone::clone); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + x.field.as_ref().map(|v| Clone::clone(v)); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + // https://github.com/rust-lang/rust-clippy/pull/12136#discussion_r1451565223 + #[allow(clippy::clone_on_copy)] + Some(1).as_ref().map(|&x| x.clone()); + //~^ ERROR: this call to `as_ref.map(...)` does nothing + + x.field.as_ref().map(|v| v.method().clone()) + } +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr index deb5d90f2f6..e158df2664d 100644 --- a/src/tools/clippy/tests/ui/useless_asref.stderr +++ b/src/tools/clippy/tests/ui/useless_asref.stderr @@ -88,5 +88,29 @@ error: this call to `as_ref.map(...)` does nothing LL | let z = x.as_ref().map(|z| String::clone(z)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()` -error: aborting due to 14 previous errors +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:167:9 + | +LL | x.field.as_ref().map(|v| v.clone()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` + +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:169:9 + | +LL | x.field.as_ref().map(Clone::clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` + +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:171:9 + | +LL | x.field.as_ref().map(|v| Clone::clone(v)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` + +error: this call to `as_ref.map(...)` does nothing + --> $DIR/useless_asref.rs:176:9 + | +LL | Some(1).as_ref().map(|&x| x.clone()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index a05765b3981..3eadc66f544 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -19,7 +19,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = ["blyxyas"] [assign.owners] "/.github" = ["@flip1995"] diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 76c2e330b21..f4dac6e947e 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] mdbook = { version = "0.4", default-features = false, features = ["search"] } -rustc_error_codes = { version = "0.0.0", path = "../../../compiler/rustc_error_codes" } [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 865d7172cd3..2de2d959a95 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -4,13 +4,15 @@ extern crate rustc_driver; extern crate rustc_log; extern crate rustc_session; +extern crate rustc_errors; +use rustc_errors::codes::DIAGNOSTICS; + use std::env; use std::error::Error; use std::fs::{self, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; - use std::str::FromStr; use mdbook::book::{parse_summary, BookItem, Chapter}; @@ -38,7 +40,7 @@ fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> { write!(output_file, "# Rust Compiler Error Index\n")?; - for (err_code, description) in rustc_error_codes::DIAGNOSTICS.iter() { + for (err_code, description) in DIAGNOSTICS.iter() { write!(output_file, "## {}\n{}\n", err_code, description)? } @@ -85,7 +87,7 @@ This page lists all the error codes emitted by the Rust compiler. " ); - let err_codes = rustc_error_codes::DIAGNOSTICS; + let err_codes = DIAGNOSTICS; let mut chapters = Vec::with_capacity(err_codes.len()); for (err_code, explanation) in err_codes.iter() { diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml index 509521e7478..96d7d4d1118 100644 --- a/src/tools/miri/.github/workflows/sysroots.yml +++ b/src/tools/miri/.github/workflows/sysroots.yml @@ -1,8 +1,8 @@ name: Tier 2 sysroots -on: push -# schedule: -# - cron: '44 4 * * *' # At 4:44 UTC every day. +on: + schedule: + - cron: '44 4 * * *' # At 4:44 UTC every day. defaults: run: diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 6cd22a91518..8cd996d8564 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -486,9 +486,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "measureme" -version = "10.1.2" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe" +checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" dependencies = [ "log", "memmap2", diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 3dee742fa0d..6695f123c78 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -590,6 +590,7 @@ Definite bugs found: * [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186) * [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084) * [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460) +* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index a7412f90c85..79ce1f4ca32 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -501,11 +501,10 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner // Set missing env vars. We prefer build-time env vars over run-time ones; see // <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes. for (name, val) in info.env { - // `CARGO_MAKEFLAGS` contains information about how to reach the - // jobserver, but by the time the program is being run, that jobserver - // no longer exists. Hence we shouldn't forward this. - // FIXME: Miri builds the final crate without a jobserver. - // This may be fixed with github.com/rust-lang/cargo/issues/12597. + // `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time + // the program is being run, that jobserver no longer exists (cargo only runs the jobserver + // for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this. + // Also see <https://github.com/rust-lang/rust/pull/113730>. if name == "CARGO_MAKEFLAGS" { continue; } diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 548e12ffdea..6624672775f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98 +dd2559e08e1530806740931037d6bb83ef956161 diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 905b2fc4d60..d6b1e135808 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Helper function to get a `windows` constant as a `Scalar`. fn eval_windows(&self, module: &str, name: &str) -> Scalar<Provenance> { - self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal","windows", module, name]) + self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name]) } /// Helper function to get a `windows` constant as a `u32`. @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { 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) + .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS) .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty).unwrap() } @@ -270,6 +270,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { bug!("No field named {} in type {}", name, base.layout().ty); } + /// Search if `base` (which must be a struct or union type) contains the `name` field. + fn projectable_has_field<P: Projectable<'tcx, Provenance>>( + &self, + base: &P, + name: &str, + ) -> bool { + let adt = base.layout().ty.ty_adt_def().unwrap(); + for field in adt.non_enum_variant().fields.iter() { + if field.name.as_str() == name { + return true; + } + } + false + } + /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so /// this method is fine for almost all integer types. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index b0b6d994366..057b883a3bf 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -94,7 +94,6 @@ pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::TlsData; -pub use crate::shims::EvalContextExt as _; pub use crate::borrow_tracker::stacked_borrows::{ EvalContextExt as _, Item, Permission, Stack, Stacks, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 4cd48b2e5a3..946887637ff 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -10,8 +10,8 @@ use std::process; use either::Either; use rand::rngs::StdRng; -use rand::SeedableRng; use rand::Rng; +use rand::SeedableRng; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -83,7 +83,8 @@ pub struct FrameExtra<'tcx> { impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = self; + let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = + self; f.debug_struct("FrameData") .field("borrow_tracker", borrow_tracker) .field("catch_unwind", catch_unwind) @@ -93,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { impl VisitProvenance for FrameExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = self; + let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = + self; catch_unwind.visit_provenance(visit); borrow_tracker.visit_provenance(visit); @@ -710,7 +712,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { Ok(()) } - fn add_extern_static( + pub(crate) fn add_extern_static( this: &mut MiriInterpCx<'mir, 'tcx>, name: &str, ptr: Pointer<Option<Provenance>>, @@ -720,75 +722,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } - fn alloc_extern_static( - this: &mut MiriInterpCx<'mir, 'tcx>, - name: &str, - val: ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { - let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; - this.write_immediate(*val, &place)?; - Self::add_extern_static(this, name, place.ptr()); - Ok(()) - } - - /// Sets up the "extern statics" for this machine. - fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { - // "__rust_no_alloc_shim_is_unstable" - let val = ImmTy::from_int(0, this.machine.layouts.u8); - Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?; - - match this.tcx.sess.target.os.as_ref() { - "linux" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code which ends up calling a - // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] - { - let val = ImmTy::from_int(0, this.machine.layouts.usize); - Self::alloc_extern_static(this, name, val)?; - } - } - "freebsd" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr(), - ); - } - "android" => { - // "signal" -- just needs a non-zero pointer value (function does not even get called), - // but we arrange for this to be callable anyway (it will then do nothing). - let layout = this.machine.layouts.const_raw_ptr; - let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal"))); - let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); - Self::alloc_extern_static(this, "signal", val)?; - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code.) - for name in &["bsd_signal"] { - let val = ImmTy::from_int(0, this.machine.layouts.usize); - Self::alloc_extern_static(this, name, val)?; - } - } - "windows" => { - // "_tls_used" - // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let val = ImmTy::from_int(0, this.machine.layouts.u8); - Self::alloc_extern_static(this, "_tls_used", val)?; - } - _ => {} // No "extern statics" supported on this target - } - Ok(()) - } - pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } @@ -1009,7 +942,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind) + // For foreign items, try to see if we can emulate them. + if ecx.tcx.is_foreign_item(instance.def_id()) { + // An external function call that does not have a MIR body. We either find MIR elsewhere + // or emulate its effect. + // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need + // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the + // foreign function + // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. + let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? + let link_name = ecx.item_link_name(instance.def_id()); + return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); + } + + // Otherwise, load the MIR. + Ok(Some((ecx.load_mir(instance.def, None)?, instance))) } #[inline(always)] diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 14076444696..6f19dead2e9 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { - assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` + assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for` let size = this.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs new file mode 100644 index 00000000000..0284e5b606c --- /dev/null +++ b/src/tools/miri/src/shims/extern_static.rs @@ -0,0 +1,79 @@ +//! Provides the `extern static` that this platform expects. + +use crate::*; + +impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { + fn alloc_extern_static( + this: &mut MiriInterpCx<'mir, 'tcx>, + name: &str, + val: ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; + this.write_immediate(*val, &place)?; + Self::add_extern_static(this, name, place.ptr()); + Ok(()) + } + + /// Zero-initialized pointer-sized extern statics are pretty common. + /// Most of them are for weak symbols, which we all set to null (indicating that the + /// symbol is not supported, and triggering fallback code which ends up calling a + /// syscall that we do support). + fn null_ptr_extern_statics( + this: &mut MiriInterpCx<'mir, 'tcx>, + names: &[&str], + ) -> InterpResult<'tcx> { + for name in names { + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; + } + Ok(()) + } + + /// Sets up the "extern statics" for this machine. + pub fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { + // "__rust_no_alloc_shim_is_unstable" + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?; + + match this.tcx.sess.target.os.as_ref() { + "linux" => { + Self::null_ptr_extern_statics( + this, + &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"], + )?; + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.as_ref().unwrap().ptr(), + ); + } + "freebsd" => { + Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?; + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.as_ref().unwrap().ptr(), + ); + } + "android" => { + Self::null_ptr_extern_statics(this, &["bsd_signal"])?; + // "signal" -- just needs a non-zero pointer value (function does not even get called), + // but we arrange for this to call the `signal` function anyway. + let layout = this.machine.layouts.const_raw_ptr; + let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal"))); + let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); + Self::alloc_extern_static(this, "signal", val)?; + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "_tls_used", val)?; + } + _ => {} // No "extern statics" supported on this target + } + Ok(()) + } +} diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index 8edc0a4220d..e34fb118f72 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -148,7 +148,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // ``` // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). "is_val_statically_known" => { - let [_] = check_arg_count(args)?; + let [arg] = check_arg_count(args)?; + this.validate_operand(arg)?; let branch: bool = this.machine.rng.get_mut().gen(); this.write_scalar(Scalar::from_bool(branch), dest)?; } diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 1e9d927e1a9..ea6120f7579 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -10,48 +10,8 @@ pub mod windows; mod x86; pub mod env; +pub mod extern_static; pub mod os_str; pub mod panic; pub mod time; pub mod tls; - -// End module management, begin local code - -use log::trace; - -use rustc_middle::{mir, ty}; -use rustc_target::spec::abi::Abi; - -use crate::*; - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - fn find_mir_or_eval_fn( - &mut self, - instance: ty::Instance<'tcx>, - abi: Abi, - args: &[FnArg<'tcx, Provenance>], - dest: &PlaceTy<'tcx, Provenance>, - ret: Option<mir::BasicBlock>, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest); - - // For foreign items, try to see if we can emulate them. - if this.tcx.is_foreign_item(instance.def_id()) { - // An external function call that does not have a MIR body. We either find MIR elsewhere - // or emulate its effect. - // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need - // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the - // foreign function - // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit? - let link_name = this.item_link_name(instance.def_id()); - return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); - } - - // Otherwise, load the MIR. - Ok(Some((this.load_mir(instance.def, None)?, instance))) - } -} diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 23342c8045e..35036ce078d 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -155,6 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_i64()?; + let whence = this.read_scalar(whence)?.to_i32()?; + let result = this.lseek64(fd, offset.into(), whence)?; + this.write_scalar(result, dest)?; + } + "lseek" => { + let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let whence = this.read_scalar(whence)?.to_i32()?; let result = this.lseek64(fd, offset, whence)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 7c843e106ea..64094ac307d 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateForeignItemResult; +use shims::unix::fs::EvalContextExt as _; use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { @@ -63,6 +64,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_target_usize(len, this), dest)?; } + // File related shims + // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases + // since freebsd 12 the former form can be expected. + "stat" | "stat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_stat(path, buf)?; + this.write_scalar(result, dest)?; + } + "lstat" | "lstat@FBSD_1.0" => { + let [path, buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_lstat(path, buf)?; + this.write_scalar(result, dest)?; + } + "fstat" | "fstat@FBSD_1.0" => { + let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_fstat(fd, buf)?; + this.write_scalar(result, dest)?; + } + "readdir_r" | "readdir_r@FBSD_1.0" => { + let [dirp, entry, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; + this.write_scalar(result, dest)?; + } + // errno "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 99d8a3a2c91..53f975baa89 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -813,24 +813,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn lseek64( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - offset_op: &OpTy<'tcx, Provenance>, - whence_op: &OpTy<'tcx, Provenance>, + fd: i32, + offset: i128, + whence: i32, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. - let fd = this.read_scalar(fd_op)?.to_i32()?; - let offset = this.read_scalar(offset_op)?.to_i64()?; - let whence = this.read_scalar(whence_op)?.to_i32()?; - let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { SeekFrom::Start(u64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_CUR") { - SeekFrom::Current(offset) + SeekFrom::Current(i64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_END") { - SeekFrom::End(offset) + SeekFrom::End(i64::try_from(offset).unwrap()) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -897,13 +893,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.try_unwrap_io_result(result) } - fn macos_stat( + fn macos_fbsd_stat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "stat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -926,13 +925,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // `lstat` is used to get symlink metadata. - fn macos_lstat( + fn macos_fbsd_lstat( &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "lstat"); + + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os); + } let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); @@ -953,14 +955,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } - fn macos_fstat( + fn macos_fbsd_fstat( &mut self, fd_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "fstat"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_fstat` should not be called on {}", this.tcx.sess.target.os); + } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1199,7 +1203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.os == "macos" { + let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { u32::from(this.read_scalar(mode_op)?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? @@ -1371,7 +1375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_maybe_pointer(entry, this)) } - fn macos_readdir_r( + fn macos_fbsd_readdir_r( &mut self, dirp_op: &OpTy<'tcx, Provenance>, entry_op: &OpTy<'tcx, Provenance>, @@ -1379,7 +1383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "readdir_r"); + if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { + panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os); + } let dirp = this.read_target_usize(dirp_op)?; @@ -1410,7 +1416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // } let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?; - let name_place = this.project_field(&entry_place, 5)?; + let name_place = this.project_field_named(&entry_place, "d_name")?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( @@ -1434,16 +1440,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields_named( - &[ - ("d_ino", ino.into()), - ("d_seekoff", 0), - ("d_reclen", 0), - ("d_namlen", file_name_len.into()), - ("d_type", file_type.into()), - ], - &entry_place, - )?; + // macOS offset field is d_seekoff + if this.projectable_has_field(&entry_place, "d_seekoff") { + this.write_int_fields_named( + &[ + ("d_ino", ino.into()), + ("d_seekoff", 0), + ("d_reclen", 0), + ("d_namlen", file_name_len.into()), + ("d_type", file_type.into()), + ], + &entry_place, + )?; + } else if this.projectable_has_field(&entry_place, "d_off") { + // freebsd 12 and onwards had added the d_off field + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_off", 0), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } else { + this.write_int_fields_named( + &[ + ("d_fileno", ino.into()), + ("d_reclen", 0), + ("d_type", file_type.into()), + ("d_namlen", file_name_len.into()), + ], + &entry_place, + )?; + } let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; 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 07e19cadd6e..ecc07e28a29 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -40,18 +40,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_stat(path, buf)?; + let result = this.macos_fbsd_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_lstat(path, buf)?; + let result = this.macos_fbsd_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_fstat(fd, buf)?; + let result = this.macos_fbsd_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { @@ -62,14 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "readdir_r" | "readdir_r$INODE64" => { let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.macos_readdir_r(dirp, entry, result)?; - this.write_scalar(result, dest)?; - } - "lseek" => { - let [fd, offset, whence] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - // macOS is 64bit-only, so this is lseek64 - let result = this.lseek64(fd, offset, whence)?; + let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs index adfece58661..5185db0b0e2 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: no libc on Windows -//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0` //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs b/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs new file mode 100644 index 00000000000..5af0d0e4bbd --- /dev/null +++ b/src/tools/miri/tests/pass/issues/issue-120337-irrefutable-let-ice.rs @@ -0,0 +1,16 @@ +// Validation stops the test before the ICE we used to hit +//@compile-flags: -Zmiri-disable-validation + +#![feature(never_type)] +#[derive(Copy, Clone)] +pub enum E { + A(!), +} +pub union U { + u: (), + e: E, +} + +fn main() { + let E::A(ref _a) = unsafe { &(&U { u: () }).e }; +} diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index aa25f82ae1d..bf1feb9a7eb 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -379,14 +379,14 @@ fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str { let mut error_message = ""; match mode { Mode::CStr => { - rustc_lexer::unescape::unescape_c_string(text, mode, &mut |_, res| { + rustc_lexer::unescape::unescape_mixed(text, mode, &mut |_, res| { if let Err(e) = res { error_message = error_to_diagnostic_message(e, mode); } }); } Mode::ByteStr | Mode::Str => { - rustc_lexer::unescape::unescape_literal(text, mode, &mut |_, res| { + rustc_lexer::unescape::unescape_unicode(text, mode, &mut |_, res| { if let Err(e) = res { error_message = error_to_diagnostic_message(e, mode); } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index b39006e2ff2..7cd1f1550b9 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -6,7 +6,7 @@ use std::{ }; use rustc_lexer::unescape::{ - unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode, + unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, }; use crate::{ @@ -193,7 +193,7 @@ pub trait IsString: AstToken { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - unescape_literal(text, Self::MODE, &mut |range, unescaped_char| { + unescape_unicode(text, Self::MODE, &mut |range, unescaped_char| { let text_range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); cb(text_range + offset, unescaped_char); @@ -226,7 +226,7 @@ impl ast::String { let mut buf = String::new(); let mut prev_end = 0; let mut has_error = false; - unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match ( + unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { @@ -270,7 +270,7 @@ impl ast::ByteString { let mut buf: Vec<u8> = Vec::new(); let mut prev_end = 0; let mut has_error = false; - unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match ( + unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { @@ -311,7 +311,7 @@ impl IsString for ast::CString { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| { + unescape_mixed(text, Self::MODE, &mut |range, unescaped_char| { let text_range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); // XXX: This method should only be used for highlighting ranges. The unescaped @@ -336,12 +336,11 @@ impl ast::CString { let mut buf = Vec::new(); let mut prev_end = 0; let mut has_error = false; - let mut char_buf = [0u8; 4]; - let mut extend_unit = |buf: &mut Vec<u8>, unit: CStrUnit| match unit { - CStrUnit::Byte(b) => buf.push(b), - CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()), + let extend_unit = |buf: &mut Vec<u8>, unit: MixedUnit| match unit { + MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()), + MixedUnit::HighByte(b) => buf.push(b), }; - unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match ( + unescape_mixed(text, Self::MODE, &mut |char_range, unescaped| match ( unescaped, buf.capacity() == 0, ) { diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 69dffbf79f1..5c5b26f525f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -5,7 +5,7 @@ mod block; use rowan::Direction; -use rustc_lexer::unescape::{self, unescape_literal, Mode}; +use rustc_lexer::unescape::{self, unescape_mixed, unescape_unicode, Mode}; use crate::{ algo, @@ -140,7 +140,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::String(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 1, '"') { - unescape_literal(without_quotes, Mode::Str, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Str, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -151,7 +151,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::ByteString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { + unescape_unicode(without_quotes, Mode::ByteStr, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -162,7 +162,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::CString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { + unescape_mixed(without_quotes, Mode::CStr, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -172,7 +172,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { } ast::LiteralKind::Char(_) => { if let Some(without_quotes) = unquote(text, 1, '\'') { - unescape_literal(without_quotes, Mode::Char, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Char, &mut |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -181,7 +181,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { } ast::LiteralKind::Byte(_) => { if let Some(without_quotes) = unquote(text, 2, '\'') { - unescape_literal(without_quotes, Mode::Byte, &mut |range, char| { + unescape_unicode(without_quotes, Mode::Byte, &mut |range, char| { if let Err(err) = char { push_err(2, range.start, err); } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b03811e5efd..b06c072a2b0 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -340,8 +340,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "termize", "thin-vec", "thiserror", - "thiserror-core", - "thiserror-core-impl", "thiserror-impl", "thorin-dwp", "thread_local", diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 094efa981d3..6fc65e56901 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -2,7 +2,7 @@ //! //! Overview of check: //! -//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/error_codes.rs`. +//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/lib.rs`. //! //! 2. We check that the error code has a long-form explanation in `compiler/rustc_error_codes/src/error_codes/`. //! - The explanation is expected to contain a `doctest` that fails with the correct error code. (`EXEMPT_FROM_DOCTEST` *currently* bypasses this check) @@ -22,7 +22,7 @@ use regex::Regex; use crate::walk::{filter_dirs, walk, walk_many}; -const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/error_codes.rs"; +const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/lib.rs"; const ERROR_DOCS_PATH: &str = "compiler/rustc_error_codes/src/error_codes/"; const ERROR_TESTS_PATH: &str = "tests/ui/error-codes/"; @@ -80,13 +80,14 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String if line.starts_with('E') { let split_line = line.split_once(':'); - // Extract the error code from the line, emitting a fatal error if it is not in a correct format. + // Extract the error code from the line. Emit a fatal error if it is not in the correct + // format. let err_code = if let Some(err_code) = split_line { err_code.0.to_owned() } else { errors.push(format!( - "Expected a line with the format `Exxxx: include_str!(\"..\")`, but got \"{}\" \ - without a `:` delimiter", + "Expected a line with the format `Eabcd: abcd, \ + but got \"{}\" without a `:` delimiter", line, )); continue; @@ -98,12 +99,16 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String continue; } + let mut chars = err_code.chars(); + chars.next(); + let error_num_as_str = chars.as_str(); + // Ensure that the line references the correct markdown file. - let expected_filename = format!(" include_str!(\"./error_codes/{}.md\"),", err_code); + let expected_filename = format!(" {},", error_num_as_str); if expected_filename != split_line.unwrap().1 { errors.push(format!( - "Error code `{}` expected to reference docs with `{}` but instead found `{}` in \ - `compiler/rustc_error_codes/src/error_codes.rs`", + "`{}:` should be followed by `{}` but instead found `{}` in \ + `compiler/rustc_error_codes/src/lib.rs`", err_code, expected_filename, split_line.unwrap().1, @@ -311,13 +316,8 @@ fn check_error_codes_used( no_longer_emitted: &[String], verbose: bool, ) { - // We want error codes which match the following cases: - // - // * foo(a, E0111, a) - // * foo(a, E0111) - // * foo(E0111, a) - // * #[error = "E0111"] - let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap(); + // Search for error codes in the form `E0123`. + let regex = Regex::new(r#"\bE\d{4}\b"#).unwrap(); let mut found_codes = Vec::new(); @@ -336,12 +336,12 @@ fn check_error_codes_used( } for cap in regex.captures_iter(line) { - if let Some(error_code) = cap.get(1) { + if let Some(error_code) = cap.get(0) { let error_code = error_code.as_str().to_owned(); if !error_codes.contains(&error_code) { // This error code isn't properly defined, we must error. - errors.push(format!("Error code `{}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/error_codes.rs`.", error_code)); + errors.push(format!("Error code `{}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`.", error_code)); continue; } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 95cf9f8cb13..85553d2e338 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -24,9 +24,10 @@ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint - "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs - "tests/ui/commandline-argfile-badutf8.args", // passing args via a file - "tests/ui/commandline-argfile.args", // passing args via a file + "tests/ui/codegen/mismatched-data-layout.json", // testing mismatched data layout w/ custom targets + "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs + "tests/ui/commandline-argfile-badutf8.args", // passing args via a file + "tests/ui/commandline-argfile.args", // passing args via a file "tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib "tests/ui/include-macros/data.bin", // testing including data with the include macros "tests/ui/include-macros/file.txt", // testing including data with the include macros diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index f6f2f5e88ff..dee0fa9f4a4 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -1,29 +1,5 @@ // assembly-output: emit-asm // ignore-tidy-linelength -// revisions: aarch64_apple_darwin -// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin -// [aarch64_apple_darwin] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios -// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios -// [aarch64_apple_ios] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios_macabi -// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi -// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 -// revisions: aarch64_apple_ios_sim -// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim -// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 -// revisions: aarch64_apple_tvos -// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos -// [aarch64_apple_tvos] needs-llvm-components: aarch64 -// revisions: aarch64_apple_tvos_sim -// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim -// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 -// revisions: aarch64_apple_watchos -// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos -// [aarch64_apple_watchos] needs-llvm-components: aarch64 -// revisions: aarch64_apple_watchos_sim -// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim -// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 // revisions: aarch64_be_unknown_linux_gnu // [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu // [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 @@ -93,15 +69,6 @@ // revisions: aarch64_wrs_vxworks // [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks // [aarch64_wrs_vxworks] needs-llvm-components: aarch64 -// revisions: arm64_32_apple_watchos -// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos -// [arm64_32_apple_watchos] needs-llvm-components: aarch64 -// revisions: arm64e_apple_darwin -// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin -// [arm64e_apple_darwin] needs-llvm-components: aarch64 -// revisions: arm64e_apple_ios -// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios -// [arm64e_apple_ios] needs-llvm-components: aarch64 // revisions: arm_linux_androideabi // [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi // [arm_linux_androideabi] needs-llvm-components: arm @@ -201,18 +168,12 @@ // revisions: armv7a_none_eabihf // [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf // [armv7a_none_eabihf] needs-llvm-components: arm -// revisions: armv7k_apple_watchos -// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos -// [armv7k_apple_watchos] needs-llvm-components: arm // revisions: armv7r_none_eabi // [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi // [armv7r_none_eabi] needs-llvm-components: arm // revisions: armv7r_none_eabihf // [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf // [armv7r_none_eabihf] needs-llvm-components: arm -// revisions: armv7s_apple_ios -// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios -// [armv7s_apple_ios] needs-llvm-components: arm // FIXME: disabled since it fails on CI saying the csky component is missing /* revisions: csky_unknown_linux_gnuabiv2 @@ -228,9 +189,6 @@ // revisions: hexagon_unknown_none_elf // [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf // [hexagon_unknown_none_elf] needs-llvm-components: hexagon -// revisions: i386_apple_ios -// [i386_apple_ios] compile-flags: --target i386-apple-ios -// [i386_apple_ios] needs-llvm-components: x86 // revisions: i586_pc_nto_qnx700 // [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700 // [i586_pc_nto_qnx700] needs-llvm-components: x86 @@ -243,9 +201,6 @@ // revisions: i586_unknown_netbsd // [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd // [i586_unknown_netbsd] needs-llvm-components: x86 -// revisions: i686_apple_darwin -// [i686_apple_darwin] compile-flags: --target i686-apple-darwin -// [i686_apple_darwin] needs-llvm-components: x86 // revisions: i686_linux_android // [i686_linux_android] compile-flags: --target i686-linux-android // [i686_linux_android] needs-llvm-components: x86 @@ -537,21 +492,6 @@ // revisions: wasm32_wasi_preview2 // [wasm32_wasi_preview2] compile-flags: --target wasm32-wasi-preview2 // [wasm32_wasi_preview2] needs-llvm-components: webassembly -// revisions: x86_64_apple_darwin -// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin -// [x86_64_apple_darwin] needs-llvm-components: x86 -// revisions: x86_64_apple_ios -// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios -// [x86_64_apple_ios] needs-llvm-components: x86 -// revisions: x86_64_apple_ios_macabi -// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi -// [x86_64_apple_ios_macabi] needs-llvm-components: x86 -// revisions: x86_64_apple_tvos -// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos -// [x86_64_apple_tvos] needs-llvm-components: x86 -// revisions: x86_64_apple_watchos_sim -// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim -// [x86_64_apple_watchos_sim] needs-llvm-components: x86 // revisions: x86_64_fortanix_unknown_sgx // [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx // [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 @@ -618,9 +558,6 @@ // revisions: x86_64_wrs_vxworks // [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks // [x86_64_wrs_vxworks] needs-llvm-components: x86 -// revisions: x86_64h_apple_darwin -// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin -// [x86_64h_apple_darwin] needs-llvm-components: x86 // Sanity-check that each target can produce assembly code. @@ -636,4 +573,4 @@ pub fn test() -> u8 { 42 } -// CHECK: .section +// CHECK: .text diff --git a/tests/assembly/targets/targets-macho.rs b/tests/assembly/targets/targets-macho.rs new file mode 100644 index 00000000000..ead9ccfc8e7 --- /dev/null +++ b/tests/assembly/targets/targets-macho.rs @@ -0,0 +1,81 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_apple_darwin +// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +// [aarch64_apple_darwin] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios +// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +// [aarch64_apple_ios] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_macabi +// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi +// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_sim +// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos +// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos +// [aarch64_apple_tvos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos_sim +// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim +// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos +// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos +// [aarch64_apple_watchos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos_sim +// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim +// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 +// revisions: arm64_32_apple_watchos +// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos +// [arm64_32_apple_watchos] needs-llvm-components: aarch64 +// revisions: arm64e_apple_darwin +// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin +// [arm64e_apple_darwin] needs-llvm-components: aarch64 +// revisions: arm64e_apple_ios +// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios +// [arm64e_apple_ios] needs-llvm-components: aarch64 +// revisions: armv7k_apple_watchos +// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos +// [armv7k_apple_watchos] needs-llvm-components: arm +// revisions: armv7s_apple_ios +// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +// [armv7s_apple_ios] needs-llvm-components: arm +// revisions: i386_apple_ios +// [i386_apple_ios] compile-flags: --target i386-apple-ios +// [i386_apple_ios] needs-llvm-components: x86 +// revisions: i686_apple_darwin +// [i686_apple_darwin] compile-flags: --target i686-apple-darwin +// [i686_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_darwin +// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +// [x86_64_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_ios +// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +// [x86_64_apple_ios] needs-llvm-components: x86 +// revisions: x86_64_apple_ios_macabi +// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi +// [x86_64_apple_ios_macabi] needs-llvm-components: x86 +// revisions: x86_64_apple_tvos +// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos +// [x86_64_apple_tvos] needs-llvm-components: x86 +// revisions: x86_64_apple_watchos_sim +// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim +// [x86_64_apple_watchos_sim] needs-llvm-components: x86 +// revisions: x86_64h_apple_darwin +// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin +// [x86_64h_apple_darwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .section __TEXT,__text diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index d66e4c660f7..400e8801ca2 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -46,12 +46,12 @@ // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] // cdb-command: dx niche128_some -// cdb-check: niche128_some : Some [Type: enum2$<core::option::Option<core::num::nonzero::NonZeroI128> >] +// cdb-check: niche128_some : Some [Type: enum2$<core::option::Option<core::num::nonzero::NonZero<i128> > >] // Note: we can't actually read the value of the field because CDB cannot handle 128 bit integers. -// cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZeroI128] +// cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZero<i128>] // cdb-command: dx niche128_none -// cdb-check: niche128_none : None [Type: enum2$<core::option::Option<core::num::nonzero::NonZeroI128> >] +// cdb-check: niche128_none : None [Type: enum2$<core::option::Option<core::num::nonzero::NonZero<i128> > >] // cdb-command: dx wrapping_niche128_untagged // cdb-check: wrapping_niche128_untagged : X [Type: enum2$<msvc_pretty_enums::Wrapping128Niche>] @@ -84,7 +84,7 @@ // cdb-command: dx niche_w_fields_2_some,d // cdb-check: niche_w_fields_2_some,d : A [Type: enum2$<msvc_pretty_enums::NicheLayoutWithFields2>] -// cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] +// cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZero<u32>] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] // cdb-command: dx niche_w_fields_2_none,d diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index c122112e6c7..a1b5ae792a1 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -3,59 +3,59 @@ // min-gdb-version: 8.1 // ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows -// Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and +// Tests the visualizations for `NonZero<T>`, `Wrapping<T>` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. // === CDB TESTS ================================================================================== // cdb-command: g // cdb-command: dx nz_i8 -// cdb-check:nz_i8 : 11 [Type: core::num::nonzero::NonZeroI8] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroI8] +// cdb-check:nz_i8 : 11 [Type: core::num::nonzero::NonZero<i8>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<i8>] // cdb-command: dx nz_i16 -// cdb-check:nz_i16 : 22 [Type: core::num::nonzero::NonZeroI16] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroI16] +// cdb-check:nz_i16 : 22 [Type: core::num::nonzero::NonZero<i16>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<i16>] // cdb-command: dx nz_i32 -// cdb-check:nz_i32 : 33 [Type: core::num::nonzero::NonZeroI32] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroI32] +// cdb-check:nz_i32 : 33 [Type: core::num::nonzero::NonZero<i32>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<i32>] // cdb-command: dx nz_i64 -// cdb-check:nz_i64 : 44 [Type: core::num::nonzero::NonZeroI64] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroI64] +// cdb-check:nz_i64 : 44 [Type: core::num::nonzero::NonZero<i64>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<i64>] // 128-bit integers don't seem to work in CDB // cdb-command: dx nz_i128 -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroI128] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<i128>] // cdb-command: dx nz_isize -// cdb-check:nz_isize : 66 [Type: core::num::nonzero::NonZeroIsize] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroIsize] +// cdb-check:nz_isize : 66 [Type: core::num::nonzero::NonZero<isize>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<isize>] // cdb-command: dx nz_u8 -// cdb-check:nz_u8 : 0x4d [Type: core::num::nonzero::NonZeroU8] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroU8] +// cdb-check:nz_u8 : 0x4d [Type: core::num::nonzero::NonZero<u8>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u8>] // cdb-command: dx nz_u16 -// cdb-check:nz_u16 : 0x58 [Type: core::num::nonzero::NonZeroU16] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroU16] +// cdb-check:nz_u16 : 0x58 [Type: core::num::nonzero::NonZero<u16>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u16>] // cdb-command: dx nz_u32 -// cdb-check:nz_u32 : 0x63 [Type: core::num::nonzero::NonZeroU32] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroU32] +// cdb-check:nz_u32 : 0x63 [Type: core::num::nonzero::NonZero<u32>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u32>] // cdb-command: dx nz_u64 -// cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZeroU64] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroU64] +// cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZero<u64>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u64>] // 128-bit integers don't seem to work in CDB // cdb-command: dx nz_u128 -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroU128] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u128>] // cdb-command: dx nz_usize -// cdb-check:nz_usize : 0x7a [Type: core::num::nonzero::NonZeroUsize] -// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZeroUsize] +// cdb-check:nz_usize : 0x7a [Type: core::num::nonzero::NonZero<usize>] +// cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<usize>] // cdb-command: dx w_i8 // cdb-check:w_i8 : 10 [Type: core::num::wrapping::Wrapping<i8>] diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff new file mode 100644 index 00000000000..0b6819ad483 --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before GVN ++ // MIR for `f` after GVN + + fn f() -> u32 { + let mut _0: u32; + let _1: u32; + let mut _2: E; + let mut _3: &U; + let _4: U; + scope 1 { + debug i => _1; + } + scope 2 { + let mut _5: &U; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _5 = const _; + _3 = &(*_5); + _2 = ((*_3).1: E); + StorageLive(_1); +- _1 = ((_2 as A).1: u32); ++ _1 = const 0_u32; + StorageDead(_3); + StorageDead(_2); +- _0 = _1; ++ _0 = const 0_u32; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff new file mode 100644 index 00000000000..0b6819ad483 --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before GVN ++ // MIR for `f` after GVN + + fn f() -> u32 { + let mut _0: u32; + let _1: u32; + let mut _2: E; + let mut _3: &U; + let _4: U; + scope 1 { + debug i => _1; + } + scope 2 { + let mut _5: &U; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _5 = const _; + _3 = &(*_5); + _2 = ((*_3).1: E); + StorageLive(_1); +- _1 = ((_2 as A).1: u32); ++ _1 = const 0_u32; + StorageDead(_3); + StorageDead(_2); +- _0 = _1; ++ _0 = const 0_u32; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/gvn_uninhabited.rs b/tests/mir-opt/gvn_uninhabited.rs new file mode 100644 index 00000000000..a55b2dd763a --- /dev/null +++ b/tests/mir-opt/gvn_uninhabited.rs @@ -0,0 +1,24 @@ +// unit-test: GVN +// compile-flags: -O +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// skip-filecheck + +#![feature(never_type)] + +#[derive(Copy, Clone)] +pub enum E { + A(!, u32), +} + +pub union U { + i: u32, + e: E, +} + +// EMIT_MIR gvn_uninhabited.f.GVN.diff +pub const fn f() -> u32 { + let E::A(_, i) = unsafe { (&U { i: 0 }).e }; + i +} + +fn main() {} diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 8e53427e7e0..a38b8246bde 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index b06db41af9d..dc6628ab44c 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -36,7 +36,7 @@ - _4 = g() -> [return: bb1, unwind continue]; + _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _3 = &mut _4; -+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { pointer: _3 }; ++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = const false; diff --git a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff b/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff index cb623e83f52..be7f9cd4412 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff +++ b/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify.diff @@ -4,7 +4,7 @@ fn adt_transmutes() -> () { let mut _0: (); let _1: u8; - let mut _2: std::option::Option<std::num::NonZeroU8>; + let mut _2: std::option::Option<std::num::NonZero<u8>>; let mut _4: std::num::Wrapping<i16>; let mut _6: std::num::Wrapping<i16>; let mut _8: Union32; @@ -37,7 +37,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = Option::<NonZeroU8>::Some(const _); + _2 = Option::<NonZero<u8>>::Some(const _); _1 = move _2 as u8 (Transmute); StorageDead(_2); StorageLive(_3); diff --git a/tests/run-make/symbol-mangling-hashed/Makefile b/tests/run-make/symbol-mangling-hashed/Makefile new file mode 100644 index 00000000000..68894b2192a --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/Makefile @@ -0,0 +1,48 @@ +include ../tools.mk + +# ignore-cross-compile +# only-linux +# only-x86_64 + +NM=nm -D +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.so +SO_NAME=libb_dylib.so +BIN_NAME=b_bin + +ifeq ($(UNAME),Darwin) +NM=nm -gU +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.dylib +SO_NAME=libb_dylib.dylib +BIN_NAME=b_bin +endif + +ifdef IS_WINDOWS +NM=nm -g +RLIB_NAME=liba_rlib.dll.a +DYLIB_NAME=liba_dylib.dll +SO_NAME=libb_dylib.dll +BIN_NAME=b_bin.exe +endif + +all: + $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=foo a_dylib.rs + $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=bar a_rlib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_dylib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_bin.rs + + # Check hashed symbol name + + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep -c hello)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep _RNxC7a_dylib | grep -c ' T ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep b_dylib | grep -c hello)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC6a_rlib | grep -c ' T ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC6a_rlib | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep b_dylib | grep hello | grep -c ' U ')" -eq "1" ] + + $(call RUN,$(BIN_NAME)) diff --git a/tests/run-make/symbol-mangling-hashed/a_dylib.rs b/tests/run-make/symbol-mangling-hashed/a_dylib.rs new file mode 100644 index 00000000000..8aec8fd82a5 --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/a_dylib.rs @@ -0,0 +1,4 @@ +#![crate_type="dylib"] +pub fn hello() { + println!("hello dylib"); +} diff --git a/tests/run-make/symbol-mangling-hashed/a_rlib.rs b/tests/run-make/symbol-mangling-hashed/a_rlib.rs new file mode 100644 index 00000000000..873c86c5d0b --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/a_rlib.rs @@ -0,0 +1,5 @@ +#![crate_type="rlib"] + +pub fn hello() { + println!("hello rlib"); +} diff --git a/tests/run-make/symbol-mangling-hashed/b_bin.rs b/tests/run-make/symbol-mangling-hashed/b_bin.rs new file mode 100644 index 00000000000..bcc53c37e12 --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/b_bin.rs @@ -0,0 +1,9 @@ +extern crate a_rlib; +extern crate a_dylib; +extern crate b_dylib; + +fn main() { + a_rlib::hello(); + a_dylib::hello(); + b_dylib::hello(); +} diff --git a/tests/run-make/symbol-mangling-hashed/b_dylib.rs b/tests/run-make/symbol-mangling-hashed/b_dylib.rs new file mode 100644 index 00000000000..c26a04b39ec --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/b_dylib.rs @@ -0,0 +1,9 @@ +#![crate_type="dylib"] + +extern crate a_rlib; +extern crate a_dylib; + +pub fn hello() { + a_rlib::hello(); + a_dylib::hello(); +} diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile index 62d5365a73d..161b6602185 100644 --- a/tests/run-make/target-specs/Makefile +++ b/tests/run-make/target-specs/Makefile @@ -9,4 +9,4 @@ all: $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' - $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib + $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target' diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index f553aa96505..d3cfd28082d 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -25,22 +25,26 @@ extern crate rustc_middle; use rustc_middle::ty::Ty; extern crate rustc_errors; -use rustc_errors::{Applicability, DiagnosticMessage, MultiSpan, SubdiagnosticMessage}; +use rustc_errors::{Applicability, DiagnosticMessage, ErrCode, MultiSpan, SubdiagnosticMessage}; extern crate rustc_session; rustc_fluent_macro::fluent_messages! { "./example.ftl" } +// E0123 and E0456 are no longer used, so we define our own constants here just for this test. +const E0123: ErrCode = ErrCode::from_u32(0123); +const E0456: ErrCode = ErrCode::from_u32(0456); + #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct Hello {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct HelloWarn {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] //~^ ERROR unsupported type attribute for diagnostic derive enum enum DiagnosticOnEnum { Foo, @@ -50,53 +54,53 @@ enum DiagnosticOnEnum { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[diag = "E0123"] //~^ ERROR failed to resolve: maybe a missing crate `core` struct WrongStructAttrStyle {} #[derive(Diagnostic)] -#[nonsense(no_crate_example, code = "E0123")] +#[nonsense(no_crate_example, code = E0123)] //~^ ERROR `#[nonsense(...)]` is not a valid attribute //~^^ ERROR diagnostic slug not specified //~^^^ ERROR cannot find attribute `nonsense` in this scope struct InvalidStructAttr {} #[derive(Diagnostic)] -#[diag("E0123")] +#[diag(code = E0123)] //~^ ERROR diagnostic slug not specified struct InvalidLitNestedAttr {} #[derive(Diagnostic)] -#[diag(nonsense, code = "E0123")] +#[diag(nonsense, code = E0123)] //~^ ERROR cannot find value `nonsense` in module `crate::fluent_generated` struct InvalidNestedStructAttr {} #[derive(Diagnostic)] -#[diag(nonsense("foo"), code = "E0123", slug = "foo")] +#[diag(nonsense("foo"), code = E0123, slug = "foo")] //~^ ERROR diagnostic slug must be the first argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr1 {} #[derive(Diagnostic)] -#[diag(nonsense = "...", code = "E0123", slug = "foo")] +#[diag(nonsense = "...", code = E0123, slug = "foo")] //~^ ERROR unknown argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr2 {} #[derive(Diagnostic)] -#[diag(nonsense = 4, code = "E0123", slug = "foo")] +#[diag(nonsense = 4, code = E0123, slug = "foo")] //~^ ERROR unknown argument //~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr3 {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123", slug = "foo")] +#[diag(no_crate_example, code = E0123, slug = "foo")] //~^ ERROR unknown argument struct InvalidNestedStructAttr4 {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WrongPlaceField { #[suggestion = "bar"] //~^ ERROR `#[suggestion = ...]` is not a valid attribute @@ -104,19 +108,19 @@ struct WrongPlaceField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] -#[diag(no_crate_example, code = "E0456")] +#[diag(no_crate_example, code = E0123)] +#[diag(no_crate_example, code = E0456)] //~^ ERROR specified multiple times //~^^ ERROR specified multiple times struct DiagSpecifiedTwice {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0456", code = "E0457")] +#[diag(no_crate_example, code = E0123, code = E0456)] //~^ ERROR specified multiple times struct CodeSpecifiedTwice {} #[derive(Diagnostic)] -#[diag(no_crate_example, no_crate::example, code = "E0456")] +#[diag(no_crate_example, no_crate::example, code = E0123)] //~^ ERROR diagnostic slug must be the first argument struct SlugSpecifiedTwice {} @@ -124,7 +128,7 @@ struct SlugSpecifiedTwice {} struct KindNotProvided {} //~ ERROR diagnostic slug not specified #[derive(Diagnostic)] -#[diag(code = "E0456")] +#[diag(code = E0123)] //~^ ERROR diagnostic slug not specified struct SlugNotProvided {} @@ -133,7 +137,7 @@ struct SlugNotProvided {} struct CodeNotProvided {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MessageWrongType { #[primary_span] //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -141,7 +145,7 @@ struct MessageWrongType { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidPathFieldAttr { #[nonsense] //~^ ERROR `#[nonsense]` is not a valid attribute @@ -150,7 +154,7 @@ struct InvalidPathFieldAttr { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithField { name: String, #[label(no_crate_label)] @@ -158,7 +162,7 @@ struct ErrorWithField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithMessageAppliedToField { #[label(no_crate_label)] //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -166,7 +170,7 @@ struct ErrorWithMessageAppliedToField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNonexistentField { #[suggestion(no_crate_suggestion, code = "{name}")] //~^ ERROR `name` doesn't refer to a field on this type @@ -175,7 +179,7 @@ struct ErrorWithNonexistentField { #[derive(Diagnostic)] //~^ ERROR invalid format string: expected `'}'` -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorMissingClosingBrace { #[suggestion(no_crate_suggestion, code = "{name")] suggestion: (Span, Applicability), @@ -185,7 +189,7 @@ struct ErrorMissingClosingBrace { #[derive(Diagnostic)] //~^ ERROR invalid format string: unmatched `}` -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorMissingOpeningBrace { #[suggestion(no_crate_suggestion, code = "name}")] suggestion: (Span, Applicability), @@ -194,14 +198,14 @@ struct ErrorMissingOpeningBrace { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelOnSpan { #[label(no_crate_label)] sp: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelOnNonSpan { #[label(no_crate_label)] //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` @@ -209,7 +213,7 @@ struct LabelOnNonSpan { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct Suggest { #[suggestion(no_crate_suggestion, code = "This is the suggested code")] #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "normal")] @@ -220,7 +224,7 @@ struct Suggest { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithoutCode { #[suggestion(no_crate_suggestion)] //~^ ERROR suggestion without `code = "..."` @@ -228,7 +232,7 @@ struct SuggestWithoutCode { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithBadKey { #[suggestion(nonsense = "bar")] //~^ ERROR invalid nested attribute @@ -237,7 +241,7 @@ struct SuggestWithBadKey { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithShorthandMsg { #[suggestion(msg = "bar")] //~^ ERROR invalid nested attribute @@ -246,21 +250,21 @@ struct SuggestWithShorthandMsg { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithoutMsg { #[suggestion(code = "bar")] suggestion: (Span, Applicability), } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithTypesSwapped { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Applicability, Span), } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithWrongTypeApplicabilityOnly { #[suggestion(no_crate_suggestion, code = "This is suggested code")] //~^ ERROR wrong field type for suggestion @@ -268,14 +272,14 @@ struct SuggestWithWrongTypeApplicabilityOnly { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithSpanOnly { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithDuplicateSpanAndApplicability { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Span, Span, Applicability), @@ -283,7 +287,7 @@ struct SuggestWithDuplicateSpanAndApplicability { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct SuggestWithDuplicateApplicabilityAndSpan { #[suggestion(no_crate_suggestion, code = "This is suggested code")] suggestion: (Applicability, Applicability, Span), @@ -291,7 +295,7 @@ struct SuggestWithDuplicateApplicabilityAndSpan { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WrongKindOfAnnotation { #[label = "bar"] //~^ ERROR `#[label = ...]` is not a valid attribute @@ -299,7 +303,7 @@ struct WrongKindOfAnnotation { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct OptionsInErrors { #[label(no_crate_label)] label: Option<Span>, @@ -308,7 +312,7 @@ struct OptionsInErrors { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0456")] +#[diag(no_crate_example, code = E0123)] struct MoveOutOfBorrowError<'tcx> { name: Ident, ty: Ty<'tcx>, @@ -322,7 +326,7 @@ struct MoveOutOfBorrowError<'tcx> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithLifetime<'a> { #[label(no_crate_label)] span: Span, @@ -330,7 +334,7 @@ struct ErrorWithLifetime<'a> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithDefaultLabelAttr<'a> { #[label] span: Span, @@ -338,7 +342,7 @@ struct ErrorWithDefaultLabelAttr<'a> { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ArgFieldWithoutSkip { #[primary_span] span: Span, @@ -347,7 +351,7 @@ struct ArgFieldWithoutSkip { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ArgFieldWithSkip { #[primary_span] span: Span, @@ -358,56 +362,56 @@ struct ArgFieldWithSkip { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedNote { #[note] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedNoteCustom { #[note(no_crate_note)] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[note] struct ErrorWithNote { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[note(no_crate_note)] struct ErrorWithNoteCustom { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedHelp { #[help] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithSpannedHelpCustom { #[help(no_crate_help)] span: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[help] struct ErrorWithHelp { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[help(no_crate_help)] struct ErrorWithHelpCustom { val: String, @@ -415,34 +419,34 @@ struct ErrorWithHelpCustom { #[derive(Diagnostic)] #[help] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithHelpWrongOrder { val: String, } #[derive(Diagnostic)] #[help(no_crate_help)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithHelpCustomWrongOrder { val: String, } #[derive(Diagnostic)] #[note] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNoteWrongOrder { val: String, } #[derive(Diagnostic)] #[note(no_crate_note)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithNoteCustomWrongOrder { val: String, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ApplicabilityInBoth { #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] //~^ ERROR specified multiple times @@ -450,7 +454,7 @@ struct ApplicabilityInBoth { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidApplicability { #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] //~^ ERROR invalid applicability @@ -458,14 +462,14 @@ struct InvalidApplicability { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ValidApplicability { #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] suggestion: Span, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct NoApplicability { #[suggestion(no_crate_suggestion, code = "...")] suggestion: Span, @@ -483,7 +487,7 @@ struct Subdiagnostic { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct VecField { #[primary_span] #[label] @@ -491,7 +495,7 @@ struct VecField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct UnitField { #[primary_span] spans: Span, @@ -502,7 +506,7 @@ struct UnitField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct OptUnitField { #[primary_span] spans: Span, @@ -526,7 +530,7 @@ struct BoolField { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingPath { #[label(no_crate_label, foo)] //~^ ERROR a diagnostic slug must be the first argument to the attribute @@ -534,7 +538,7 @@ struct LabelWithTrailingPath { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingNameValue { #[label(no_crate_label, foo = "...")] //~^ ERROR only `no_span` is a valid nested attribute @@ -542,7 +546,7 @@ struct LabelWithTrailingNameValue { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct LabelWithTrailingList { #[label(no_crate_label, foo("..."))] //~^ ERROR only `no_span` is a valid nested attribute @@ -562,42 +566,42 @@ struct PrimarySpanOnLint { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct ErrorWithMultiSpan { #[primary_span] span: MultiSpan, } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[warning] struct ErrorWithWarn { val: String, } #[derive(Diagnostic)] -#[error(no_crate_example, code = "E0123")] +#[error(no_crate_example, code = E0123)] //~^ ERROR `#[error(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `error` in this scope struct ErrorAttribute {} #[derive(Diagnostic)] -#[warn_(no_crate_example, code = "E0123")] +#[warn_(no_crate_example, code = E0123)] //~^ ERROR `#[warn_(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `warn_` in this scope struct WarnAttribute {} #[derive(Diagnostic)] -#[lint(no_crate_example, code = "E0123")] +#[lint(no_crate_example, code = E0123)] //~^ ERROR `#[lint(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified //~| ERROR cannot find attribute `lint` in this scope struct LintAttributeOnSessionDiag {} #[derive(LintDiagnostic)] -#[lint(no_crate_example, code = "E0123")] +#[lint(no_crate_example, code = E0123)] //~^ ERROR `#[lint(...)]` is not a valid attribute //~| ERROR `#[lint(...)]` is not a valid attribute //~| ERROR diagnostic slug not specified @@ -605,7 +609,7 @@ struct LintAttributeOnSessionDiag {} struct LintAttributeOnLintDiag {} #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct DuplicatedSuggestionCode { #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] //~^ ERROR specified multiple times @@ -613,7 +617,7 @@ struct DuplicatedSuggestionCode { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct InvalidTypeInSuggestionTuple { #[suggestion(no_crate_suggestion, code = "...")] suggestion: (Span, usize), @@ -621,7 +625,7 @@ struct InvalidTypeInSuggestionTuple { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MissingApplicabilityInSuggestionTuple { #[suggestion(no_crate_suggestion, code = "...")] suggestion: (Span,), @@ -629,7 +633,7 @@ struct MissingApplicabilityInSuggestionTuple { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct MissingCodeInSuggestion { #[suggestion(no_crate_suggestion)] //~^ ERROR suggestion without `code = "..."` @@ -637,7 +641,7 @@ struct MissingCodeInSuggestion { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[multipart_suggestion(no_crate_suggestion)] //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute //~| ERROR cannot find attribute `multipart_suggestion` in this scope @@ -652,7 +656,7 @@ struct MultipartSuggestion { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[suggestion(no_crate_suggestion, code = "...")] //~^ ERROR `#[suggestion(...)]` is not a valid attribute struct SuggestionOnStruct { @@ -661,7 +665,7 @@ struct SuggestionOnStruct { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] #[label] //~^ ERROR `#[label]` is not a valid attribute struct LabelOnStruct { @@ -688,7 +692,7 @@ enum ExampleEnum { } #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct RawIdentDiagnosticArg { pub r#type: String, } @@ -762,7 +766,7 @@ struct SubdiagnosticEagerSuggestion { /// with a doc comment on the type.. #[derive(Diagnostic)] -#[diag(no_crate_example, code = "E0123")] +#[diag(no_crate_example, code = E0123)] struct WithDocComment { /// ..and the field #[primary_span] diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f376c034587..67257c28b6e 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,11 +1,11 @@ error: unsupported type attribute for diagnostic derive enum - --> $DIR/diagnostic-derive.rs:43:1 + --> $DIR/diagnostic-derive.rs:47:1 | -LL | #[diag(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[diag(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:46:5 + --> $DIR/diagnostic-derive.rs:50:5 | LL | Foo, | ^^^ @@ -13,7 +13,7 @@ LL | Foo, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:48:5 + --> $DIR/diagnostic-derive.rs:52:5 | LL | Bar, | ^^^ @@ -21,15 +21,15 @@ LL | Bar, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[nonsense(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:59:1 + --> $DIR/diagnostic-derive.rs:63:1 | -LL | #[nonsense(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[nonsense(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:59:1 + --> $DIR/diagnostic-derive.rs:63:1 | -LL | / #[nonsense(no_crate_example, code = "E0123")] +LL | / #[nonsense(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -39,9 +39,9 @@ LL | | struct InvalidStructAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:66:1 + --> $DIR/diagnostic-derive.rs:70:1 | -LL | / #[diag("E0123")] +LL | / #[diag(code = E0123)] LL | | LL | | struct InvalidLitNestedAttr {} | |______________________________^ @@ -49,15 +49,15 @@ LL | | struct InvalidLitNestedAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:76:16 + --> $DIR/diagnostic-derive.rs:80:16 | -LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")] +LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:76:1 + --> $DIR/diagnostic-derive.rs:80:1 | -LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")] +LL | / #[diag(nonsense("foo"), code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr1 {} @@ -66,17 +66,17 @@ LL | | struct InvalidNestedStructAttr1 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:82:8 + --> $DIR/diagnostic-derive.rs:86:8 | -LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] +LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | ^^^^^^^^ | = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:82:1 + --> $DIR/diagnostic-derive.rs:86:1 | -LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")] +LL | / #[diag(nonsense = "...", code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr2 {} @@ -85,17 +85,17 @@ LL | | struct InvalidNestedStructAttr2 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:88:8 + --> $DIR/diagnostic-derive.rs:92:8 | -LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] +LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | ^^^^^^^^ | = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:88:1 + --> $DIR/diagnostic-derive.rs:92:1 | -LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")] +LL | / #[diag(nonsense = 4, code = E0123, slug = "foo")] LL | | LL | | LL | | struct InvalidNestedStructAttr3 {} @@ -104,63 +104,63 @@ LL | | struct InvalidNestedStructAttr3 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:94:42 + --> $DIR/diagnostic-derive.rs:98:40 | -LL | #[diag(no_crate_example, code = "E0123", slug = "foo")] - | ^^^^ +LL | #[diag(no_crate_example, code = E0123, slug = "foo")] + | ^^^^ | = note: only the `code` parameter is valid after the slug error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:101:5 + --> $DIR/diagnostic-derive.rs:105:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:108:8 + --> $DIR/diagnostic-derive.rs:112:8 | -LL | #[diag(no_crate_example, code = "E0456")] +LL | #[diag(no_crate_example, code = E0456)] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:107:8 + --> $DIR/diagnostic-derive.rs:111:8 | -LL | #[diag(no_crate_example, code = "E0123")] +LL | #[diag(no_crate_example, code = E0123)] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:108:26 + --> $DIR/diagnostic-derive.rs:112:26 | -LL | #[diag(no_crate_example, code = "E0456")] +LL | #[diag(no_crate_example, code = E0456)] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:107:26 + --> $DIR/diagnostic-derive.rs:111:26 | -LL | #[diag(no_crate_example, code = "E0123")] +LL | #[diag(no_crate_example, code = E0123)] | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:114:42 + --> $DIR/diagnostic-derive.rs:118:40 | -LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] - | ^^^^ +LL | #[diag(no_crate_example, code = E0123, code = E0456)] + | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:114:26 + --> $DIR/diagnostic-derive.rs:118:26 | -LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] +LL | #[diag(no_crate_example, code = E0123, code = E0456)] | ^^^^ error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:119:43 + --> $DIR/diagnostic-derive.rs:123:43 | -LL | #[diag(no_crate_example, no_crate::example, code = "E0456")] +LL | #[diag(no_crate_example, no_crate::example, code = E0123)] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:124:1 + --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,9 +168,9 @@ LL | struct KindNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:127:1 + --> $DIR/diagnostic-derive.rs:131:1 | -LL | / #[diag(code = "E0456")] +LL | / #[diag(code = E0123)] LL | | LL | | struct SlugNotProvided {} | |_________________________^ @@ -178,31 +178,31 @@ LL | | struct SlugNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:138:5 + --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:146:5 + --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^^^^^^^^^^^ error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:163:5 + --> $DIR/diagnostic-derive.rs:167:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:171:46 + --> $DIR/diagnostic-derive.rs:175:46 | LL | #[suggestion(no_crate_suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:176:10 + --> $DIR/diagnostic-derive.rs:180:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ expected `'}'` in format string @@ -211,7 +211,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:186:10 + --> $DIR/diagnostic-derive.rs:190:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ unmatched `}` in format string @@ -220,19 +220,19 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:206:5 + --> $DIR/diagnostic-derive.rs:210:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:225:5 + --> $DIR/diagnostic-derive.rs:229:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:233:18 + --> $DIR/diagnostic-derive.rs:237:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^ @@ -240,13 +240,13 @@ LL | #[suggestion(nonsense = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:233:5 + --> $DIR/diagnostic-derive.rs:237:5 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:242:18 + --> $DIR/diagnostic-derive.rs:246:18 | LL | #[suggestion(msg = "bar")] | ^^^ @@ -254,13 +254,13 @@ LL | #[suggestion(msg = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:242:5 + --> $DIR/diagnostic-derive.rs:246:5 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:265:5 + --> $DIR/diagnostic-derive.rs:269:5 | LL | / #[suggestion(no_crate_suggestion, code = "This is suggested code")] LL | | @@ -270,79 +270,79 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: specified multiple times - --> $DIR/diagnostic-derive.rs:281:24 + --> $DIR/diagnostic-derive.rs:285:24 | LL | suggestion: (Span, Span, Applicability), | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:281:18 + --> $DIR/diagnostic-derive.rs:285:18 | LL | suggestion: (Span, Span, Applicability), | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:289:33 + --> $DIR/diagnostic-derive.rs:293:33 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:289:18 + --> $DIR/diagnostic-derive.rs:293:18 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ error: `#[label = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:296:5 + --> $DIR/diagnostic-derive.rs:300:5 | LL | #[label = "bar"] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:447:5 + --> $DIR/diagnostic-derive.rs:451:5 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:449:24 + --> $DIR/diagnostic-derive.rs:453:24 | LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:455:69 + --> $DIR/diagnostic-derive.rs:459:69 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` - --> $DIR/diagnostic-derive.rs:522:5 + --> $DIR/diagnostic-derive.rs:526:5 | LL | #[help(no_crate_help)] | ^^^^^^^^^^^^^^^^^^^^^^ error: a diagnostic slug must be the first argument to the attribute - --> $DIR/diagnostic-derive.rs:531:32 + --> $DIR/diagnostic-derive.rs:535:32 | LL | #[label(no_crate_label, foo)] | ^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:539:29 + --> $DIR/diagnostic-derive.rs:543:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:547:29 + --> $DIR/diagnostic-derive.rs:551:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:559:5 + --> $DIR/diagnostic-derive.rs:563:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -350,15 +350,15 @@ LL | #[primary_span] = help: the `primary_span` field attribute is not valid for lint diagnostics error: `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:583:1 | -LL | #[error(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:583:1 | -LL | / #[error(no_crate_example, code = "E0123")] +LL | / #[error(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -368,15 +368,15 @@ LL | | struct ErrorAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:586:1 + --> $DIR/diagnostic-derive.rs:590:1 | -LL | #[warn_(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn_(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:586:1 + --> $DIR/diagnostic-derive.rs:590:1 | -LL | / #[warn_(no_crate_example, code = "E0123")] +LL | / #[warn_(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -386,15 +386,15 @@ LL | | struct WarnAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:593:1 + --> $DIR/diagnostic-derive.rs:597:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:593:1 + --> $DIR/diagnostic-derive.rs:597:1 | -LL | / #[lint(no_crate_example, code = "E0123")] +LL | / #[lint(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -404,23 +404,23 @@ LL | | struct LintAttributeOnSessionDiag {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | #[lint(no_crate_example, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[lint(no_crate_example, code = E0123)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:600:1 + --> $DIR/diagnostic-derive.rs:604:1 | -LL | / #[lint(no_crate_example, code = "E0123")] +LL | / #[lint(no_crate_example, code = E0123)] LL | | LL | | LL | | @@ -431,19 +431,19 @@ LL | | struct LintAttributeOnLintDiag {} = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` error: specified multiple times - --> $DIR/diagnostic-derive.rs:610:53 + --> $DIR/diagnostic-derive.rs:614:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:610:39 + --> $DIR/diagnostic-derive.rs:614:39 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:619:24 + --> $DIR/diagnostic-derive.rs:623:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -451,7 +451,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:627:17 + --> $DIR/diagnostic-derive.rs:631:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -459,13 +459,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:634:5 + --> $DIR/diagnostic-derive.rs:638:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:641:1 + --> $DIR/diagnostic-derive.rs:645:1 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -473,7 +473,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:644:1 + --> $DIR/diagnostic-derive.rs:648:1 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:648:5 + --> $DIR/diagnostic-derive.rs:652:5 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:656:1 + --> $DIR/diagnostic-derive.rs:660:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:665:1 + --> $DIR/diagnostic-derive.rs:669:1 | LL | #[label] | ^^^^^^^^ @@ -505,31 +505,31 @@ LL | #[label] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:699:7 + --> $DIR/diagnostic-derive.rs:703:7 | LL | #[subdiagnostic(bad)] | ^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:707:5 + --> $DIR/diagnostic-derive.rs:711:5 | LL | #[subdiagnostic = "bad"] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:715:7 + --> $DIR/diagnostic-derive.rs:719:7 | LL | #[subdiagnostic(bad, bad)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:723:7 + --> $DIR/diagnostic-derive.rs:727:7 | LL | #[subdiagnostic("bad")] | ^^^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:731:5 + --> $DIR/diagnostic-derive.rs:735:5 | LL | #[subdiagnostic(eager)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -537,19 +537,19 @@ LL | #[subdiagnostic(eager)] = help: eager subdiagnostics are not supported on lints error: expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive.rs:789:23 + --> $DIR/diagnostic-derive.rs:793:23 | LL | #[suggestion(code())] | ^ error: `code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:797:23 + --> $DIR/diagnostic-derive.rs:801:23 | LL | #[suggestion(code(foo))] | ^^^ error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:821:5 + --> $DIR/diagnostic-derive.rs:825:5 | LL | #[suggestion(no_crate_suggestion, code = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -559,85 +559,85 @@ LL | #[suggestion(no_crate_suggestion, code = "")] = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:54:8 + --> $DIR/diagnostic-derive.rs:58:8 | LL | #[diag = "E0123"] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:797:23 + --> $DIR/diagnostic-derive.rs:801:23 | LL | #[suggestion(code(foo))] | ^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:806:25 + --> $DIR/diagnostic-derive.rs:810:25 | LL | #[suggestion(code = 3)] | ^ maybe a missing crate `core`? error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:59:3 + --> $DIR/diagnostic-derive.rs:63:3 | -LL | #[nonsense(no_crate_example, code = "E0123")] +LL | #[nonsense(no_crate_example, code = E0123)] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:146:7 + --> $DIR/diagnostic-derive.rs:150:7 | LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive.rs:579:3 + --> $DIR/diagnostic-derive.rs:583:3 | -LL | #[error(no_crate_example, code = "E0123")] +LL | #[error(no_crate_example, code = E0123)] | ^^^^^ error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive.rs:586:3 + --> $DIR/diagnostic-derive.rs:590:3 | -LL | #[warn_(no_crate_example, code = "E0123")] +LL | #[warn_(no_crate_example, code = E0123)] | ^^^^^ help: a built-in attribute with a similar name exists: `warn` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:593:3 + --> $DIR/diagnostic-derive.rs:597:3 | -LL | #[lint(no_crate_example, code = "E0123")] +LL | #[lint(no_crate_example, code = E0123)] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:600:3 + --> $DIR/diagnostic-derive.rs:604:3 | -LL | #[lint(no_crate_example, code = "E0123")] +LL | #[lint(no_crate_example, code = E0123)] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:641:3 + --> $DIR/diagnostic-derive.rs:645:3 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:644:3 + --> $DIR/diagnostic-derive.rs:648:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:648:7 + --> $DIR/diagnostic-derive.rs:652:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` - --> $DIR/diagnostic-derive.rs:71:8 + --> $DIR/diagnostic-derive.rs:75:8 | -LL | #[diag(nonsense, code = "E0123")] +LL | #[diag(nonsense, code = E0123)] | ^^^^^^^^ not found in `crate::fluent_generated` error[E0425]: cannot find value `__code_34` in this scope - --> $DIR/diagnostic-derive.rs:803:10 + --> $DIR/diagnostic-derive.rs:807:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ not found in this scope @@ -645,7 +645,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:345:12 + --> $DIR/diagnostic-derive.rs:349:12 | LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs index a0a8114e0c5..785da11b9b2 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs @@ -19,6 +19,6 @@ use rustc_errors::{Applicability, MultiSpan}; extern crate rustc_session; #[derive(Diagnostic)] -#[diag(compiletest_example, code = "E0123")] +#[diag(compiletest_example, code = 0123)] //~^ ERROR diagnostic slug and crate name do not match struct Hello {} diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index 4cdc24e6a6b..eda24a555f8 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,7 +1,7 @@ error: diagnostic slug and crate name do not match --> $DIR/enforce_slug_naming.rs:22:8 | -LL | #[diag(compiletest_example, code = "E0123")] +LL | #[diag(compiletest_example, code = 0123)] | ^^^^^^^^^^^^^^^^^^^ | = note: slug is `compiletest_example` but the crate name is `rustc_dummy` diff --git a/tests/ui/async-await/async-closures/higher-ranked.rs b/tests/ui/async-await/async-closures/higher-ranked.rs new file mode 100644 index 00000000000..f0bdcf691ae --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked.rs @@ -0,0 +1,12 @@ +// edition:2021 + +#![feature(async_closure)] + +fn main() { + let x = async move |x: &str| { + //~^ ERROR lifetime may not live long enough + // This error is proof that the `&str` type is higher-ranked. + // This won't work until async closures are fully impl'd. + println!("{x}"); + }; +} diff --git a/tests/ui/async-await/async-closures/higher-ranked.stderr b/tests/ui/async-await/async-closures/higher-ranked.stderr new file mode 100644 index 00000000000..fb02a15b079 --- /dev/null +++ b/tests/ui/async-await/async-closures/higher-ranked.stderr @@ -0,0 +1,17 @@ +error: lifetime may not live long enough + --> $DIR/higher-ranked.rs:6:34 + | +LL | let x = async move |x: &str| { + | ____________________________-___-_^ + | | | | + | | | return type of closure `{async closure body@$DIR/higher-ranked.rs:6:34: 11:6}` contains a lifetime `'2` + | | let's call the lifetime of this reference `'1` +LL | | +LL | | // This error is proof that the `&str` type is higher-ranked. +LL | | // This won't work until async closures are fully impl'd. +LL | | println!("{x}"); +LL | | }; + | |_____^ returning this value requires that `'1` must outlive `'2` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs b/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs new file mode 100644 index 00000000000..72f02679d77 --- /dev/null +++ b/tests/ui/async-await/in-trait/returning-possibly-unsized-self.rs @@ -0,0 +1,18 @@ +// check-pass +// edition:2021 + +#![deny(opaque_hidden_inferred_bound)] + +trait Repository /* : ?Sized */ { + async fn new() -> Self; +} + +struct MyRepository {} + +impl Repository for MyRepository { + async fn new() -> Self { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json new file mode 100644 index 00000000000..4cb0602dc75 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layout.json @@ -0,0 +1,13 @@ +{ + "llvm-target": "x86_64-unknown-none-gnu", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "unknown", + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "executables": true +} + diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs new file mode 100644 index 00000000000..047ec155fdc --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.rs @@ -0,0 +1,14 @@ +// This test checks that data layout mismatches emit an error. +// +// build-fail +// needs-llvm-components: x86 +// compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options +// error-pattern: differs from LLVM target's +// normalize-stderr-test: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`" +// normalize-stderr-test: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`" + +#![feature(lang_items, no_core, auto_traits)] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/ui/codegen/mismatched-data-layouts.stderr b/tests/ui/codegen/mismatched-data-layouts.stderr new file mode 100644 index 00000000000..1fe242266df --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.stderr @@ -0,0 +1,4 @@ +error: data-layout for target `mismatched-data-layout-7814813422914914169`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout` + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs new file mode 100644 index 00000000000..7da6b7ca285 --- /dev/null +++ b/tests/ui/consts/let-irrefutable-pattern-ice-120337.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(never_type)] +#[derive(Copy, Clone)] +pub enum E { A(!), } +pub union U { u: (), e: E, } +pub const C: () = { + let E::A(ref a) = unsafe { &(&U { u: () }).e}; +}; + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs index 134ea25b75a..594a2672d43 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -7,7 +7,7 @@ use core::{marker::PhantomPinned, pin::Pin}; /// The `unsafe_pin_internals` is indeed unsound. fn non_unsafe_pin_new_unchecked<T>(pointer: &mut T) -> Pin<&mut T> { - Pin { pointer } + Pin { __pointer: pointer } } fn main() { diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index 28dbdf4c374..3d753b9c8b8 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -34,15 +34,11 @@ error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIte LL | for item in *things { *item = 0 } | ^^^^^^^ -error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time - --> $DIR/issue-20605.rs:5:9 +error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed + --> $DIR/issue-20605.rs:5:17 | LL | for item in *things { *item = 0 } - | ^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` - = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature + | ^^^^^^^ error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time --> $DIR/issue-20605.rs:5:5 @@ -54,11 +50,15 @@ LL | for item in *things { *item = 0 } note: required by a bound in `None` --> $SRC_DIR/core/src/option.rs:LL:COL -error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed - --> $DIR/issue-20605.rs:5:17 +error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time + --> $DIR/issue-20605.rs:5:9 | LL | for item in *things { *item = 0 } - | ^^^^^^^ + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced --> $DIR/issue-20605.rs:5:27 diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs index 55353999b67..0c050c550c4 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs @@ -17,12 +17,18 @@ fn main() { } match x as i32 { 0..5+1 => errors_only.push(x), - //~^ error: expected one of `=>`, `if`, or `|`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: exclusive range pattern syntax is experimental 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: exclusive range pattern syntax is experimental + //~| error: inline-const in pattern position is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index cf3bde9705b..cc481f7a79e 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `if`, or `|`, found `+` - --> $DIR/range_pat_interactions1.rs:19:17 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions1.rs:19:16 | LL | 0..5+1 => errors_only.push(x), - | ^ expected one of `=>`, `if`, or `|` + | ^^^ arbitrary expressions are not allowed in patterns error[E0408]: variable `n` is not bound in all patterns --> $DIR/range_pat_interactions1.rs:10:25 @@ -12,6 +12,16 @@ LL | if let n @ 2..3|4 = x { | | | variable not in all patterns +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions1.rs:26:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information + = help: add `#![feature(inline_const_pat)]` 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]: exclusive range pattern syntax is experimental --> $DIR/range_pat_interactions1.rs:10:20 | @@ -34,7 +44,62 @@ LL | } else if let 2..3 | 4 = x { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: use an inclusive range pattern, like N..=M -error: aborting due to 4 previous errors +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:19:13 + | +LL | 0..5+1 => errors_only.push(x), + | ^^^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:22:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:24:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:26:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions1.rs:30:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 10 previous errors Some errors have detailed explanations: E0408, E0658. For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs index 0e96cfe7858..068104c4b1b 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs @@ -8,12 +8,18 @@ fn main() { for x in -9 + 1..=(9 - 2) { match x as i32 { 0..=(5+1) => errors_only.push(x), - //~^ error: expected `)`, found `+` + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses 1 | -3..0 => first_or.push(x), + //~^ error: exclusive range pattern syntax is experimental y @ (0..5 | 6) => or_two.push(y), + //~^ error: exclusive range pattern syntax is experimental y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + //~^ error: inline-const in pattern position is experimental + //~| error: exclusive range pattern syntax is experimental y @ -5.. => range_from.push(y), y @ ..-7 => assert_eq!(y, -8), + //~^ error: exclusive range pattern syntax is experimental y => bottom.push(y), } } diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index a54f29a3b32..8f21a6149fb 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -1,8 +1,75 @@ -error: expected `)`, found `+` - --> $DIR/range_pat_interactions2.rs:10:19 +error: expected a pattern range bound, found an expression + --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^ expected `)` + | ^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: range pattern bounds cannot have parentheses + --> $DIR/range_pat_interactions2.rs:10:17 + | +LL | 0..=(5+1) => errors_only.push(x), + | ^ ^ + | +help: remove these parentheses + | +LL - 0..=(5+1) => errors_only.push(x), +LL + 0..=5+1 => errors_only.push(x), + | + +error[E0658]: inline-const in pattern position is experimental + --> $DIR/range_pat_interactions2.rs:17:20 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^ + | + = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information + = help: add `#![feature(inline_const_pat)]` 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]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:13:17 + | +LL | 1 | -3..0 => first_or.push(x), + | ^^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:15:18 + | +LL | y @ (0..5 | 6) => or_two.push(y), + | ^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:17:17 + | +LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5), + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error[E0658]: exclusive range pattern syntax is experimental + --> $DIR/range_pat_interactions2.rs:21:17 + | +LL | y @ ..-7 => assert_eq!(y, -8), + | ^^^^ + | + = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information + = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: use an inclusive range pattern, like N..=M + +error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index 1eb27fbdc3a..a4445fefef5 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -28,6 +28,14 @@ macro_rules! bar { }} } +#[allow_internal_unstable(stmt_expr_attributes)] +macro_rules! internal_attr { + ($e: expr) => { + #[allow(overflowing_literals)] + $e + } +} + fn main() { // ok, the instability is contained. call_unstable_allow!(); @@ -51,4 +59,6 @@ fn main() { #[allow_internal_unstable] _ => {} } + + assert_eq!(internal_attr!(1e100_f32), f32::INFINITY); } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index af5ac21e696..78b9109d1c2 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:40:25 + --> $DIR/internal-unstable.rs:48:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:42:27 + --> $DIR/internal-unstable.rs:50:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:46:22 + --> $DIR/internal-unstable.rs:54:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:48:10 + --> $DIR/internal-unstable.rs:56:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 8161f97dde0..0ed743818c5 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -232,7 +232,7 @@ error: layout_of(MultipleAlignments) = Layout { LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: layout_of(Result<[u32; 0], Packed<NonZeroU16>>) = Layout { +error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout { size: Size(4 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 09fda33dbec..9740742fbbb 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -436,7 +436,7 @@ mod hidden_niche { fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; //~^ WARN redeclared with a different signature - //~| WARN block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe + //~| WARN block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe } } } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 0d269e599dd..5b9244b6993 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -8,7 +8,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN = note: enum has no representation hint = note: `#[warn(improper_ctypes)]` on by default -warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe +warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:437:46 | LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; @@ -163,7 +163,7 @@ LL | fn non_zero_usize() -> core::num::NonZeroUsize; LL | fn non_zero_usize() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> NonZeroUsize` + = note: expected `unsafe extern "C" fn() -> NonZero<usize>` found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature @@ -224,7 +224,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` - found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>` + found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZero<usize>>>` warning: 19 warnings emitted diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index 57531b0968f..bdf47343114 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -316,7 +316,7 @@ LL | let _val: NonNull<i32> = mem::uninitialized(); = note: `std::ptr::NonNull<i32>` must be non-null = note: raw pointers must be initialized -error: the type `(NonZeroU32, i32)` does not permit zero-initialization +error: the type `(NonZero<u32>, i32)` does not permit zero-initialization --> $DIR/invalid_value.rs:95:39 | LL | let _val: (NonZeroU32, i32) = mem::zeroed(); @@ -325,9 +325,9 @@ LL | let _val: (NonZeroU32, i32) = mem::zeroed(); | this code causes undefined behavior when executed | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero<u32>` must be non-null -error: the type `(NonZeroU32, i32)` does not permit being left uninitialized +error: the type `(NonZero<u32>, i32)` does not permit being left uninitialized --> $DIR/invalid_value.rs:96:39 | LL | let _val: (NonZeroU32, i32) = mem::uninitialized(); @@ -336,7 +336,7 @@ LL | let _val: (NonZeroU32, i32) = mem::uninitialized(); | this code causes undefined behavior when executed | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero<u32>` must be non-null = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization @@ -417,7 +417,7 @@ LL | let _val: OneFruitNonZero = mem::zeroed(); | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done | = note: `OneFruitNonZero` must be non-null -note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) +note: because `std::num::NonZero<u32>` must be non-null (in this field of the only potentially inhabited enum variant) --> $DIR/invalid_value.rs:39:12 | LL | Banana(NonZeroU32), @@ -433,7 +433,7 @@ LL | let _val: OneFruitNonZero = mem::uninitialized(); | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done | = note: `OneFruitNonZero` must be non-null -note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) +note: because `std::num::NonZero<u32>` must be non-null (in this field of the only potentially inhabited enum variant) --> $DIR/invalid_value.rs:39:12 | LL | Banana(NonZeroU32), @@ -603,7 +603,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | = note: references must be non-null -error: the type `NonZeroU32` does not permit zero-initialization +error: the type `NonZero<u32>` does not permit zero-initialization --> $DIR/invalid_value.rs:154:32 | LL | let _val: NonZeroU32 = mem::transmute(0); @@ -612,7 +612,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0); | this code causes undefined behavior when executed | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done | - = note: `std::num::NonZeroU32` must be non-null + = note: `std::num::NonZero<u32>` must be non-null error: the type `NonNull<i32>` does not permit zero-initialization --> $DIR/invalid_value.rs:157:34 diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 8554e261778..64beefbb757 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -61,7 +61,7 @@ LL | fn nonzero_i128(x: Option<num::NonZeroI128>); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `Option<TransparentUnion<NonZeroU8>>`, which is not FFI-safe +error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:86:28 | LL | fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>); @@ -70,7 +70,7 @@ LL | fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `Option<Rust<NonZeroU8>>`, which is not FFI-safe +error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:88:20 | LL | fn repr_rust(x: Option<Rust<num::NonZeroU8>>); @@ -79,7 +79,7 @@ LL | fn repr_rust(x: Option<Rust<num::NonZeroU8>>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `Result<(), NonZeroI32>`, which is not FFI-safe +error: `extern` block uses type `Result<(), NonZero<i32>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:89:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index 57db71f889c..f8e86905ab9 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -2,10 +2,12 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:2:35 | LL | let _: std::num::NonZeroU64 = 1; - | -------------------- ^ expected `NonZeroU64`, found integer + | -------------------- ^ expected `NonZero<u64>`, found integer | | | expected due to this | + = note: expected struct `NonZero<u64>` + found type `{integer}` help: consider calling `NonZeroU64::new` | LL | let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap(); @@ -15,11 +17,11 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:6:43 | LL | let _: Option<std::num::NonZeroU64> = 1; - | ---------------------------- ^ expected `Option<NonZeroU64>`, found integer + | ---------------------------- ^ expected `Option<NonZero<u64>>`, found integer | | | expected due to this | - = note: expected enum `Option<NonZeroU64>` + = note: expected enum `Option<NonZero<u64>>` found type `{integer}` help: consider calling `NonZeroU64::new` | diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index e1825eb5b54..be0fc0f98e2 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -124,7 +124,7 @@ LL | x / 100.0 = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div<Rhs>`: <u8 as Div> - <u8 as Div<NonZeroU8>> + <u8 as Div<NonZero<u8>>> <u8 as Div<&u8>> <&'a u8 as Div<u8>> <&u8 as Div<&u8>> diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs new file mode 100644 index 00000000000..a7412f51782 --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.rs @@ -0,0 +1,9 @@ +// Issue #118164: recovery path leaving unemitted error behind +fn bar() -> String { + #[cfg(feature = )] + [1, 2, 3].iter().map().collect::<String>() //~ ERROR expected `;`, found `#` + #[attr] //~ ERROR expected statement after outer attribute +} +fn main() { + let _ = bar(); +} diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr new file mode 100644 index 00000000000..dd0081cc2df --- /dev/null +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body.stderr @@ -0,0 +1,27 @@ +error: expected `;`, found `#` + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:4:47 + | +LL | #[cfg(feature = )] + | ------------------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | [1, 2, 3].iter().map().collect::<String>() + | ^ expected `;` here +LL | #[attr] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter().map().collect::<String>(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter().map().collect::<String>() } + | + + + +error: expected statement after outer attribute + --> $DIR/properly-recover-from-trailing-outer-attribute-in-body.rs:5:5 + | +LL | #[attr] + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issues/issue-24197.rs b/tests/ui/parser/issues/issue-24197.rs index aaf5137461f..9bba16e5596 100644 --- a/tests/ui/parser/issues/issue-24197.rs +++ b/tests/ui/parser/issues/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let buf[0] = 0; //~ error: expected a pattern, found an expression } diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 3ef707f3953..7ebbf4ac370 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/issue-24197.rs:2:12 +error: expected a pattern, found an expression + --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs index 1d128d33e4f..a5e256b7f15 100644 --- a/tests/ui/parser/issues/issue-24375.rs +++ b/tests/ui/parser/issues/issue-24375.rs @@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"]; fn main() { let z = "hello"; match z { - tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` + tmp[0] => {} //~ error: expected a pattern, found an expression _ => {} } } diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index bb1e19e9e6d..e6ef07d13fd 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -1,8 +1,8 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `[` - --> $DIR/issue-24375.rs:6:12 +error: expected a pattern, found an expression + --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^ expected one of `=>`, `@`, `if`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns error: aborting due to 1 previous error diff --git a/tests/ui/parser/pat-lt-bracket-5.rs b/tests/ui/parser/pat-lt-bracket-5.rs index aaece1f6bd9..6d784494d56 100644 --- a/tests/ui/parser/pat-lt-bracket-5.rs +++ b/tests/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,5 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` + let v[0] = v[1]; + //~^ error: expected a pattern, found an expression + //~| error: cannot find value `v` in this scope } diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index e556e6c0206..18cf2df0282 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,15 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-5.rs:2:10 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | ^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error[E0425]: cannot find value `v` in this scope + --> $DIR/pat-lt-bracket-5.rs:2:16 + | +LL | let v[0] = v[1]; + | ^ not found in this scope + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/pat-lt-bracket-6.rs b/tests/ui/parser/pat-lt-bracket-6.rs index 7becffa9fe2..496525ed537 100644 --- a/tests/ui/parser/pat-lt-bracket-6.rs +++ b/tests/ui/parser/pat-lt-bracket-6.rs @@ -3,7 +3,8 @@ fn main() { let x = Test(&0, []); let Test(&desc[..]) = x; - //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[` + //~^ error: expected a pattern, found an expression + //~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields } const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 035d0dbfe06..10c638a63e4 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -1,18 +1,30 @@ -error: expected one of `)`, `,`, `@`, or `|`, found `[` - --> $DIR/pat-lt-bracket-6.rs:5:19 +error: expected a pattern, found an expression + --> $DIR/pat-lt-bracket-6.rs:5:15 | LL | let Test(&desc[..]) = x; - | ^ - | | - | expected one of `)`, `,`, `@`, or `|` - | help: missing `,` + | ^^^^^^^^ arbitrary expressions are not allowed in patterns error[E0308]: mismatched types - --> $DIR/pat-lt-bracket-6.rs:9:30 + --> $DIR/pat-lt-bracket-6.rs:10:30 | LL | const RECOVERY_WITNESS: () = 0; | ^ expected `()`, found integer -error: aborting due to 2 previous errors +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-lt-bracket-6.rs:5:14 + | +LL | struct Test(&'static u8, [u8; 0]); + | ----------- ------- tuple struct has 2 fields +... +LL | let Test(&desc[..]) = x; + | ^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | let Test(&desc[..], _) = x; + | +++ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0023, E0308. +For more information about an error, try `rustc --explain E0023`. diff --git a/tests/ui/parser/pat-ranges-3.rs b/tests/ui/parser/pat-ranges-3.rs index 8976dcf0d90..419768a2a20 100644 --- a/tests/ui/parser/pat-ranges-3.rs +++ b/tests/ui/parser/pat-ranges-3.rs @@ -1,5 +1,9 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` + let 10 ..= 10 + 3 = 12; + //~^ error: expected a pattern range bound, found an expression + + let 10 - 3 ..= 10 = 8; + //~^ error: expected a pattern range bound, found an expression } diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 611b35a6502..5e1f35d1b6f 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,14 @@ -error: expected one of `:`, `;`, `=`, or `|`, found `+` - --> $DIR/pat-ranges-3.rs:4:19 +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, `=`, or `|` + | ^^^^^^ arbitrary expressions are not allowed in patterns -error: aborting due to 1 previous error +error: expected a pattern range bound, found an expression + --> $DIR/pat-ranges-3.rs:7:9 + | +LL | let 10 - 3 ..= 10 = 8; + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/pat-ranges-4.rs b/tests/ui/parser/pat-ranges-4.rs deleted file mode 100644 index 61188976b02..00000000000 --- a/tests/ui/parser/pat-ranges-4.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Parsing of range patterns - -fn main() { - let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` -} diff --git a/tests/ui/parser/pat-ranges-4.stderr b/tests/ui/parser/pat-ranges-4.stderr deleted file mode 100644 index c30160291d6..00000000000 --- a/tests/ui/parser/pat-ranges-4.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` - --> $DIR/pat-ranges-4.rs:4:12 - | -LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of 7 possible tokens - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs new file mode 100644 index 00000000000..ecd471467e3 --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.rs @@ -0,0 +1,28 @@ +fn main() { + match u8::MAX { + u8::MAX.abs() => (), + //~^ error: expected a pattern, found a method call + x.sqrt() @ .. => (), + //~^ error: expected a pattern, found a method call + //~| error: left-hand side of `@` must be a binding + z @ w @ v.u() => (), + //~^ error: expected a pattern, found a method call + y.ilog(3) => (), + //~^ error: expected a pattern, found a method call + n + 1 => (), + //~^ error: expected a pattern, found an expression + ("".f() + 14 * 8) => (), + //~^ error: expected a pattern, found an expression + 0 | ((1) | 2) | 3 => (), + f?() => (), + //~^ error: expected a pattern, found an expression + (_ + 1) => (), + //~^ error: expected one of `)`, `,`, or `|`, found `+` + } + + let 1 + 1 = 2; + //~^ error: expected a pattern, found an expression + + let b = matches!(x, (x * x | x.f()) | x[0]); + //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*` +} diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr new file mode 100644 index 00000000000..787fd03b0c3 --- /dev/null +++ b/tests/ui/parser/pat-recover-exprs.stderr @@ -0,0 +1,76 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:3:9 + | +LL | u8::MAX.abs() => (), + | ^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | ^^^^^^^^ method calls are not allowed in patterns + +error: left-hand side of `@` must be a binding + --> $DIR/pat-recover-exprs.rs:5:9 + | +LL | x.sqrt() @ .. => (), + | --------^^^-- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:8:17 + | +LL | z @ w @ v.u() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-exprs.rs:10:9 + | +LL | y.ilog(3) => (), + | ^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:12:9 + | +LL | n + 1 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:14:10 + | +LL | ("".f() + 14 * 8) => (), + | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:17:9 + | +LL | f?() => (), + | ^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, or `|`, found `+` + --> $DIR/pat-recover-exprs.rs:19:12 + | +LL | (_ + 1) => (), + | ^ expected one of `)`, `,`, or `|` + +error: expected a pattern, found an expression + --> $DIR/pat-recover-exprs.rs:23:9 + | +LL | let 1 + 1 = 2; + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected one of `)`, `,`, `@`, or `|`, found `*` + --> $DIR/pat-recover-exprs.rs:26:28 + | +LL | let b = matches!(x, (x * x | x.f()) | x[0]); + | ^ expected one of `)`, `,`, `@`, or `|` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: while parsing argument for this `pat` macro fragment + +error: aborting due to 11 previous errors + diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs new file mode 100644 index 00000000000..54104e9a535 --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.rs @@ -0,0 +1,37 @@ +struct Foo(String); +struct Bar { baz: String } + +fn foo(foo: Foo) -> bool { + match foo { + Foo("hi".to_owned()) => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn bar(bar: Bar) -> bool { + match bar { + Bar { baz: "hi".to_owned() } => true, + //~^ error: expected a pattern, found a method call + _ => false + } +} + +fn baz() { // issue #90121 + let foo = vec!["foo".to_string()]; + + match foo.as_slice() { + &["foo".to_string()] => {} + //~^ error: expected a pattern, found a method call + _ => {} + }; +} + +fn main() { + if let (-1.some(4)) = (0, Some(4)) {} + //~^ error: expected a pattern, found a method call + + if let (-1.Some(4)) = (0, Some(4)) {} + //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + //~| help: missing `,` +} diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr new file mode 100644 index 00000000000..1f9ae81dc0c --- /dev/null +++ b/tests/ui/parser/pat-recover-methodcalls.stderr @@ -0,0 +1,35 @@ +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:6:13 + | +LL | Foo("hi".to_owned()) => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:14:20 + | +LL | Bar { baz: "hi".to_owned() } => true, + | ^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:24:11 + | +LL | &["foo".to_string()] => {} + | ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns + +error: expected a pattern, found a method call + --> $DIR/pat-recover-methodcalls.rs:31:13 + | +LL | if let (-1.some(4)) = (0, Some(4)) {} + | ^^^^^^^^^^ method calls are not allowed in patterns + +error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.` + --> $DIR/pat-recover-methodcalls.rs:34:15 + | +LL | if let (-1.Some(4)) = (0, Some(4)) {} + | ^ + | | + | expected one of `)`, `,`, `...`, `..=`, `..`, or `|` + | help: missing `,` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/pat-recover-ranges.rs index 65a6fc6fe21..7d77e950d90 100644 --- a/tests/ui/parser/pat-recover-ranges.rs +++ b/tests/ui/parser/pat-recover-ranges.rs @@ -8,6 +8,22 @@ fn main() { (0)..=(-4) => (), //~^ error: range pattern bounds cannot have parentheses //~| error: range pattern bounds cannot have parentheses + ..=1 + 2 => (), + //~^ error: expected a pattern range bound, found an expression + (4).. => (), + //~^ error: range pattern bounds cannot have parentheses + (-4 + 0).. => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + (1 + 4)...1 * 2 => (), + //~^ error: expected a pattern range bound, found an expression + //~| error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + //~| warning: `...` range patterns are deprecated + //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + 0.x()..="y".z() => (), + //~^ error: expected a pattern range bound, found a method call + //~| error: expected a pattern range bound, found a method call }; } diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/pat-recover-ranges.stderr index 0d722b5aa95..a7d62bd7f8a 100644 --- a/tests/ui/parser/pat-recover-ranges.stderr +++ b/tests/ui/parser/pat-recover-ranges.stderr @@ -46,5 +46,87 @@ LL - (0)..=(-4) => (), LL + (0)..=-4 => (), | -error: aborting due to 4 previous errors +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:11:12 + | +LL | ..=1 + 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:13:9 + | +LL | (4).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (4).. => (), +LL + 4.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:15:10 + | +LL | (-4 + 0).. => (), + | ^^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:15:9 + | +LL | (-4 + 0).. => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (-4 + 0).. => (), +LL + -4 + 0.. => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:10 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-ranges.rs:18:9 + | +LL | (1 + 4)...1 * 2 => (), + | ^ ^ + | +help: remove these parentheses + | +LL - (1 + 4)...1 * 2 => (), +LL + 1 + 4...1 * 2 => (), + | + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-ranges.rs:18:19 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:9 + | +LL | 0.x()..="y".z() => (), + | ^^^^^ method calls are not allowed in patterns + +error: expected a pattern range bound, found a method call + --> $DIR/pat-recover-ranges.rs:24:17 + | +LL | 0.x()..="y".z() => (), + | ^^^^^^^ method calls are not allowed in patterns + +warning: `...` range patterns are deprecated + --> $DIR/pat-recover-ranges.rs:18:16 + | +LL | (1 + 4)...1 * 2 => (), + | ^^^ help: use `..=` for an inclusive range + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> + = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default + +error: aborting due to 13 previous errors; 1 warning emitted diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/pat-recover-wildcards.rs new file mode 100644 index 00000000000..f506e2223d6 --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.rs @@ -0,0 +1,61 @@ +// check that we can't do funny things with wildcards. + +fn a() { + match 1 { + _ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+` + } +} + +fn b() { + match 2 { + (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%` + } +} + +fn c() { + match 3 { + _.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.` + } +} + +fn d() { + match 4 { + _..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=` + } +} + +fn e() { + match 5 { + .._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn f() { + match 6 { + 0..._ => () + //~^ error: inclusive range with no end + //~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + } +} + +fn g() { + match 7 { + (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*` + } +} + +fn h() { + match 8 { + ..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(` + } +} + +fn i() { + match 9 { + 4..=(2 + _) => () + //~^ error: expected a pattern range bound, found an expression + //~| error: range pattern bounds cannot have parentheses + } +} + +fn main() {} diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr new file mode 100644 index 00000000000..2b0c9bbc5be --- /dev/null +++ b/tests/ui/parser/pat-recover-wildcards.stderr @@ -0,0 +1,77 @@ +error: expected one of `=>`, `if`, or `|`, found `+` + --> $DIR/pat-recover-wildcards.rs:5:11 + | +LL | _ + 1 => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `%` + --> $DIR/pat-recover-wildcards.rs:11:12 + | +LL | (_ % 4) => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `.` + --> $DIR/pat-recover-wildcards.rs:17:10 + | +LL | _.x() => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `..=` + --> $DIR/pat-recover-wildcards.rs:23:10 + | +LL | _..=4 => () + | ^^^ expected one of `=>`, `if`, or `|` + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:29:11 + | +LL | .._ => () + | ^ expected one of `=>`, `if`, or `|` + +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`) + +error: expected one of `=>`, `if`, or `|`, found reserved identifier `_` + --> $DIR/pat-recover-wildcards.rs:35:13 + | +LL | 0..._ => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected one of `)`, `,`, or `|`, found `*` + --> $DIR/pat-recover-wildcards.rs:43:12 + | +LL | (_ * 0)..5 => () + | ^ expected one of `)`, `,`, or `|` + +error: expected one of `=>`, `if`, or `|`, found `(` + --> $DIR/pat-recover-wildcards.rs:49:11 + | +LL | ..(_) => () + | ^ expected one of `=>`, `if`, or `|` + +error: expected a pattern range bound, found an expression + --> $DIR/pat-recover-wildcards.rs:55:14 + | +LL | 4..=(2 + _) => () + | ^^^^^ arbitrary expressions are not allowed in patterns + +error: range pattern bounds cannot have parentheses + --> $DIR/pat-recover-wildcards.rs:55:13 + | +LL | 4..=(2 + _) => () + | ^ ^ + | +help: remove these parentheses + | +LL - 4..=(2 + _) => () +LL + 4..=2 + _ => () + | + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/parser/range-exclusive-dotdotlt.rs b/tests/ui/parser/range-exclusive-dotdotlt.rs new file mode 100644 index 00000000000..5752566026f --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.rs @@ -0,0 +1,43 @@ +fn foo() { + let _ = 0..<10; + //~^ ERROR: expected type, found `10` + //~| HELP: remove the `<` to write an exclusive range +} + +fn bar() { + let _ = 0..<foo; + //~^ ERROR: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` + //~| HELP: remove the `<` to write an exclusive range +} + +fn baz() { + let _ = <foo>; + //~^ ERROR: expected `::`, found `;` +} + +fn qux() { + let _ = [1, 2, 3][..<1]; + //~^ ERROR: expected type, found `1` + //~| HELP: remove the `<` to write an exclusive range +} + +fn quux() { + let _ = [1, 2, 3][..<foo]; + //~^ ERROR: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` + //~| HELP: remove the `<` to write an exclusive range +} + +fn foobar() { + let _ = [1, 2, 3][..<foo>]; + //~^ ERROR: expected `::`, found `]` +} + +fn ok1() { + let _ = [1, 2, 3][..<usize>::default()]; +} + +fn ok2() { + let _ = 0..<i32>::default(); +} + +fn main() {} diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr new file mode 100644 index 00000000000..af25e1df343 --- /dev/null +++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr @@ -0,0 +1,46 @@ +error: expected type, found `10` + --> $DIR/range-exclusive-dotdotlt.rs:2:17 + | +LL | let _ = 0..<10; + | -^^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;` + --> $DIR/range-exclusive-dotdotlt.rs:8:20 + | +LL | let _ = 0..<foo; + | - ^ expected one of 7 possible tokens + | | + | help: remove the `<` to write an exclusive range + +error: expected `::`, found `;` + --> $DIR/range-exclusive-dotdotlt.rs:14:18 + | +LL | let _ = <foo>; + | ^ expected `::` + +error: expected type, found `1` + --> $DIR/range-exclusive-dotdotlt.rs:19:26 + | +LL | let _ = [1, 2, 3][..<1]; + | -^ expected type + | | + | help: remove the `<` to write an exclusive range + +error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]` + --> $DIR/range-exclusive-dotdotlt.rs:25:29 + | +LL | let _ = [1, 2, 3][..<foo]; + | - ^ expected one of 7 possible tokens + | | + | help: remove the `<` to write an exclusive range + +error: expected `::`, found `]` + --> $DIR/range-exclusive-dotdotlt.rs:31:30 + | +LL | let _ = [1, 2, 3][..<foo>]; + | ^ expected `::` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index 367aba3bdd6..0c55164a780 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -1,23 +1,23 @@ error: unreachable pattern - --> $DIR/empty-types.rs:47:9 + --> $DIR/empty-types.rs:50:9 | LL | _ => {} | ^ | note: the lint level is defined here - --> $DIR/empty-types.rs:13:9 + --> $DIR/empty-types.rs:16:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:50:9 + --> $DIR/empty-types.rs:53:9 | LL | _x => {} | ^^ error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:54:11 + --> $DIR/empty-types.rs:57:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -32,31 +32,31 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:69:9 + --> $DIR/empty-types.rs:72:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:76:9 + --> $DIR/empty-types.rs:79:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:79:9 + --> $DIR/empty-types.rs:82:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:83:9 + --> $DIR/empty-types.rs:86:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `Ok(_)` not covered - --> $DIR/empty-types.rs:87:11 + --> $DIR/empty-types.rs:90:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered @@ -75,19 +75,19 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:95:9 + --> $DIR/empty-types.rs:98:9 | LL | Err(_) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:100:9 + --> $DIR/empty-types.rs:103:9 | LL | Err(_) => {} | ^^^^^^ error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:97:11 + --> $DIR/empty-types.rs:100:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -105,7 +105,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:104:9 + --> $DIR/empty-types.rs:107:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -119,121 +119,121 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:115:9 + --> $DIR/empty-types.rs:118:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:119:9 + --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:122:9 + --> $DIR/empty-types.rs:125:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:123:9 + --> $DIR/empty-types.rs:126:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:126:9 + --> $DIR/empty-types.rs:129:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:127:9 + --> $DIR/empty-types.rs:130:9 | LL | Err(_) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:136:13 + --> $DIR/empty-types.rs:139:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:139:13 + --> $DIR/empty-types.rs:142:13 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:148:13 + --> $DIR/empty-types.rs:151:13 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:152:13 + --> $DIR/empty-types.rs:155:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:204:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:209:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:214:13 + --> $DIR/empty-types.rs:217:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:222:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:225:13 + --> $DIR/empty-types.rs:228:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:284:9 + --> $DIR/empty-types.rs:287:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:287:9 + --> $DIR/empty-types.rs:290:9 | LL | (_, _) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:290:9 + --> $DIR/empty-types.rs:293:9 | LL | Ok(_) => {} | ^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:291:9 + --> $DIR/empty-types.rs:294:9 | LL | Err(_) => {} | ^^^^^^ error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:323:11 + --> $DIR/empty-types.rs:326:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -247,7 +247,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:334:11 + --> $DIR/empty-types.rs:337:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -260,7 +260,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` not covered - --> $DIR/empty-types.rs:347:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[]` not covered @@ -274,7 +274,7 @@ LL + &[] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:353:11 + --> $DIR/empty-types.rs:356:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -288,25 +288,25 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:363:9 + --> $DIR/empty-types.rs:366:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:366:9 + --> $DIR/empty-types.rs:369:9 | LL | [_, _, _] => {} | ^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:369:9 + --> $DIR/empty-types.rs:372:9 | LL | [_, ..] => {} | ^^^^^^^ error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:383:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -320,13 +320,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:390:9 + --> $DIR/empty-types.rs:393:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:392:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -340,49 +340,49 @@ LL + [] => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:411:9 + --> $DIR/empty-types.rs:414:9 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:416:9 + --> $DIR/empty-types.rs:419:9 | LL | Some(_a) => {} | ^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:421:9 + --> $DIR/empty-types.rs:424:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:426:9 + --> $DIR/empty-types.rs:429:9 | LL | _a => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:598:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:601:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:604:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:607:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^ diff --git a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr new file mode 100644 index 00000000000..ed5d125e684 --- /dev/null +++ b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr @@ -0,0 +1,630 @@ +warning: the feature `min_exhaustive_patterns` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/empty-types.rs:13:35 + | +LL | #![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #119612 <https://github.com/rust-lang/rust/issues/119612> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: unreachable pattern + --> $DIR/empty-types.rs:50:9 + | +LL | _ => {} + | ^ + | +note: the lint level is defined here + --> $DIR/empty-types.rs:16:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:53:9 + | +LL | _x => {} + | ^^ + +error[E0004]: non-exhaustive patterns: type `&!` is non-empty + --> $DIR/empty-types.rs:57:11 + | +LL | match ref_never {} + | ^^^^^^^^^ + | + = note: the matched value is of type `&!` + = note: references are always considered inhabited +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match ref_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:72:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:79:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:82:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:86:9 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `Ok(_)` not covered + --> $DIR/empty-types.rs:90:11 + | +LL | match res_u32_never {} + | ^^^^^^^^^^^^^ pattern `Ok(_)` not covered + | +note: `Result<u32, !>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result<u32, !>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ match res_u32_never { +LL + Ok(_) => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:98:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:103:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered + --> $DIR/empty-types.rs:100:11 + | +LL | match res_u32_never { + | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered + | +note: `Result<u32, !>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result<u32, !>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Err(_) => {}, +LL ~ Ok(1_u32..=u32::MAX) => todo!() + | + +error[E0005]: refutable pattern in local binding + --> $DIR/empty-types.rs:107:9 + | +LL | let Ok(_x) = res_u32_never.as_ref(); + | ^^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `Result<&u32, &!>` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; + | ++++++++++++++++ + +error[E0005]: refutable pattern in local binding + --> $DIR/empty-types.rs:111:9 + | +LL | let Ok(_x) = &res_u32_never; + | ^^^^^^ pattern `&Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `&Result<u32, !>` +help: you might want to use `let else` to handle the variant that isn't matched + | +LL | let Ok(_x) = &res_u32_never else { todo!() }; + | ++++++++++++++++ + +error: unreachable pattern + --> $DIR/empty-types.rs:118:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:122:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:125:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:126:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:129:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:130:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:139:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:142:13 + | +LL | _ if false => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:151:13 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:155:13 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:164:15 + | +LL | match *ref_opt_void { + | ^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option<Void>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<Void>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: unreachable pattern + --> $DIR/empty-types.rs:207:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:212:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:217:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:222:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:228:13 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:287:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:290:9 + | +LL | (_, _) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:293:9 + | +LL | Ok(_) => {} + | ^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:294:9 + | +LL | Err(_) => {} + | ^^^^^^ + +error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty + --> $DIR/empty-types.rs:315:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `(u32, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty + --> $DIR/empty-types.rs:317:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `(!, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered + --> $DIR/empty-types.rs:319:11 + | +LL | match *x {} + | ^^ patterns `Ok(_)` and `Err(_)` not covered + | +note: `Result<!, !>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result<!, !>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ match *x { +LL + Ok(_) | Err(_) => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty + --> $DIR/empty-types.rs:321:11 + | +LL | match *x {} + | ^^ + | + = note: the matched value is of type `[!; 3]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *x { +LL + _ => todo!(), +LL ~ } + | + +error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty + --> $DIR/empty-types.rs:326:11 + | +LL | match slice_never {} + | ^^^^^^^^^^^ + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match slice_never { +LL + _ => todo!(), +LL + } + | + +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/empty-types.rs:328:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ pattern `&[_, ..]` not covered + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [] => {}, +LL + &[_, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered + --> $DIR/empty-types.rs:337:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ [_, _, _, ..] => {}, +LL + &[] | &[_] | &[_, _] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered + --> $DIR/empty-types.rs:350:11 + | +LL | match slice_never { + | ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered + | + = note: the matched value is of type `&[!]` + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ &[..] if false => {}, +LL + &[] | &[_, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: type `[!]` is non-empty + --> $DIR/empty-types.rs:356:11 + | +LL | match *slice_never {} + | ^^^^^^^^^^^^ + | + = note: the matched value is of type `[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *slice_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:366:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:369:9 + | +LL | [_, _, _] => {} + | ^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:372:9 + | +LL | [_, ..] => {} + | ^^^^^^^ + +error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty + --> $DIR/empty-types.rs:386:11 + | +LL | match array_0_never {} + | ^^^^^^^^^^^^^ + | + = note: the matched value is of type `[!; 0]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match array_0_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:393:9 + | +LL | _ => {} + | ^ + +error[E0004]: non-exhaustive patterns: `[]` not covered + --> $DIR/empty-types.rs:395:11 + | +LL | match array_0_never { + | ^^^^^^^^^^^^^ pattern `[]` not covered + | + = note: the matched value is of type `[!; 0]` + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [..] if false => {}, +LL + [] => todo!() + | + +error: unreachable pattern + --> $DIR/empty-types.rs:414:9 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:419:9 + | +LL | Some(_a) => {} + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:424:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:429:9 + | +LL | _a => {} + | ^^ + +error[E0004]: non-exhaustive patterns: `&Some(_)` not covered + --> $DIR/empty-types.rs:449:11 + | +LL | match ref_opt_never { + | ^^^^^^^^^^^^^ pattern `&Some(_)` not covered + | +note: `Option<!>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `&Option<!>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ &None => {}, +LL + &Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:490:11 + | +LL | match *ref_opt_never { + | ^^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option<!>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<!>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Err(_)` not covered + --> $DIR/empty-types.rs:538:11 + | +LL | match *ref_res_never { + | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered + | +note: `Result<!, !>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result<!, !>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Ok(_) => {}, +LL + Err(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Err(_)` not covered + --> $DIR/empty-types.rs:549:11 + | +LL | match *ref_res_never { + | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered + | +note: `Result<!, !>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result<!, !>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Ok(_a) => {}, +LL + Err(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty + --> $DIR/empty-types.rs:568:11 + | +LL | match *ref_tuple_half_never {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the matched value is of type `(u32, !)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match *ref_tuple_half_never { +LL + _ => todo!(), +LL + } + | + +error: unreachable pattern + --> $DIR/empty-types.rs:601:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:604:9 + | +LL | _x => {} + | ^^ + +error: unreachable pattern + --> $DIR/empty-types.rs:607:9 + | +LL | _ if false => {} + | ^ + +error: unreachable pattern + --> $DIR/empty-types.rs:610:9 + | +LL | _x if false => {} + | ^^ + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/empty-types.rs:635:11 + | +LL | match ref_never { + | ^^^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&!` + = note: references are always considered inhabited + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ &_a if false => {}, +LL + &_ => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:663:11 + | +LL | match *x { + | ^^ pattern `Some(_)` not covered + | +note: `Option<Result<!, !>>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<Result<!, !>>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: aborting due to 63 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index 133a95a821b..2fdb51677da 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -1,23 +1,23 @@ error: unreachable pattern - --> $DIR/empty-types.rs:47:9 + --> $DIR/empty-types.rs:50:9 | LL | _ => {} | ^ | note: the lint level is defined here - --> $DIR/empty-types.rs:13:9 + --> $DIR/empty-types.rs:16:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-types.rs:50:9 + --> $DIR/empty-types.rs:53:9 | LL | _x => {} | ^^ error[E0004]: non-exhaustive patterns: type `&!` is non-empty - --> $DIR/empty-types.rs:54:11 + --> $DIR/empty-types.rs:57:11 | LL | match ref_never {} | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:66:11 + --> $DIR/empty-types.rs:69:11 | LL | match tuple_half_never {} | ^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:73:11 + --> $DIR/empty-types.rs:76:11 | LL | match tuple_never {} | ^^^^^^^^^^^ @@ -60,13 +60,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:83:9 + --> $DIR/empty-types.rs:86:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:87:11 + --> $DIR/empty-types.rs:90:11 | LL | match res_u32_never {} | ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered @@ -88,7 +88,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:89:11 + --> $DIR/empty-types.rs:92:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -106,7 +106,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered - --> $DIR/empty-types.rs:97:11 + --> $DIR/empty-types.rs:100:11 | LL | match res_u32_never { | ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered @@ -124,7 +124,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:102:9 + --> $DIR/empty-types.rs:105:9 | LL | let Ok(_x) = res_u32_never; | ^^^^^^ pattern `Err(_)` not covered @@ -138,7 +138,7 @@ LL | let Ok(_x) = res_u32_never else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:104:9 + --> $DIR/empty-types.rs:107:9 | LL | let Ok(_x) = res_u32_never.as_ref(); | ^^^^^^ pattern `Err(_)` not covered @@ -152,7 +152,7 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() }; | ++++++++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/empty-types.rs:108:9 + --> $DIR/empty-types.rs:111:9 | LL | let Ok(_x) = &res_u32_never; | ^^^^^^ pattern `&Err(_)` not covered @@ -166,7 +166,7 @@ LL | let Ok(_x) = &res_u32_never else { todo!() }; | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:112:11 + --> $DIR/empty-types.rs:115:11 | LL | match result_never {} | ^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered @@ -188,7 +188,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:117:11 + --> $DIR/empty-types.rs:120:11 | LL | match result_never { | ^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -205,19 +205,19 @@ LL | Ok(_) => {}, Err(_) => todo!() | +++++++++++++++++++ error: unreachable pattern - --> $DIR/empty-types.rs:136:13 + --> $DIR/empty-types.rs:139:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:139:13 + --> $DIR/empty-types.rs:142:13 | LL | _ if false => {} | ^ error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:142:15 + --> $DIR/empty-types.rs:145:15 | LL | match opt_void { | ^^^^^^^^ pattern `Some(_)` not covered @@ -235,7 +235,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:161:15 + --> $DIR/empty-types.rs:164:15 | LL | match *ref_opt_void { | ^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -253,43 +253,43 @@ LL + Some(_) => todo!() | error: unreachable pattern - --> $DIR/empty-types.rs:204:13 + --> $DIR/empty-types.rs:207:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:209:13 + --> $DIR/empty-types.rs:212:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:214:13 + --> $DIR/empty-types.rs:217:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:219:13 + --> $DIR/empty-types.rs:222:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:225:13 + --> $DIR/empty-types.rs:228:13 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:284:9 + --> $DIR/empty-types.rs:287:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:312:11 + --> $DIR/empty-types.rs:315:11 | LL | match *x {} | ^^ @@ -303,7 +303,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty - --> $DIR/empty-types.rs:314:11 + --> $DIR/empty-types.rs:317:11 | LL | match *x {} | ^^ @@ -317,7 +317,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered - --> $DIR/empty-types.rs:316:11 + --> $DIR/empty-types.rs:319:11 | LL | match *x {} | ^^ patterns `Ok(_)` and `Err(_)` not covered @@ -339,7 +339,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:318:11 + --> $DIR/empty-types.rs:321:11 | LL | match *x {} | ^^ @@ -353,7 +353,7 @@ LL ~ } | error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty - --> $DIR/empty-types.rs:323:11 + --> $DIR/empty-types.rs:326:11 | LL | match slice_never {} | ^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL + } | error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered - --> $DIR/empty-types.rs:325:11 + --> $DIR/empty-types.rs:328:11 | LL | match slice_never { | ^^^^^^^^^^^ pattern `&[_, ..]` not covered @@ -380,7 +380,7 @@ LL + &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered - --> $DIR/empty-types.rs:334:11 + --> $DIR/empty-types.rs:337:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered @@ -393,7 +393,7 @@ LL + &[] | &[_] | &[_, _] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered - --> $DIR/empty-types.rs:347:11 + --> $DIR/empty-types.rs:350:11 | LL | match slice_never { | ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered @@ -407,7 +407,7 @@ LL + &[] | &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: type `[!]` is non-empty - --> $DIR/empty-types.rs:353:11 + --> $DIR/empty-types.rs:356:11 | LL | match *slice_never {} | ^^^^^^^^^^^^ @@ -421,7 +421,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty - --> $DIR/empty-types.rs:360:11 + --> $DIR/empty-types.rs:363:11 | LL | match array_3_never {} | ^^^^^^^^^^^^^ @@ -435,7 +435,7 @@ LL + } | error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty - --> $DIR/empty-types.rs:383:11 + --> $DIR/empty-types.rs:386:11 | LL | match array_0_never {} | ^^^^^^^^^^^^^ @@ -449,13 +449,13 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:390:9 + --> $DIR/empty-types.rs:393:9 | LL | _ => {} | ^ error[E0004]: non-exhaustive patterns: `[]` not covered - --> $DIR/empty-types.rs:392:11 + --> $DIR/empty-types.rs:395:11 | LL | match array_0_never { | ^^^^^^^^^^^^^ pattern `[]` not covered @@ -469,7 +469,7 @@ LL + [] => todo!() | error[E0004]: non-exhaustive patterns: `&Some(_)` not covered - --> $DIR/empty-types.rs:446:11 + --> $DIR/empty-types.rs:449:11 | LL | match ref_opt_never { | ^^^^^^^^^^^^^ pattern `&Some(_)` not covered @@ -487,7 +487,7 @@ LL + &Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:487:11 + --> $DIR/empty-types.rs:490:11 | LL | match *ref_opt_never { | ^^^^^^^^^^^^^^ pattern `Some(_)` not covered @@ -505,7 +505,7 @@ LL + Some(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:535:11 + --> $DIR/empty-types.rs:538:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -523,7 +523,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: `Err(_)` not covered - --> $DIR/empty-types.rs:546:11 + --> $DIR/empty-types.rs:549:11 | LL | match *ref_res_never { | ^^^^^^^^^^^^^^ pattern `Err(_)` not covered @@ -541,7 +541,7 @@ LL + Err(_) => todo!() | error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty - --> $DIR/empty-types.rs:565:11 + --> $DIR/empty-types.rs:568:11 | LL | match *ref_tuple_half_never {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -555,31 +555,31 @@ LL + } | error: unreachable pattern - --> $DIR/empty-types.rs:598:9 + --> $DIR/empty-types.rs:601:9 | LL | _ => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:601:9 + --> $DIR/empty-types.rs:604:9 | LL | _x => {} | ^^ error: unreachable pattern - --> $DIR/empty-types.rs:604:9 + --> $DIR/empty-types.rs:607:9 | LL | _ if false => {} | ^ error: unreachable pattern - --> $DIR/empty-types.rs:607:9 + --> $DIR/empty-types.rs:610:9 | LL | _x if false => {} | ^^ error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/empty-types.rs:631:11 + --> $DIR/empty-types.rs:635:11 | LL | match ref_never { | ^^^^^^^^^ pattern `&_` not covered @@ -594,7 +594,7 @@ LL + &_ => todo!() | error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/empty-types.rs:659:11 + --> $DIR/empty-types.rs:663:11 | LL | match *x { | ^^ pattern `Some(_)` not covered diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs index 1e1d23e446d..c66fd1edc19 100644 --- a/tests/ui/pattern/usefulness/empty-types.rs +++ b/tests/ui/pattern/usefulness/empty-types.rs @@ -1,4 +1,5 @@ -// revisions: normal exhaustive_patterns +// revisions: normal min_exh_pats exhaustive_patterns +// gate-test-min_exhaustive_patterns // // This tests correct handling of empty types in exhaustiveness checking. // @@ -9,6 +10,8 @@ // This feature is useful to avoid `!` falling back to `()` all the time. #![feature(never_type_fallback)] #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] +#![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))] +//[min_exh_pats]~^ WARN the feature `min_exhaustive_patterns` is incomplete #![allow(dead_code, unreachable_code)] #![deny(unreachable_patterns)] @@ -66,17 +69,17 @@ fn basic(x: NeverBundle) { match tuple_half_never {} //[normal]~^ ERROR non-empty match tuple_half_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let tuple_never: (!, !) = x.tuple_never; match tuple_never {} //[normal]~^ ERROR non-empty match tuple_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match tuple_never.0 {} match tuple_never.0 { @@ -92,12 +95,12 @@ fn basic(x: NeverBundle) { } match res_u32_never { Ok(_) => {} - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match res_u32_never { //~^ ERROR non-exhaustive Ok(0) => {} - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let Ok(_x) = res_u32_never; //[normal]~^ ERROR refutable @@ -106,25 +109,25 @@ fn basic(x: NeverBundle) { // Non-obvious difference: here there's an implicit dereference in the patterns, which makes the // inner place !known_valid. `exhaustive_patterns` ignores this. let Ok(_x) = &res_u32_never; - //[normal]~^ ERROR refutable + //[normal,min_exh_pats]~^ ERROR refutable let result_never: Result<!, !> = x.result_never; match result_never {} //[normal]~^ ERROR non-exhaustive match result_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { //[normal]~^ ERROR non-exhaustive - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } } @@ -145,11 +148,11 @@ fn void_same_as_never(x: NeverBundle) { } match opt_void { None => {} - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_void { None => {} - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let ref_void: &Void = &x.void; @@ -159,7 +162,7 @@ fn void_same_as_never(x: NeverBundle) { } let ref_opt_void: &Option<Void> = &None; match *ref_opt_void { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive None => {} } match *ref_opt_void { @@ -284,11 +287,11 @@ fn nested_validity_tracking(bundle: NeverBundle) { _ => {} //~ ERROR unreachable pattern } match tuple_never { - (_, _) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match result_never { - Ok(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - Err(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern + Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } // These should be considered !known_valid and not warn unreachable. @@ -309,13 +312,13 @@ fn invalid_empty_match(bundle: NeverBundle) { match *x {} let x: &(u32, !) = &bundle.tuple_half_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &(!, !) = &bundle.tuple_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &Result<!, !> = &bundle.result_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive let x: &[!; 3] = &bundle.array_3_never; - match *x {} //[normal]~ ERROR non-exhaustive + match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive } fn arrays_and_slices(x: NeverBundle) { @@ -323,7 +326,7 @@ fn arrays_and_slices(x: NeverBundle) { match slice_never {} //~^ ERROR non-empty match slice_never { - //[normal]~^ ERROR not covered + //[normal,min_exh_pats]~^ ERROR not covered [] => {} } match slice_never { @@ -332,7 +335,7 @@ fn arrays_and_slices(x: NeverBundle) { [_, _, ..] => {} } match slice_never { - //[normal]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered + //[normal,min_exh_pats]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered //[exhaustive_patterns]~^^ ERROR `&[]` not covered [_, _, _, ..] => {} } @@ -345,7 +348,7 @@ fn arrays_and_slices(x: NeverBundle) { _x => {} } match slice_never { - //[normal]~^ ERROR `&[]` and `&[_, ..]` not covered + //[normal,min_exh_pats]~^ ERROR `&[]` and `&[_, ..]` not covered //[exhaustive_patterns]~^^ ERROR `&[]` not covered &[..] if false => {} } @@ -360,13 +363,13 @@ fn arrays_and_slices(x: NeverBundle) { match array_3_never {} //[normal]~^ ERROR non-empty match array_3_never { - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match array_3_never { - [_, _, _] => {} //[exhaustive_patterns]~ ERROR unreachable pattern + [_, _, _] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match array_3_never { - [_, ..] => {} //[exhaustive_patterns]~ ERROR unreachable pattern + [_, ..] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } let ref_array_3_never: &[!; 3] = &array_3_never; @@ -408,22 +411,22 @@ fn bindings(x: NeverBundle) { match opt_never { None => {} // !useful, !reachable - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - Some(_a) => {} //[exhaustive_patterns]~ ERROR unreachable pattern + Some(_a) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _ => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } match opt_never { None => {} // !useful, !reachable - _a => {} //[exhaustive_patterns]~ ERROR unreachable pattern + _a => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern } // The scrutinee is known_valid, but under the `&` isn't anymore. @@ -444,7 +447,7 @@ fn bindings(x: NeverBundle) { &_a => {} } match ref_opt_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive &None => {} } match ref_opt_never { @@ -485,7 +488,7 @@ fn bindings(x: NeverBundle) { ref _a => {} } match *ref_opt_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive None => {} } match *ref_opt_never { @@ -533,7 +536,7 @@ fn bindings(x: NeverBundle) { let ref_res_never: &Result<!, !> = &x.result_never; match *ref_res_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, reachable Ok(_) => {} } @@ -544,7 +547,7 @@ fn bindings(x: NeverBundle) { _ => {} } match *ref_res_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, !reachable Ok(_a) => {} } @@ -563,7 +566,7 @@ fn bindings(x: NeverBundle) { let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never; match *ref_tuple_half_never {} - //[normal]~^ ERROR non-empty + //[normal,min_exh_pats]~^ ERROR non-empty match *ref_tuple_half_never { // useful, reachable (_, _) => {} @@ -614,6 +617,7 @@ fn guards_and_validity(x: NeverBundle) { // useful, reachable _ => {} } + // Now the madness commences. The guard caused a load of the value thus asserting validity. So // there's no invalid value for `_` to catch. So the second pattern is unreachable despite the // guard not being taken. @@ -629,7 +633,7 @@ fn guards_and_validity(x: NeverBundle) { _a if false => {} } match ref_never { - //[normal]~^ ERROR non-exhaustive + //[normal,min_exh_pats]~^ ERROR non-exhaustive // useful, !reachable &_a if false => {} } @@ -657,7 +661,7 @@ fn diagnostics_subtlety(x: NeverBundle) { // Regression test for diagnostics: don't report `Some(Ok(_))` and `Some(Err(_))`. let x: &Option<Result<!, !>> = &None; match *x { - //[normal]~^ ERROR `Some(_)` not covered + //[normal,min_exh_pats]~^ ERROR `Some(_)` not covered None => {} } } diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs index 4203dd94d43..51ff641509d 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs @@ -1,6 +1,6 @@ fn main() { let f = |3: isize| println!("hello"); - //~^ ERROR refutable pattern in function argument + //~^ ERROR refutable pattern in closure argument //~| `..=2_isize` and `4_isize..` not covered f(4); } diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr index bd6c5002e63..be119d27ab2 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in function argument +error[E0005]: refutable pattern in closure argument --> $DIR/refutable-pattern-in-fn-arg.rs:2:14 | LL | let f = |3: isize| println!("hello"); diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs index 5826a18b571..4aeb6a643d9 100644 --- a/tests/ui/pin-macro/cant_access_internals.rs +++ b/tests/ui/pin-macro/cant_access_internals.rs @@ -8,5 +8,5 @@ use core::{ fn main() { let mut phantom_pinned = pin!(PhantomPinned); - mem::take(phantom_pinned.pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' + mem::take(phantom_pinned.__pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' } diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr index 2737b84f599..444314a9d8b 100644 --- a/tests/ui/pin-macro/cant_access_internals.stderr +++ b/tests/ui/pin-macro/cant_access_internals.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature 'unsafe_pin_internals' --> $DIR/cant_access_internals.rs:11:15 | -LL | mem::take(phantom_pinned.pointer); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | mem::take(phantom_pinned.__pointer); + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index d1753c26ca8..b53b8936603 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -14,17 +14,17 @@ print-type-size field `.pre`: 1 bytes print-type-size field `.post`: 2 bytes print-type-size field `.val`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption<Union1<std::num::NonZero<u32>>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption<Union2<std::num::NonZero<u32>, std::num::NonZero<u32>>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes +print-type-size type: `MyOption<Union2<std::num::NonZero<u32>, u32>>`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes @@ -53,22 +53,22 @@ print-type-size type: `MyOption<char>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size type: `MyOption<std::num::NonZero<u32>>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size variant `None`: 0 bytes -print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union1<std::num::NonZero<u32>>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union1`: 4 bytes print-type-size field `.a`: 4 bytes -print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union2<std::num::NonZero<u32>, std::num::NonZero<u32>>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes -print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes +print-type-size type: `Union2<std::num::NonZero<u32>, u32>`: 4 bytes, alignment: 4 bytes print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes -print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes +print-type-size type: `std::num::NonZero<u32>`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes print-type-size variant `Four`: 2 bytes diff --git a/tests/ui/str/str-escape.rs b/tests/ui/str/str-escape.rs index 10a72421f24..89a82171063 100644 --- a/tests/ui/str/str-escape.rs +++ b/tests/ui/str/str-escape.rs @@ -1,5 +1,6 @@ // check-pass // ignore-tidy-tab +// edition: 2021 fn main() { let s = "\ @@ -8,11 +9,11 @@ fn main() { //~^^^ WARNING multiple lines skipped by escaped newline assert_eq!(s, ""); - let s = "foo\ + let s = c"foo\ bar "; //~^^^ WARNING whitespace symbol '\u{a0}' is not skipped - assert_eq!(s, "foo bar\n "); + assert_eq!(s, c"foo bar\n "); let s = "a\ b"; @@ -22,10 +23,10 @@ fn main() { b"; assert_eq!(s, "ab"); - let s = "a\ + let s = b"a\ b"; //~^^ WARNING whitespace symbol '\u{c}' is not skipped // '\x0c' is ASCII whitespace, but it may not need skipped // discussion: https://github.com/rust-lang/rust/pull/108403 - assert_eq!(s, "a\x0cb"); + assert_eq!(s, b"a\x0cb"); } diff --git a/tests/ui/str/str-escape.stderr b/tests/ui/str/str-escape.stderr index 43b4f7e36f6..00fe5444e1a 100644 --- a/tests/ui/str/str-escape.stderr +++ b/tests/ui/str/str-escape.stderr @@ -1,5 +1,5 @@ warning: multiple lines skipped by escaped newline - --> $DIR/str-escape.rs:5:14 + --> $DIR/str-escape.rs:6:14 | LL | let s = "\ | ______________^ @@ -8,20 +8,20 @@ LL | | "; | |_____________^ skipping everything up to and including this point warning: whitespace symbol '\u{a0}' is not skipped - --> $DIR/str-escape.rs:11:17 + --> $DIR/str-escape.rs:12:18 | -LL | let s = "foo\ - | _________________^ +LL | let s = c"foo\ + | __________________^ LL | | bar | | ^ whitespace symbol '\u{a0}' is not skipped | |___| | warning: whitespace symbol '\u{c}' is not skipped - --> $DIR/str-escape.rs:25:15 + --> $DIR/str-escape.rs:26:16 | -LL | let s = "a\ - | _______________^ +LL | let s = b"a\ + | ________________^ LL | | b"; | | ^- whitespace symbol '\u{c}' is not skipped | |____| diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed new file mode 100644 index 00000000000..86ac07a93a3 --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +struct A { + +} + +trait M { + fn foo(_a: Self); + fn bar(_a: Self); + fn baz(_a: i32); +} + +impl M for A { + fn foo(_a: Self) {} + fn bar(_a: A) {} + fn baz(_a: i32) {} +} + +fn main() { + let _a = A {}; + A::foo(_a); + //~^ ERROR no method named `foo` found + A::baz(0); + //~^ ERROR no method named `baz` found + + let _b = A {}; + A::bar(_b); + //~^ ERROR no method named `bar` found +} diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs new file mode 100644 index 00000000000..9a57ffb7740 --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.rs @@ -0,0 +1,29 @@ +// run-rustfix + +struct A { + +} + +trait M { + fn foo(_a: Self); + fn bar(_a: Self); + fn baz(_a: i32); +} + +impl M for A { + fn foo(_a: Self) {} + fn bar(_a: A) {} + fn baz(_a: i32) {} +} + +fn main() { + let _a = A {}; + _a.foo(); + //~^ ERROR no method named `foo` found + _a.baz(0); + //~^ ERROR no method named `baz` found + + let _b = A {}; + _b.bar(); + //~^ ERROR no method named `bar` found +} diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr new file mode 100644 index 00000000000..0df2b08d3be --- /dev/null +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr @@ -0,0 +1,60 @@ +error[E0599]: no method named `foo` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:21:8 + | +LL | struct A { + | -------- method `foo` not found for this struct +... +LL | _a.foo(); + | ---^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::foo(_a)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:8:5 + | +LL | fn foo(_a: Self); + | ^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `baz` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8 + | +LL | struct A { + | -------- method `baz` not found for this struct +... +LL | _a.baz(0); + | ---^^^--- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::baz(0)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:10:5 + | +LL | fn baz(_a: i32); + | ^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `bar` found for struct `A` in the current scope + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8 + | +LL | struct A { + | -------- method `bar` not found for this struct +... +LL | _b.bar(); + | ---^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `A::bar(_b)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `M` + --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:9:5 + | +LL | fn bar(_a: Self); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/symbol-mangling-version/bad-value.bad.stderr b/tests/ui/symbol-mangling-version/bad-value.bad.stderr index c36c73c6069..a12e5e241c0 100644 --- a/tests/ui/symbol-mangling-version/bad-value.bad.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.blank.stderr b/tests/ui/symbol-mangling-version/bad-value.blank.stderr index 0e70af5b8ff..95456587781 100644 --- a/tests/ui/symbol-mangling-version/bad-value.blank.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.blank.stderr @@ -1,2 +1,2 @@ -error: incorrect value `` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr index 77013b72b6c..325e47a281f 100644 --- a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr @@ -1,2 +1,2 @@ -error: codegen option `symbol-mangling-version` requires either `legacy` or `v0` (RFC 2603) (C symbol-mangling-version=<value>) +error: codegen option `symbol-mangling-version` requires one of: `legacy`, `v0` (RFC 2603), or `hashed` (C symbol-mangling-version=<value>) diff --git a/tests/ui/symbol-mangling-version/unstable.hashed.stderr b/tests/ui/symbol-mangling-version/unstable.hashed.stderr new file mode 100644 index 00000000000..f2ae18290f2 --- /dev/null +++ b/tests/ui/symbol-mangling-version/unstable.hashed.stderr @@ -0,0 +1,2 @@ +error: `-C symbol-mangling-version=hashed` requires `-Z unstable-options` + diff --git a/tests/ui/symbol-mangling-version/unstable.rs b/tests/ui/symbol-mangling-version/unstable.rs index df87a39cdfb..42750a64574 100644 --- a/tests/ui/symbol-mangling-version/unstable.rs +++ b/tests/ui/symbol-mangling-version/unstable.rs @@ -1,6 +1,9 @@ -// revisions: legacy legacy-ok +// revisions: legacy legacy-ok hashed hashed-ok // [legacy] compile-flags: -Csymbol-mangling-version=legacy // [legacy-ok] check-pass // [legacy-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy +// [hashed] compile-flags: -Csymbol-mangling-version=hashed +// [hashed-ok] check-pass +// [hashed-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=hashed fn main() {} diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index 592cfd970c6..bffad037fba 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -44,8 +44,9 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( | type must be known at this point | = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate: + - impl From<Char> for u32; - impl From<Ipv4Addr> for u32; - - impl From<NonZeroU32> for u32; + - impl From<NonZero<u32>> for u32; - impl From<bool> for u32; - impl From<char> for u32; - impl From<u16> for u32; diff --git a/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_cant_be_furthur_normalized.rs index 04d1b949692..04d1b949692 100644 --- a/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs +++ b/tests/ui/traits/next-solver/alias-relate/alias_eq_cant_be_furthur_normalized.rs diff --git a/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_dont_use_normalizes_to_if_substs_eq.rs index 48157192a10..48157192a10 100644 --- a/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs +++ b/tests/ui/traits/next-solver/alias-relate/alias_eq_dont_use_normalizes_to_if_substs_eq.rs diff --git a/tests/ui/traits/next-solver/alias_eq_simple.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_simple.rs index 21ad1a4fa3c..21ad1a4fa3c 100644 --- a/tests/ui/traits/next-solver/alias_eq_simple.rs +++ b/tests/ui/traits/next-solver/alias-relate/alias_eq_simple.rs diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.rs index 4717aa80499..4717aa80499 100644 --- a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs +++ b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.rs diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.stderr index 8c6840f72a7..8c6840f72a7 100644 --- a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr +++ b/tests/ui/traits/next-solver/alias-relate/alias_eq_substs_eq_not_intercrate.stderr diff --git a/tests/ui/traits/next-solver/tait-eq-proj-2.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj-2.rs index a3df053dd83..915643f1d2a 100644 --- a/tests/ui/traits/next-solver/tait-eq-proj-2.rs +++ b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj-2.rs @@ -3,7 +3,7 @@ #![feature(type_alias_impl_trait)] -// Similar to tests/ui/traits/next-solver/tait-eq-proj.rs +// Similar to tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs // but check the alias-sub relation in the other direction. type Tait = impl Iterator<Item = impl Sized>; diff --git a/tests/ui/traits/next-solver/tait-eq-proj.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs index 871e8e1e9fc..871e8e1e9fc 100644 --- a/tests/ui/traits/next-solver/tait-eq-proj.rs +++ b/tests/ui/traits/next-solver/alias-relate/tait-eq-proj.rs diff --git a/tests/ui/traits/next-solver/tait-eq-tait.rs b/tests/ui/traits/next-solver/alias-relate/tait-eq-tait.rs index 2629a124c3a..2629a124c3a 100644 --- a/tests/ui/traits/next-solver/tait-eq-tait.rs +++ b/tests/ui/traits/next-solver/alias-relate/tait-eq-tait.rs diff --git a/tests/ui/traits/next-solver/normalize-path-for-method.rs b/tests/ui/traits/next-solver/normalize-path-for-method.rs new file mode 100644 index 00000000000..b95454306cd --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-path-for-method.rs @@ -0,0 +1,18 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Mirror { + type Assoc; +} +impl<T> Mirror for T { + type Assoc = T; +} + +struct Foo; +impl Foo { + fn new() -> Self { Foo } +} + +fn main() { + <Foo as Mirror>::Assoc::new(); +} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 71b1502d775..932826519b7 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -16,6 +16,7 @@ fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc //~^ ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _` //~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _` //~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _` //~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index bad6820f738..e4f1f9cf022 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -1,3 +1,11 @@ +error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::<T::Assoc1>(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar` --> $DIR/recursive-self-normalization-2.rs:15:17 | @@ -35,7 +43,8 @@ LL | needs_bar::<T::Assoc1>(); | ^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs index 809a6a59ca6..32672c08c7e 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -12,6 +12,7 @@ fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() { //~^ ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _` //~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _` //~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _` + //~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _` //~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr index 80005d344ba..da5c8bde568 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -1,3 +1,11 @@ +error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::<T::Assoc>(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar` --> $DIR/recursive-self-normalization.rs:11:17 | @@ -35,7 +43,8 @@ LL | needs_bar::<T::Assoc>(); | ^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/temporary-ambiguity.rs b/tests/ui/traits/next-solver/temporary-ambiguity.rs deleted file mode 100644 index 6102de7e446..00000000000 --- a/tests/ui/traits/next-solver/temporary-ambiguity.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Znext-solver -// check-pass - -// Checks that we don't explode when we assemble >1 candidate for a goal. - -struct Wrapper<T>(T); - -trait Foo {} - -impl Foo for Wrapper<i32> {} - -impl Foo for Wrapper<()> {} - -fn needs_foo(_: impl Foo) {} - -fn main() { - let mut x = Default::default(); - let w = Wrapper(x); - needs_foo(w); - x = 1; - let _ = x; -} diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 97fbbdbf8f8..7e5b68353fb 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -11,7 +11,8 @@ LL | Ok(Err(123_i32)?) = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: <u8 as From<bool>> - <u8 as From<NonZeroU8>> + <u8 as From<NonZero<u8>>> + <u8 as From<Char>> = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` diff --git a/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs b/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs new file mode 100644 index 00000000000..39f0b9a02ee --- /dev/null +++ b/tests/ui/type-alias-impl-trait/struct-assignment-validity.rs @@ -0,0 +1,31 @@ +// compile-flags: -Zvalidate-mir +// check-pass + +// Check that we don't cause cycle errors when validating pre-`Reveal::All` MIR +// that assigns opaques through normalized projections. + +#![feature(impl_trait_in_assoc_type)] + +struct Bar; + +trait Trait { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo + where + Self::Assoc:, + { + let x: <Bar as Trait>::Assoc = (); + Foo { field: () } + } +} + +struct Foo { + field: <Bar as Trait>::Assoc, +} + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 264f6efd982..e57dd158374 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -476,7 +476,7 @@ of `ObligationCtxt`. """ cc = ["@lcnr", "@compiler-errors"] -[mentions."compiler/rustc_error_codes/src/error_codes.rs"] +[mentions."compiler/rustc_error_codes/src/lib.rs"] message = "Some changes occurred in diagnostic error codes" cc = ["@GuillaumeGomez"] @@ -652,6 +652,7 @@ compiler-team-contributors = [ "@TaKO8Ki", "@b-naber", "@nnethercote", + "@fmease", ] compiler = [ "compiler-team", @@ -662,7 +663,6 @@ libs = [ "@joshtriplett", "@Mark-Simulacrum", "@m-ou-se", - "@thomcc", ] bootstrap = [ "@Mark-Simulacrum", @@ -802,7 +802,7 @@ project-stable-mir = [ "/library/panic_unwind" = ["libs"] "/library/proc_macro" = ["@petrochenkov"] "/library/std" = ["libs"] -"/library/std/src/sys/pal/windows" = ["@ChrisDenton", "@thomcc"] +"/library/std/src/sys/pal/windows" = ["@ChrisDenton"] "/library/stdarch" = ["libs"] "/library/test" = ["libs"] "/src/bootstrap" = ["bootstrap"] |
