diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f95551d679b9..8b0a33841ad9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,9 +65,20 @@ jobs: - name: x86_64-gnu-tools os: ubuntu-20.04-16core-64gb env: {} + defaults: + run: + shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: + - if: "contains(matrix.os, 'windows')" + uses: msys2/setup-msys2@v2.22.0 + with: + msystem: "${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}" + update: false + release: true + path-type: inherit + install: "make dos2unix diffutils\n" - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code @@ -461,9 +472,20 @@ jobs: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler" SCRIPT: python x.py dist bootstrap --include-default-paths os: windows-2019-8core-32gb + defaults: + run: + shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: + - if: "contains(matrix.os, 'windows')" + uses: msys2/setup-msys2@v2.22.0 + with: + msystem: "${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}" + update: false + release: true + path-type: inherit + install: "make dos2unix diffutils\n" - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code @@ -589,9 +611,20 @@ jobs: env: CODEGEN_BACKENDS: "llvm,cranelift" os: ubuntu-20.04-16core-64gb + defaults: + run: + shell: "${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}" timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: + - if: "contains(matrix.os, 'windows')" + uses: msys2/setup-msys2@v2.22.0 + with: + msystem: "${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }}" + update: false + release: true + path-type: inherit + install: "make dos2unix diffutils\n" - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code diff --git a/Cargo.lock b/Cargo.lock index 8518bb2a91f1..4e00c9034bd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4101,6 +4101,7 @@ dependencies = [ "rustc_target", "rustc_trait_selection", "rustc_type_ir", + "smallvec", "tracing", "unicode-security", ] diff --git a/INSTALL.md b/INSTALL.md index b872d317e362..d7e0fd72044e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -145,10 +145,9 @@ toolchain. 1. Download the latest [MSYS2 installer][msys2] and go through the installer. -2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation - directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit - Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd - -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead.) +2. Start a MINGW64 or MINGW32 shell (depending on whether you want 32-bit + or 64-bit Rust) either from your start menu, or by running `mingw64.exe` + or `mingw32.exe` from your MSYS2 installation directory (e.g. `C:\msys64`). 3. From this terminal, install the required tools: @@ -157,8 +156,7 @@ toolchain. pacman -Sy pacman-mirrors # Install build tools needed for Rust. If you're building a 32-bit compiler, - # then replace "x86_64" below with "i686". If you've already got Git, Python, - # or CMake installed and in PATH you can remove them from this list. + # then replace "x86_64" below with "i686". # Note that it is important that you do **not** use the 'python2', 'cmake', # and 'ninja' packages from the 'msys2' subsystem. # The build has historically been known to fail with these packages. @@ -175,9 +173,21 @@ toolchain. 4. Navigate to Rust's source code (or clone it), then build it: ```sh - python x.py setup user && python x.py build && python x.py install + python x.py setup dist && python x.py build && python x.py install ``` +If you want to use the native versions of Git, Python, or CMake you can remove +them from the above pacman command and install them from another source. Make +sure that they're in your Windows PATH, and edit the relevant `mingw[32|64].ini` +file in your MSYS2 installation directory by uncommenting the line +`MSYS2_PATH_TYPE=inherit` to include them in your MSYS2 PATH. + +Using Windows native Python can be helpful if you get errors when building LLVM. +You may also want to use Git for Windows, as it is often *much* faster. Turning +off real-time protection in the Windows Virus & Threat protections settings can +also help with long run times (although note that it will automatically turn +itself back on after some time). + ### MSVC MSVC builds of Rust additionally require an installation of Visual Studio 2017 diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 50fe37dcdb6f..5ccc7d51066d 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -107,7 +107,7 @@ impl Lit { /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation. pub fn from_token(token: &Token) -> Option { match token.uninterpolate().kind { - Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), + Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), Interpolated(ref nt) if let NtExpr(expr) | NtLiteral(expr) = &nt.0 @@ -183,7 +183,7 @@ impl LitKind { } } -pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { +pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool { let ident_token = Token::new(Ident(name, is_raw), span); !ident_token.is_reserved_ident() @@ -214,7 +214,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { .contains(&name) } -fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { +fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool { let ident_token = Token::new(Ident(name, is_raw), span); !ident_token.is_reserved_ident() @@ -223,6 +223,24 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { .contains(&name) } +#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)] +pub enum IdentIsRaw { + No, + Yes, +} + +impl From for IdentIsRaw { + fn from(b: bool) -> Self { + if b { Self::Yes } else { Self::No } + } +} + +impl From for bool { + fn from(is_raw: IdentIsRaw) -> bool { + matches!(is_raw, IdentIsRaw::Yes) + } +} + // SAFETY: due to the `Clone` impl below, all fields of all variants other than // `Interpolated` must impl `Copy`. #[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -298,7 +316,7 @@ pub enum TokenKind { /// Do not forget about `NtIdent` when you want to match on identifiers. /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated identifiers in the same way. - Ident(Symbol, /* is_raw */ bool), + Ident(Symbol, IdentIsRaw), /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to @@ -411,7 +429,7 @@ impl Token { /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary. pub fn from_ast_ident(ident: Ident) -> Self { - Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) + Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span) } /// For interpolated tokens, returns a span of the fragment to which the interpolated @@ -567,7 +585,7 @@ impl Token { pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, - Ident(name, false) if name.is_bool_lit() => true, + Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, Interpolated(ref nt) => match &nt.0 { NtLiteral(_) => true, NtExpr(e) => match &e.kind { @@ -602,7 +620,7 @@ impl Token { /// Returns an identifier if this token is an identifier. #[inline] - pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> { + pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> { // We avoid using `Token::uninterpolate` here because it's slow. match &self.kind { &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), @@ -755,7 +773,7 @@ impl Token { /// Returns `true` if the token is a non-raw identifier for which `pred` holds. pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { - Some((id, false)) => pred(id), + Some((id, IdentIsRaw::No)) => pred(id), _ => false, } } @@ -806,7 +824,7 @@ impl Token { _ => return None, }, SingleQuote => match joint.kind { - Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))), + Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))), _ => return None, }, @@ -836,7 +854,7 @@ pub enum Nonterminal { NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Ident, /* is_raw */ bool), + NtIdent(Ident, IdentIsRaw), NtLifetime(Ident), NtLiteral(P), /// Stuff inside brackets for attributes diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 298c01a45674..adc3056cc292 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -656,7 +656,7 @@ impl TokenStream { DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Bracket, [ - TokenTree::token_alone(token::Ident(sym::doc, false), span), + TokenTree::token_alone(token::Ident(sym::doc, token::IdentIsRaw::No), span), TokenTree::token_alone(token::Eq, span), TokenTree::token_alone( TokenKind::lit(token::StrRaw(num_of_hashes), data, None), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 7ea0078ea3bb..6e1974f48b26 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -185,7 +185,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { // IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if` (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _)) - if !Ident::new(*sym, *span).is_reserved() || *is_raw => + if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) => { false } @@ -197,7 +197,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { || *sym == kw::Fn || *sym == kw::SelfUpper || *sym == kw::Pub - || *is_raw => + || matches!(is_raw, IdentIsRaw::Yes) => { false } @@ -731,7 +731,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::NtBlock(e) => self.block_to_string(e), token::NtStmt(e) => self.stmt_to_string(e), token::NtPat(e) => self.pat_to_string(e), - token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(), + &token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(e) => self.expr_to_string(e), token::NtVis(e) => self.vis_to_string(e), @@ -795,7 +795,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere /* Name components */ token::Ident(s, is_raw) => { - IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into() + IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into() } token::Lifetime(s) => s.to_string().into(), diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index c5a73c319957..263081ea19ea 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,3 +1,4 @@ +use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; @@ -416,7 +417,7 @@ fn parse_reg<'a>( ) -> PResult<'a, ast::InlineAsmRegOrRegClass> { p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; let result = match p.token.uninterpolate().kind { - token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), + token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { *explicit_reg = true; ast::InlineAsmRegOrRegClass::Reg(symbol) diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index d244897f8a5d..01821ee833f1 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,7 +1,6 @@ use rustc_ast::{ ptr::P, - token, - token::Delimiter, + token::{self, Delimiter, IdentIsRaw}, tokenstream::{DelimSpan, TokenStream, TokenTree}, BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, @@ -170,7 +169,10 @@ impl<'cx, 'a> Context<'cx, 'a> { ]; let captures = self.capture_decls.iter().flat_map(|cap| { [ - TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span), + TokenTree::token_joint_hidden( + token::Ident(cap.ident.name, IdentIsRaw::No), + cap.ident.span, + ), TokenTree::token_alone(token::Comma, self.span), ] }); diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 97d6b82de98c..bf4693cd5419 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -198,7 +198,7 @@ where match fields { Unnamed(fields, is_tuple) => { let path_expr = cx.expr_path(outer_pat_path); - if !*is_tuple { + if matches!(is_tuple, IsTuple::No) { path_expr } else { let fields = fields diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index d5a42566e191..0bd2d423a294 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -62,8 +62,8 @@ fn default_struct_substructure( let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new()); let expr = match summary { - Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident), - Unnamed(fields, true) => { + Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), + Unnamed(fields, IsTuple::Yes) => { let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); cx.expr_call_ident(trait_span, substr.type_ident, exprs) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6eeb028728c9..3ee4fded7499 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -286,10 +286,16 @@ pub struct FieldInfo { pub other_selflike_exprs: Vec>, } +#[derive(Copy, Clone)] +pub enum IsTuple { + No, + Yes, +} + /// Fields for a static method pub enum StaticFields { /// Tuple and unit structs/enum variants like this. - Unnamed(Vec, bool /*is tuple*/), + Unnamed(Vec, IsTuple), /// Normal structs/struct variants. Named(Vec<(Ident, Span)>), } @@ -1439,7 +1445,10 @@ impl<'a> TraitDef<'a> { } } - let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); + let is_tuple = match struct_def { + ast::VariantData::Tuple(..) => IsTuple::Yes, + _ => IsTuple::No, + }; match (just_spans.is_empty(), named_idents.is_empty()) { (false, false) => cx .dcx() diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index b66f7111ff00..3366378d38da 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -10,6 +10,7 @@ use rustc_ast::{ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::{self, *}; +use rustc_parse::parser::Recovered; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; @@ -111,9 +112,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< _ => return Err(err), } } - Ok(recovered) => { - assert!(recovered); - } + Ok(Recovered::Yes) => (), + Ok(Recovered::No) => unreachable!(), } } first = false; diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch new file mode 100644 index 000000000000..6af11e54d88a --- /dev/null +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch @@ -0,0 +1,47 @@ +From 9f65e742ba3e41474e6126c6c4469c48eaa6ca7e Mon Sep 17 00:00:00 2001 +From: Chris Denton +Date: Tue, 20 Feb 2024 16:01:40 -0300 +Subject: [PATCH] Don't use raw-dylib in std + +--- + library/std/src/sys/pal/windows/c.rs | 2 +- + library/std/src/sys/pal/windows/rand.rs | 3 +-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs +index ad8e01bfa9b..9ca8e4c16ce 100644 +--- a/library/std/src/sys/pal/windows/c.rs ++++ b/library/std/src/sys/pal/windows/c.rs +@@ -323,7 +323,7 @@ pub unsafe fn NtWriteFile( + + // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library. + cfg_if::cfg_if! { +-if #[cfg(not(target_vendor = "win7"))] { ++if #[cfg(any())] { + #[cfg(target_arch = "x86")] + #[link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")] + extern "system" { +diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs +index e427546222a..f2fe42a4d51 100644 +--- a/library/std/src/sys/pal/windows/rand.rs ++++ b/library/std/src/sys/pal/windows/rand.rs +@@ -2,7 +2,7 @@ + use core::mem; + use core::ptr; + +-#[cfg(not(target_vendor = "win7"))] ++#[cfg(any())] + #[inline] + pub fn hashmap_random_keys() -> (u64, u64) { + let mut v = (0, 0); +@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { + v + } + +-#[cfg(target_vendor = "win7")] + pub fn hashmap_random_keys() -> (u64, u64) { + use crate::ffi::c_void; + use crate::io; +-- +2.42.0.windows.2 + diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 1eac2157cac3..58c0765d8140 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2106,9 +2106,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(args[0].immediate()); } + #[derive(Copy, Clone)] + enum Sign { + Unsigned, + Signed, + } + use Sign::*; + enum Style { Float, - Int(/* is signed? */ bool), + Int(Sign), Unsupported, } @@ -2116,11 +2123,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // vectors of pointer-sized integers should've been // disallowed before here, so this unwrap is safe. ty::Int(i) => ( - Style::Int(true), + Style::Int(Signed), i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), ), ty::Uint(u) => ( - Style::Int(false), + Style::Int(Unsigned), u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), ), ty::Float(f) => (Style::Float, f.bit_width()), @@ -2128,11 +2135,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }; let (out_style, out_width) = match out_elem.kind() { ty::Int(i) => ( - Style::Int(true), + Style::Int(Signed), i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), ), ty::Uint(u) => ( - Style::Int(false), + Style::Int(Unsigned), u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), ), ty::Float(f) => (Style::Float, f.bit_width()), @@ -2140,31 +2147,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }; match (in_style, out_style) { - (Style::Int(in_is_signed), Style::Int(_)) => { + (Style::Int(sign), Style::Int(_)) => { return Ok(match in_width.cmp(&out_width) { Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), Ordering::Equal => args[0].immediate(), - Ordering::Less => { - if in_is_signed { - bx.sext(args[0].immediate(), llret_ty) - } else { - bx.zext(args[0].immediate(), llret_ty) - } - } + Ordering::Less => match sign { + Sign::Signed => bx.sext(args[0].immediate(), llret_ty), + Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty), + }, }); } - (Style::Int(in_is_signed), Style::Float) => { - return Ok(if in_is_signed { - bx.sitofp(args[0].immediate(), llret_ty) - } else { - bx.uitofp(args[0].immediate(), llret_ty) - }); + (Style::Int(Sign::Signed), Style::Float) => { + return Ok(bx.sitofp(args[0].immediate(), llret_ty)); } - (Style::Float, Style::Int(out_is_signed)) => { - return Ok(match (out_is_signed, name == sym::simd_as) { - (false, false) => bx.fptoui(args[0].immediate(), llret_ty), - (true, false) => bx.fptosi(args[0].immediate(), llret_ty), - (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty), + (Style::Int(Sign::Unsigned), Style::Float) => { + return Ok(bx.uitofp(args[0].immediate(), llret_ty)); + } + (Style::Float, Style::Int(sign)) => { + return Ok(match (sign, name == sym::simd_as) { + (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty), + (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty), + (_, true) => bx.cast_float_to_int( + matches!(sign, Sign::Signed), + args[0].immediate(), + llret_ty, + ), }); } (Style::Float, Style::Float) => { diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index e66cfbe6fb68..ffc8f782fd34 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -107,7 +107,7 @@ use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; -use rustc_ast::token::{Delimiter, Token, TokenKind}; +use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{DiagnosticMessage, MultiSpan}; @@ -409,7 +409,7 @@ fn check_nested_occurrences( match (state, tt) { ( NestedMacroState::Empty, - &TokenTree::Token(Token { kind: TokenKind::Ident(name, false), .. }), + &TokenTree::Token(Token { kind: TokenKind::Ident(name, IdentIsRaw::No), .. }), ) => { if name == kw::MacroRules { state = NestedMacroState::MacroRules; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c82609503c18..bf99e9e6d5cc 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,6 +8,7 @@ use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser} use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc}; use crate::mbe::transcribe::transcribe; +use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; @@ -1302,7 +1303,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, - Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes, + Ident(name, IdentIsRaw::No) if name == kw::If || name == kw::In => { + IsInFollow::Yes + } _ => IsInFollow::No(TOKENS), }, _ => IsInFollow::No(TOKENS), @@ -1313,7 +1316,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq => IsInFollow::Yes, - Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes, + Ident(name, IdentIsRaw::No) if name == kw::If || name == kw::In => { + IsInFollow::Yes + } _ => IsInFollow::No(TOKENS), }, _ => IsInFollow::No(TOKENS), @@ -1336,7 +1341,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { | BinOp(token::Shr) | Semi | BinOp(token::Or) => IsInFollow::Yes, - Ident(name, false) if name == kw::As || name == kw::Where => { + Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => { IsInFollow::Yes } _ => IsInFollow::No(TOKENS), @@ -1364,7 +1369,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { Comma => IsInFollow::Yes, - Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes, + Ident(_, IdentIsRaw::Yes) => IsInFollow::Yes, + Ident(name, _) if name != kw::Priv => IsInFollow::Yes, _ => { if token.can_begin_type() { IsInFollow::Yes diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 3ca0787ce8e1..84f7dc4771a9 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw}; use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree}; use rustc_ast::{LitIntType, LitKind}; use rustc_ast_pretty::pprust; @@ -142,7 +142,7 @@ fn parse_ident<'sess>( if let Some(tt) = iter.next() && let TokenTree::Token(token, _) = tt { - if let Some((elem, false)) = token.ident() { + if let Some((elem, IdentIsRaw::No)) = token.ident() { return Ok(elem); } let token_str = pprust::token_to_string(token); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 0fdfa5631389..ec1dd807d1a4 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -2,7 +2,7 @@ use crate::errors; use crate::mbe::macro_parser::count_metavar_decls; use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree}; -use rustc_ast::token::{self, Delimiter, Token}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw, Token}; use rustc_ast::{tokenstream, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::Features; @@ -222,7 +222,7 @@ fn parse_tree<'a>( Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => { let (ident, is_raw) = token.ident().unwrap(); let span = ident.span.with_lo(span.lo()); - if ident.name == kw::Crate && !is_raw { + if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) { TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span) } else { TokenTree::MetaVar(span, ident) diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index 7a888250ca16..0e07b41b43c7 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -2,6 +2,7 @@ use crate::tests::{ matches_codepattern, string_to_stream, with_error_checking_parse, with_expected_parse_error, }; +use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; @@ -74,9 +75,12 @@ fn string_to_tts_macro() { match tts { [ - TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name_macro_rules, IdentIsRaw::No), .. }, + _, + ), TokenTree::Token(Token { kind: token::Not, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }, _), + TokenTree::Token(Token { kind: token::Ident(name_zip, IdentIsRaw::No), .. }, _), TokenTree::Delimited(.., macro_delim, macro_tts), ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); @@ -90,7 +94,10 @@ fn string_to_tts_macro() { match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name, IdentIsRaw::No), .. }, + _, + ), ] if first_delim == &Delimiter::Parenthesis && name.as_str() == "a" => { } _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), @@ -99,7 +106,10 @@ fn string_to_tts_macro() { match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name, IdentIsRaw::No), .. }, + _, + ), ] if second_delim == &Delimiter::Parenthesis && name.as_str() == "a" => {} _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), @@ -119,8 +129,11 @@ fn string_to_tts_1() { let tts = string_to_stream("fn a(b: i32) { b; }".to_string()); let expected = TokenStream::new(vec![ - TokenTree::token_alone(token::Ident(kw::Fn, false), sp(0, 2)), - TokenTree::token_joint_hidden(token::Ident(Symbol::intern("a"), false), sp(3, 4)), + TokenTree::token_alone(token::Ident(kw::Fn, IdentIsRaw::No), sp(0, 2)), + TokenTree::token_joint_hidden( + token::Ident(Symbol::intern("a"), IdentIsRaw::No), + sp(3, 4), + ), TokenTree::Delimited( DelimSpan::from_pair(sp(4, 5), sp(11, 12)), // `JointHidden` because the `(` is followed immediately by @@ -128,10 +141,16 @@ fn string_to_tts_1() { DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Parenthesis, TokenStream::new(vec![ - TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(5, 6)), + TokenTree::token_joint( + token::Ident(Symbol::intern("b"), IdentIsRaw::No), + sp(5, 6), + ), TokenTree::token_alone(token::Colon, sp(6, 7)), // `JointHidden` because the `i32` is immediately followed by the `)`. - TokenTree::token_joint_hidden(token::Ident(sym::i32, false), sp(8, 11)), + TokenTree::token_joint_hidden( + token::Ident(sym::i32, IdentIsRaw::No), + sp(8, 11), + ), ]) .into(), ), @@ -143,7 +162,10 @@ fn string_to_tts_1() { DelimSpacing::new(Spacing::Alone, Spacing::Alone), Delimiter::Brace, TokenStream::new(vec![ - TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(15, 16)), + TokenTree::token_joint( + token::Ident(Symbol::intern("b"), IdentIsRaw::No), + sp(15, 16), + ), // `Alone` because the `;` is followed by whitespace. TokenTree::token_alone(token::Semi, sp(16, 17)), ]) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 62d0deb2d3a6..87ea8690ffef 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -1,4 +1,5 @@ use crate::base::ExtCtxt; +use ast::token::IdentIsRaw; use pm::bridge::{ server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, }; @@ -216,7 +217,9 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec op("?"), SingleQuote => op("'"), - Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })), + Ident(sym, is_raw) => { + trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span })) + } Lifetime(name) => { let ident = symbol::Ident::new(name, span).without_first_quote(); trees.extend([ @@ -238,7 +241,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec)> for Vec { trees.push(TokenTree::Ident(Ident { sym: ident.name, - is_raw: *is_raw, + is_raw: matches!(is_raw, IdentIsRaw::Yes), span: ident.span, })) } @@ -352,7 +355,7 @@ impl ToInternal> } TokenTree::Ident(self::Ident { sym, is_raw, span }) => { rustc.sess().symbol_gallery.insert(sym, span); - smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)] + smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw.into()), span)] } TokenTree::Literal(self::Literal { kind: self::LitKind::Integer, @@ -570,7 +573,7 @@ impl server::TokenStream for Rustc<'_, '_> { match &expr.kind { ast::ExprKind::Lit(token_lit) if token_lit.kind == token::Bool => { Ok(tokenstream::TokenStream::token_alone( - token::Ident(token_lit.symbol, false), + token::Ident(token_lit.symbol, IdentIsRaw::No), expr.span, )) } diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs index 91c4dd732e3a..78795e86fd5d 100644 --- a/compiler/rustc_expand/src/tokenstream/tests.rs +++ b/compiler/rustc_expand/src/tokenstream/tests.rs @@ -1,6 +1,6 @@ use crate::tests::string_to_stream; -use rustc_ast::token; +use rustc_ast::token::{self, IdentIsRaw}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_span::create_default_session_globals_then; use rustc_span::{BytePos, Span, Symbol}; @@ -86,7 +86,8 @@ fn test_diseq_1() { fn test_is_empty() { create_default_session_globals_then(|| { let test0 = TokenStream::default(); - let test1 = TokenStream::token_alone(token::Ident(Symbol::intern("a"), false), sp(0, 1)); + let test1 = + TokenStream::token_alone(token::Ident(Symbol::intern("a"), IdentIsRaw::No), sp(0, 1)); let test2 = string_to_ts("foo(bar::baz)"); assert_eq!(test0.is_empty(), true); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 18f6ae35054b..1b2993dabdb8 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -84,6 +84,8 @@ declare_features! ( (accepted, cfg_doctest, "1.40.0", Some(62210)), /// Enables `#[cfg(panic = "...")]` config key. (accepted, cfg_panic, "1.60.0", Some(77443)), + /// Allows `cfg(target_abi = "...")`. + (accepted, cfg_target_abi, "CURRENT_RUSTC_VERSION", Some(80970)), /// Allows `cfg(target_feature = "...")`. (accepted, cfg_target_feature, "1.27.0", Some(29717)), /// Allows `cfg(target_vendor = "...")`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 003baf071b8c..6cb41be7c943 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -25,7 +25,6 @@ pub type GatedCfg = (Symbol, Symbol, GateFn); const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), - (sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), ( sym::target_has_atomic_equal_alignment, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93c183a65ef3..8eea4b7d8a8d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -373,8 +373,6 @@ declare_features! ( (unstable, cfg_sanitize, "1.41.0", Some(39699)), /// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`. (unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)), - /// Allows `cfg(target_abi = "...")`. - (unstable, cfg_target_abi, "1.55.0", Some(80970)), /// Allows `cfg(target(abi = "..."))`. (unstable, cfg_target_compact, "1.63.0", Some(96901)), /// Allows `cfg(target_has_atomic_load_store = "...")`. 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 9e1e884d9769..3aef29f4ae4d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -24,6 +24,11 @@ struct InherentOverlapChecker<'tcx> { tcx: TyCtxt<'tcx>, } +rustc_index::newtype_index! { + #[orderable] + pub struct RegionId {} +} + impl<'tcx> InherentOverlapChecker<'tcx> { /// Checks whether any associated items in impls 1 and 2 share the same identifier and /// namespace. @@ -205,11 +210,6 @@ impl<'tcx> InherentOverlapChecker<'tcx> { // This is advantageous to running the algorithm over the // entire graph when there are many connected regions. - rustc_index::newtype_index! { - #[orderable] - pub struct RegionId {} - } - struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, impl_blocks: FxHashSet, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 07bbaa1926ed..b46a67d08eb0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -1,14 +1,13 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. +use crate::errors; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; use rustc_span::Span; -use rustc_trait_selection::traits; - -use crate::errors; +use rustc_trait_selection::traits::{self, IsFirstInputType}; #[instrument(skip(tcx), level = "debug")] pub(crate) fn orphan_check_impl( @@ -288,7 +287,7 @@ fn emit_orphan_check_error<'tcx>( (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()); let mut sugg = None; for &(mut ty, is_target_ty) in &tys { - let span = if is_target_ty { + let span = if matches!(is_target_ty, IsFirstInputType::Yes) { // Point at `D` in `impl for C in D` self_ty_span } else { @@ -321,7 +320,8 @@ fn emit_orphan_check_error<'tcx>( } } - let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty; + let is_foreign = + !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); match &ty.kind() { ty::Slice(_) => { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 351ac2eb7702..f70bb8c4289f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -640,16 +640,30 @@ pub(super) fn implied_predicates_with_filter( // Now require that immediate supertraits are converted, which will, in // turn, reach indirect supertraits, so we detect cycles now instead of - // overflowing during elaboration. - if matches!(filter, PredicateFilter::SelfOnly) { - for &(pred, span) in implied_bounds { - debug!("superbound: {:?}", pred); - if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() - && bound.polarity == ty::ImplPolarity::Positive - { - tcx.at(span).super_predicates_of(bound.def_id()); + // overflowing during elaboration. Same for implied predicates, which + // make sure we walk into associated type bounds. + match filter { + PredicateFilter::SelfOnly => { + for &(pred, span) in implied_bounds { + debug!("superbound: {:?}", pred); + if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() + && bound.polarity == ty::ImplPolarity::Positive + { + tcx.at(span).super_predicates_of(bound.def_id()); + } } } + PredicateFilter::SelfAndAssociatedTypeBounds => { + for &(pred, span) in implied_bounds { + debug!("superbound: {:?}", pred); + if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() + && bound.polarity == ty::ImplPolarity::Positive + { + tcx.at(span).implied_predicates_of(bound.def_id()); + } + } + } + _ => {} } ty::GenericPredicates { parent: None, predicates: implied_bounds } diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index fa1133e7780f..2271321b8bf2 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -23,6 +23,7 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" unicode-security = "0.1.0" # tidy-alphabetical-end diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 496ffeddbffb..f89cb8ed8b61 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -414,6 +414,29 @@ lint_non_fmt_panic_unused = } .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally +lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` + +lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +lint_non_local_definitions_impl = non-local `impl` definition, they should be avoided as they go against expectation + .help = + move this `impl` block outside the of the current {$body_kind_descr} {$depth -> + [one] `{$body_name}` + *[other] `{$body_name}` and up {$depth} bodies + } + .non_local = an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module and anon-const at the same nesting as the trait or type + .const_anon = use a const-anon item to suppress this lint + +lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, they should be avoided as they go against expectation + .help = + remove the `#[macro_export]` or move this `macro_rules!` outside the of the current {$body_kind_descr} {$depth -> + [one] `{$body_name}` + *[other] `{$body_name}` and up {$depth} bodies + } + .non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module + lint_non_snake_case = {$sort} `{$name}` should have a snake case name .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier .cannot_convert_note = `{$sc}` cannot be used as a raw identifier diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 3a5c585366a3..993b1d739a13 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -70,11 +70,15 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { // Check if the method call actually calls the libcore // `IntoIterator::into_iter`. - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - match cx.tcx.trait_of_item(def_id) { - Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {} - _ => return, - }; + let trait_id = cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .and_then(|did| cx.tcx.trait_of_item(did)); + if trait_id.is_none() + || !cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id.unwrap()) + { + return; + } // As this is a method call expression, we have at least one argument. let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 92f7497362e0..9f73d2e68125 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1825,7 +1825,7 @@ impl KeywordIdents { match tt { // Only report non-raw idents. TokenTree::Token(token, _) => { - if let Some((ident, false)) = token.ident() { + if let Some((ident, token::IdentIsRaw::No)) = token.ident() { self.check_ident_token(cx, UnderMacro(true), ident); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d8e12c04f753..0e446e09d412 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -70,6 +70,7 @@ mod methods; mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; +mod non_local_def; mod nonstandard_style; mod noop_method_call; mod opaque_hidden_inferred_bound; @@ -105,6 +106,7 @@ use methods::*; use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; +use non_local_def::*; use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; @@ -229,6 +231,7 @@ late_lint_methods!( MissingDebugImplementations: MissingDebugImplementations, MissingDoc: MissingDoc, AsyncFnInTrait: AsyncFnInTrait, + NonLocalDefinitions: NonLocalDefinitions::default(), ] ] ); @@ -527,6 +530,11 @@ fn register_builtins(store: &mut LintStore) { "no longer needed, see #93367 \ for more information", ); + store.register_removed( + "const_patterns_without_partial_eq", + "converted into hard error, see RFC #3535 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d73b9015ce1d..d8a0b75f8bd1 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1334,6 +1334,45 @@ pub struct SuspiciousDoubleRefCloneDiag<'a> { pub ty: Ty<'a>, } +// non_local_defs.rs +#[derive(LintDiagnostic)] +pub enum NonLocalDefinitionsDiag { + #[diag(lint_non_local_definitions_impl)] + #[help] + #[note(lint_non_local)] + #[note(lint_exception)] + #[note(lint_non_local_definitions_deprecation)] + Impl { + depth: u32, + body_kind_descr: &'static str, + body_name: String, + #[subdiagnostic] + cargo_update: Option, + #[suggestion(lint_const_anon, code = "_", applicability = "machine-applicable")] + const_anon: Option, + }, + #[diag(lint_non_local_definitions_macro_rules)] + #[help] + #[note(lint_non_local)] + #[note(lint_exception)] + #[note(lint_non_local_definitions_deprecation)] + MacroRules { + depth: u32, + body_kind_descr: &'static str, + body_name: String, + #[subdiagnostic] + cargo_update: Option, + }, +} + +#[derive(Subdiagnostic)] +#[note(lint_non_local_definitions_cargo_update)] +pub struct NonLocalDefinitionsCargoUpdateNote { + pub macro_kind: &'static str, + pub macro_name: Symbol, + pub crate_name: Symbol, +} + // pass_by_value.rs #[derive(LintDiagnostic)] #[diag(lint_pass_by_value)] diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs new file mode 100644 index 000000000000..6cb6fd1cbd55 --- /dev/null +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -0,0 +1,222 @@ +use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind}; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; +use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind}; + +use smallvec::{smallvec, SmallVec}; + +use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]` + /// macro inside bodies (functions, enum discriminant, ...). + /// + /// ### Example + /// + /// ```rust + /// trait MyTrait {} + /// struct MyStruct; + /// + /// fn foo() { + /// impl MyTrait for MyStruct {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating non-local definitions go against expectation and can create discrepancies + /// in tooling. It should be avoided. It may become deny-by-default in edition 2024 + /// and higher, see see the tracking issue . + /// + /// An `impl` definition is non-local if it is nested inside an item and neither + /// the type nor the trait are at the same nesting level as the `impl` block. + /// + /// All nested bodies (functions, enum discriminant, array length, consts) (expect for + /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. + pub NON_LOCAL_DEFINITIONS, + Warn, + "checks for non-local definitions", + report_in_external_macro +} + +#[derive(Default)] +pub struct NonLocalDefinitions { + body_depth: u32, +} + +impl_lint_pass!(NonLocalDefinitions => [NON_LOCAL_DEFINITIONS]); + +// FIXME(Urgau): Figure out how to handle modules nested in bodies. +// It's currently not handled by the current logic because modules are not bodies. +// They don't even follow the correct order (check_body -> check_mod -> check_body_post) +// instead check_mod is called after every body has been handled. + +impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { + fn check_body(&mut self, _cx: &LateContext<'tcx>, _body: &'tcx Body<'tcx>) { + self.body_depth += 1; + } + + fn check_body_post(&mut self, _cx: &LateContext<'tcx>, _body: &'tcx Body<'tcx>) { + self.body_depth -= 1; + } + + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if self.body_depth == 0 { + return; + } + + let parent = cx.tcx.parent(item.owner_id.def_id.into()); + let parent_def_kind = cx.tcx.def_kind(parent); + let parent_opt_item_name = cx.tcx.opt_item_name(parent); + + // Per RFC we (currently) ignore anon-const (`const _: Ty = ...`) in top-level module. + if self.body_depth == 1 + && parent_def_kind == DefKind::Const + && parent_opt_item_name == Some(kw::Underscore) + { + return; + } + + let cargo_update = || { + let oexpn = item.span.ctxt().outer_expn_data(); + if let Some(def_id) = oexpn.macro_def_id + && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind + && def_id.krate != LOCAL_CRATE + && std::env::var_os("CARGO").is_some() + { + Some(NonLocalDefinitionsCargoUpdateNote { + macro_kind: macro_kind.descr(), + macro_name, + crate_name: cx.tcx.crate_name(def_id.krate), + }) + } else { + None + } + }; + + match item.kind { + ItemKind::Impl(impl_) => { + // The RFC states: + // + // > An item nested inside an expression-containing item (through any + // > level of nesting) may not define an impl Trait for Type unless + // > either the **Trait** or the **Type** is also nested inside the + // > same expression-containing item. + // + // To achieve this we get try to get the paths of the _Trait_ and + // _Type_, and we look inside thoses paths to try a find in one + // of them a type whose parent is the same as the impl definition. + // + // If that's the case this means that this impl block declaration + // is using local items and so we don't lint on it. + + // We also ignore anon-const in item by including the anon-const + // parent as well; and since it's quite uncommon, we use smallvec + // to avoid unnecessary heap allocations. + let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const + && parent_opt_item_name == Some(kw::Underscore) + { + smallvec![parent, cx.tcx.parent(parent)] + } else { + smallvec![parent] + }; + + let self_ty_has_local_parent = match impl_.self_ty.kind { + TyKind::Path(QPath::Resolved(_, ty_path)) => { + path_has_local_parent(ty_path, cx, &*local_parents) + } + TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { + path_has_local_parent( + principle_poly_trait_ref.trait_ref.path, + cx, + &*local_parents, + ) + } + TyKind::TraitObject([], _, _) + | TyKind::InferDelegation(_, _) + | TyKind::Slice(_) + | TyKind::Array(_, _) + | TyKind::Ptr(_) + | TyKind::Ref(_, _) + | TyKind::BareFn(_) + | TyKind::Never + | TyKind::Tup(_) + | TyKind::Path(_) + | TyKind::AnonAdt(_) + | TyKind::OpaqueDef(_, _, _) + | TyKind::Typeof(_) + | TyKind::Infer + | TyKind::Err(_) => false, + }; + + let of_trait_has_local_parent = impl_ + .of_trait + .map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents)) + .unwrap_or(false); + + // If none of them have a local parent (LOGICAL NOR) this means that + // this impl definition is a non-local definition and so we lint on it. + if !(self_ty_has_local_parent || of_trait_has_local_parent) { + let const_anon = if self.body_depth == 1 + && parent_def_kind == DefKind::Const + && parent_opt_item_name != Some(kw::Underscore) + && let Some(parent) = parent.as_local() + && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) + && let ItemKind::Const(ty, _, _) = item.kind + && let TyKind::Tup(&[]) = ty.kind + { + Some(item.ident.span) + } else { + None + }; + + cx.emit_span_lint( + NON_LOCAL_DEFINITIONS, + item.span, + NonLocalDefinitionsDiag::Impl { + depth: self.body_depth, + body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), + body_name: parent_opt_item_name + .map(|s| s.to_ident_string()) + .unwrap_or_else(|| "".to_string()), + cargo_update: cargo_update(), + const_anon, + }, + ) + } + } + ItemKind::Macro(_macro, MacroKind::Bang) + if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => + { + cx.emit_span_lint( + NON_LOCAL_DEFINITIONS, + item.span, + NonLocalDefinitionsDiag::MacroRules { + depth: self.body_depth, + body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), + body_name: parent_opt_item_name + .map(|s| s.to_ident_string()) + .unwrap_or_else(|| "".to_string()), + cargo_update: cargo_update(), + }, + ) + } + _ => {} + } + } +} + +/// Given a path and a parent impl def id, this checks if the if parent resolution +/// def id correspond to the def id of the parent impl definition. +/// +/// Given this path, we will look at the path (and ignore any generic args): +/// +/// ```text +/// std::convert::PartialEq> +/// ^^^^^^^^^^^^^^^^^^^^^^^ +/// ``` +fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool { + path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did))) +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 84a050a242a6..1cddb45428c8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -32,7 +32,6 @@ declare_lint_pass! { CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, - CONST_PATTERNS_WITHOUT_PARTIAL_EQ, DEAD_CODE, DEPRECATED, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, @@ -2342,57 +2341,6 @@ declare_lint! { }; } -declare_lint! { - /// The `const_patterns_without_partial_eq` lint detects constants that are used in patterns, - /// whose type does not implement `PartialEq`. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(const_patterns_without_partial_eq)] - /// - /// trait EnumSetType { - /// type Repr; - /// } - /// - /// enum Enum8 { } - /// impl EnumSetType for Enum8 { - /// type Repr = u8; - /// } - /// - /// #[derive(PartialEq, Eq)] - /// struct EnumSet { - /// __enumset_underlying: T::Repr, - /// } - /// - /// const CONST_SET: EnumSet = EnumSet { __enumset_underlying: 3 }; - /// - /// fn main() { - /// match CONST_SET { - /// CONST_SET => { /* ok */ } - /// _ => panic!("match fell through?"), - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Previous versions of Rust accepted constants in patterns, even if those constants' types - /// did not have `PartialEq` implemented. The compiler falls back to comparing the value - /// field-by-field. In the future we'd like to ensure that pattern matching always - /// follows `PartialEq` semantics, so that trait bound will become a requirement for - /// matching on constants. - pub CONST_PATTERNS_WITHOUT_PARTIAL_EQ, - Warn, - "constant in pattern does not implement `PartialEq`", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #116122 ", - }; -} - declare_lint! { /// The `ambiguous_associated_items` lint detects ambiguity between /// [associated items] and [enum variants]. diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 33dffe6998a1..044bbadf41c5 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -55,7 +55,8 @@ use synstructure::Structure; /// /// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`: /// -pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { +pub fn session_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { + s.underscore_const(true); DiagnosticDerive::new(s).into_tokens() } @@ -101,7 +102,8 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// /// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: /// -pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { +pub fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { + s.underscore_const(true); LintDiagnosticDerive::new(s).into_tokens() } @@ -151,6 +153,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident }); /// ``` -pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream { +pub fn session_subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream { + s.underscore_const(true); SubdiagnosticDeriveBuilder::new().into_tokens(s) } diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index a6396ba687d1..6b3210cad7be 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -74,6 +74,8 @@ fn hash_stable_derive_with_mode( HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX), }; + s.underscore_const(true); + // no_context impl is able to derive by-field, which is closer to a perfect derive. s.add_bounds(match mode { HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics, diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index 3dedd88fb19b..f7a84ba1510d 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -4,6 +4,7 @@ use syn::parse_quote; pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); s.bind_with(|_| synstructure::BindStyle::Move); + s.underscore_const(true); let tcx: syn::Lifetime = parse_quote!('tcx); let newtcx: syn::GenericParam = parse_quote!('__lifted); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 98b53945b911..5fa11d22f0e7 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -15,6 +15,7 @@ pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder #bound }); s.add_bounds(synstructure::AddBounds::Fields); + s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -26,6 +27,7 @@ pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: s.add_impl_generic(parse_quote! { '__a }); let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -34,6 +36,7 @@ pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_span::SpanDecoder}); s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -42,12 +45,13 @@ pub fn decodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macr let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder}); s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); decodable_body(s, decoder_ty) } fn decodable_body( - s: synstructure::Structure<'_>, + mut s: synstructure::Structure<'_>, decoder_ty: TokenStream, ) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -93,6 +97,7 @@ fn decodable_body( } } }; + s.underscore_const(true); s.bound_impl( quote!(::rustc_serialize::Decodable<#decoder_ty>), @@ -130,6 +135,7 @@ pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder #bound }); s.add_bounds(synstructure::AddBounds::Fields); + s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -141,6 +147,7 @@ pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: s.add_impl_generic(parse_quote! { '__a }); let encoder_ty = quote! { EncodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); encodable_body(s, encoder_ty, true) } @@ -149,6 +156,7 @@ pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder}); s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -157,6 +165,7 @@ pub fn encodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macr let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder}); s.add_bounds(synstructure::AddBounds::Generics); + s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -170,6 +179,7 @@ fn encodable_body( panic!("cannot derive on union") } + s.underscore_const(true); s.bind_with(|binding| { // Handle the lack of a blanket reference impl. if let syn::Type::Reference(_) = binding.ast().ty { diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 5ee4d8793135..5617c53b119e 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -6,6 +6,8 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: panic!("cannot derive on union") } + s.underscore_const(true); + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { s.add_impl_generic(parse_quote! { 'tcx }); } diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index dcd505a105e5..c8430380345b 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -6,6 +6,8 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: panic!("cannot derive on union") } + s.underscore_const(true); + // ignore fields with #[type_visitable(ignore)] s.filter(|bi| { let mut ignored = false; diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 48b93ce0ac5c..101f1cb9f2f5 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -767,6 +767,14 @@ pub struct TypeNotStructural<'tcx> { pub non_sm_ty: Ty<'tcx>, } +#[derive(Diagnostic)] +#[diag(mir_build_non_partial_eq_match)] +pub struct TypeNotPartialEq<'tcx> { + #[primary_span] + pub span: Span, + pub non_peq_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(mir_build_invalid_pattern)] pub struct InvalidPattern<'tcx> { @@ -822,12 +830,6 @@ pub struct NontrivialStructuralMatch<'tcx> { pub non_sm_ty: Ty<'tcx>, } -#[derive(LintDiagnostic)] -#[diag(mir_build_non_partial_eq_match)] -pub struct NonPartialEqMatch<'tcx> { - pub non_peq_ty: Ty<'tcx>, -} - #[derive(Diagnostic)] #[diag(mir_build_pattern_not_covered, code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index c77c80d9f4b2..09727f9b71be 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -16,7 +16,7 @@ use std::cell::Cell; use super::PatCtxt; use crate::errors::{ - IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern, + IndirectStructuralMatch, InvalidPattern, NaNPattern, PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern, }; @@ -208,15 +208,12 @@ impl<'tcx> ConstToPat<'tcx> { ); } - // Always check for `PartialEq`, even if we emitted other lints. (But not if there were - // any errors.) This ensures it shows up in cargo's future-compat reports as well. + // Always check for `PartialEq` if we had no other errors yet. if !self.type_has_partial_eq_impl(cv.ty()) { - self.tcx().emit_node_span_lint( - lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ, - self.id, - self.span, - NonPartialEqMatch { non_peq_ty: cv.ty() }, - ); + let err = TypeNotPartialEq { span: self.span, non_peq_ty: cv.ty() }; + let e = self.tcx().dcx().emit_err(err); + let kind = PatKind::Error(e); + return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); } } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index a9cd688c3155..7cab66509948 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -585,20 +585,32 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { val.into() } - Aggregate(ref kind, ref fields) => Value::Aggregate { - fields: fields - .iter() - .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)) - .collect(), - variant: match **kind { - AggregateKind::Adt(_, variant, _, _, _) => variant, - AggregateKind::Array(_) - | AggregateKind::Tuple - | AggregateKind::Closure(_, _) - | AggregateKind::Coroutine(_, _) - | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), - }, - }, + Aggregate(ref kind, ref fields) => { + // Do not const pop union fields as they can be + // made to produce values that don't match their + // underlying layout's type (see ICE #121534). + // If the last element of the `Adt` tuple + // is `Some` it indicates the ADT is a union + if let AggregateKind::Adt(_, _, _, _, Some(_)) = **kind { + return None; + }; + Value::Aggregate { + fields: fields + .iter() + .map(|field| { + self.eval_operand(field).map_or(Value::Uninit, Value::Immediate) + }) + .collect(), + variant: match **kind { + AggregateKind::Adt(_, variant, _, _, _) => variant, + AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), + }, + } + } Repeat(ref op, n) => { trace!(?op, ?n); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index c768ea93b5fe..dc9f5bad765f 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -4,7 +4,7 @@ use crate::errors; use crate::lexer::unicode_chars::UNICODE_ARRAY; use crate::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; -use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::{codes::*, Applicability, DiagCtxt, DiagnosticBuilder, StashKey}; @@ -181,7 +181,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { self.dcx().emit_err(errors::CannotBeRawIdent { span, ident: sym }); } self.sess.raw_identifier_spans.push(span); - token::Ident(sym, true) + token::Ident(sym, IdentIsRaw::Yes) } rustc_lexer::TokenKind::UnknownPrefix => { self.report_unknown_prefix(start); @@ -201,7 +201,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let span = self.mk_sp(start, self.pos); self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default() .push(span); - token::Ident(sym, false) + token::Ident(sym, IdentIsRaw::No) } // split up (raw) c string literals to an ident and a string literal when edition < 2021. rustc_lexer::TokenKind::Literal { @@ -339,7 +339,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); self.sess.symbol_gallery.insert(sym, span); - token::Ident(sym, false) + token::Ident(sym, IdentIsRaw::No) } /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index a136abaa28bb..3b4e05332fac 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -307,7 +307,7 @@ pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ // fancier error recovery to it, as there will be less overall work to do this way. const ASCII_ARRAY: &[(&str, &str, Option)] = &[ (" ", "Space", None), - ("_", "Underscore", Some(token::Ident(kw::Underscore, false))), + ("_", "Underscore", Some(token::Ident(kw::Underscore, token::IdentIsRaw::No))), ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))), (",", "Comma", Some(token::Comma)), (";", "Semicolon", Some(token::Semi)), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 0cc2170714c4..517e3d827876 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -21,6 +21,8 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::parser; use crate::parser::attr::InnerAttrPolicy; +use ast::token::IdentIsRaw; +use parser::Recovered; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; @@ -264,7 +266,7 @@ impl<'a> Parser<'a> { pub(super) fn expected_ident_found( &mut self, recover: bool, - ) -> PResult<'a, (Ident, /* is_raw */ bool)> { + ) -> PResult<'a, (Ident, IdentIsRaw)> { if let TokenKind::DocComment(..) = self.prev_token.kind { return Err(self.dcx().create_err(DocCommentDoesNotDocumentAnything { span: self.prev_token.span, @@ -290,11 +292,11 @@ impl<'a> Parser<'a> { let bad_token = self.token.clone(); // suggest prepending a keyword in identifier position with `r#` - let suggest_raw = if let Some((ident, false)) = self.token.ident() + let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident() && ident.is_raw_guess() && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) { - recovered_ident = Some((ident, true)); + recovered_ident = Some((ident, IdentIsRaw::Yes)); // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` @@ -320,7 +322,7 @@ impl<'a> Parser<'a> { let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { let (invalid, valid) = self.token.span.split_at(len as u32); - recovered_ident = Some((Ident::new(valid_portion, valid), false)); + recovered_ident = Some((Ident::new(valid_portion, valid), IdentIsRaw::No)); HelpIdentifierStartsWithNumber { num_span: invalid } }); @@ -429,7 +431,7 @@ impl<'a> Parser<'a> { &mut self, edible: &[TokenKind], inedible: &[TokenKind], - ) -> PResult<'a, bool /* recovered */> { + ) -> PResult<'a, Recovered> { debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible); fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); @@ -532,7 +534,7 @@ impl<'a> Parser<'a> { sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); self.bump(); - return Ok(true); + return Ok(Recovered::Yes); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(Delimiter::Brace) || ((t.can_begin_expr() || t.can_begin_item()) @@ -556,7 +558,7 @@ impl<'a> Parser<'a> { unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); - return Ok(true); + return Ok(Recovered::Yes); } } @@ -653,9 +655,9 @@ impl<'a> Parser<'a> { // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying // that in the parser requires unbounded lookahead, so we only add a hint to the existing // error rather than replacing it entirely. - if ((self.prev_token.kind == TokenKind::Ident(sym::c, false) + if ((self.prev_token.kind == TokenKind::Ident(sym::c, IdentIsRaw::No) && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. }))) - || (self.prev_token.kind == TokenKind::Ident(sym::cr, false) + || (self.prev_token.kind == TokenKind::Ident(sym::cr, IdentIsRaw::No) && matches!( &self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound @@ -711,7 +713,7 @@ impl<'a> Parser<'a> { if self.check_too_many_raw_str_terminators(&mut err) { if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) { err.emit(); - return Ok(true); + return Ok(Recovered::Yes); } else { return Err(err); } @@ -1223,7 +1225,7 @@ impl<'a> Parser<'a> { |p| p.parse_generic_arg(None), ); match x { - Ok((_, _, false)) => { + Ok((_, _, Recovered::No)) => { if self.eat(&token::Gt) { // We made sense of it. Improve the error message. e.span_suggestion_verbose( @@ -1247,7 +1249,7 @@ impl<'a> Parser<'a> { } } } - Ok((_, _, true)) => {} + Ok((_, _, Recovered::Yes)) => {} Err(err) => { err.cancel(); } @@ -1286,7 +1288,7 @@ impl<'a> Parser<'a> { err: &mut ComparisonOperatorsCannotBeChained, inner_op: &Expr, outer_op: &Spanned, - ) -> bool /* advanced the cursor */ { + ) -> Recovered { if let ExprKind::Binary(op, l1, r1) = &inner_op.kind { if let ExprKind::Field(_, ident) = l1.kind && ident.as_str().parse::().is_err() @@ -1294,7 +1296,7 @@ impl<'a> Parser<'a> { { // The parser has encountered `foo.bar Parser<'a> { span: inner_op.span.shrink_to_hi(), middle_term: expr_to_str(r1), }); - false // Keep the current parse behavior, where the AST is `(x < y) < z`. + Recovered::No // Keep the current parse behavior, where the AST is `(x < y) < z`. } // `x == y < z` (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => { @@ -1327,12 +1329,12 @@ impl<'a> Parser<'a> { left: r1.span.shrink_to_lo(), right: r2.span.shrink_to_hi(), }); - true + Recovered::Yes } Err(expr_err) => { expr_err.cancel(); self.restore_snapshot(snapshot); - false + Recovered::Yes } } } @@ -1347,19 +1349,19 @@ impl<'a> Parser<'a> { left: l1.span.shrink_to_lo(), right: r1.span.shrink_to_hi(), }); - true + Recovered::Yes } Err(expr_err) => { expr_err.cancel(); self.restore_snapshot(snapshot); - false + Recovered::No } } } - _ => false, + _ => Recovered::No, }; } - false + Recovered::No } /// Produces an error if comparison operators are chained (RFC #558). @@ -1487,8 +1489,9 @@ impl<'a> Parser<'a> { // If it looks like a genuine attempt to chain operators (as opposed to a // misformatted turbofish, for instance), suggest a correct form. - if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op) - { + let recovered = self + .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); + if matches!(recovered, Recovered::Yes) { self.dcx().emit_err(err); mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } else { @@ -1500,7 +1503,7 @@ impl<'a> Parser<'a> { let recover = self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); self.dcx().emit_err(err); - if recover { + if matches!(recover, Recovered::Yes) { return mk_err_expr(self, inner_op.span.to(self.prev_token.span)); } } @@ -1840,10 +1843,7 @@ impl<'a> Parser<'a> { /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a /// closing delimiter. - pub(super) fn unexpected_try_recover( - &mut self, - t: &TokenKind, - ) -> PResult<'a, bool /* recovered */> { + pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> { let token_str = pprust::token_kind_to_string(t); let this_token_str = super::token_descr(&self.token); let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8826c06bebde..1ad637451b19 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3,13 +3,14 @@ use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, - SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, + AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions, + SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken, }; use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::mut_visit::{noop_visit_expr, MutVisitor}; +use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; @@ -126,7 +127,7 @@ impl<'a> Parser<'a> { match self.parse_expr_res(restrictions, None) { Ok(expr) => Ok(expr), Err(err) => match self.token.ident() { - Some((Ident { name: kw::Underscore, .. }, false)) + Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` @@ -457,7 +458,9 @@ impl<'a> Parser<'a> { return None; } (Some(op), _) => (op, self.token.span), - (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { + (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No))) + if self.may_recover() => + { self.dcx().emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "and".into(), @@ -465,7 +468,7 @@ impl<'a> Parser<'a> { }); (AssocOp::LAnd, span) } - (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => { + (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => { self.dcx().emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "or".into(), @@ -742,7 +745,7 @@ impl<'a> Parser<'a> { ( // `foo: ` ExprKind::Path(None, ast::Path { segments, .. }), - token::Ident(kw::For | kw::Loop | kw::While, false), + token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No), ) if segments.len() == 1 => { let snapshot = self.create_snapshot_for_diagnostic(); let label = Label { @@ -955,19 +958,20 @@ impl<'a> Parser<'a> { fn parse_expr_dot_or_call_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { - let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { - // we are using noexpect here because we don't expect a `?` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Question) - } else { - self.eat(&token::Question) - }; + let has_question = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // we are using noexpect here because we don't expect a `?` directly after a `return` + // which could be suggested otherwise + self.eat_noexpect(&token::Question) + } else { + self.eat(&token::Question) + }; if has_question { // `expr?` e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); continue; } - let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { + let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) @@ -1126,19 +1130,19 @@ impl<'a> Parser<'a> { // 1. DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => { assert!(suffix.is_none()); - self.token = Token::new(token::Ident(sym, false), ident_span); + self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span); let next_token = (Token::new(token::Dot, dot_span), self.token_spacing); self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token)) } // 1.2 | 1.2e3 DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => { - self.token = Token::new(token::Ident(symbol1, false), ident1_span); + self.token = Token::new(token::Ident(symbol1, IdentIsRaw::No), ident1_span); // This needs to be `Spacing::Alone` to prevent regressions. // See issue #76399 and PR #76285 for more details let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone); let base1 = self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1)); - let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); + let next_token2 = Token::new(token::Ident(symbol2, IdentIsRaw::No), ident2_span); self.bump_with((next_token2, self.token_spacing)); // `.` self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None) } @@ -1555,7 +1559,7 @@ impl<'a> Parser<'a> { return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err)); } }; - let kind = if es.len() == 1 && !trailing_comma { + let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) { // `(e)` is parenthesized `e`. ExprKind::Paren(es.into_iter().next().unwrap()) } else { @@ -1946,7 +1950,7 @@ impl<'a> Parser<'a> { self.bump(); // `builtin` self.bump(); // `#` - let Some((ident, false)) = self.token.ident() else { + let Some((ident, IdentIsRaw::No)) = self.token.ident() else { let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span }); return Err(err); }; @@ -3087,10 +3091,10 @@ impl<'a> Parser<'a> { if !require_comma { arm_body = Some(expr); this.eat(&token::Comma); - Ok(false) + Ok(Recovered::No) } else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) { arm_body = Some(body); - Ok(true) + Ok(Recovered::Yes) } else { let expr_span = expr.span; arm_body = Some(expr); @@ -3171,7 +3175,7 @@ impl<'a> Parser<'a> { this.dcx().emit_err(errors::MissingCommaAfterMatchArm { span: arm_span.shrink_to_hi(), }); - return Ok(true); + return Ok(Recovered::Yes); } Err(err) }); @@ -3574,7 +3578,7 @@ impl<'a> Parser<'a> { fn find_struct_error_after_field_looking_code(&self) -> Option { match self.token.ident() { Some((ident, is_raw)) - if (is_raw || !ident.is_reserved()) + if (matches!(is_raw, IdentIsRaw::Yes) || !ident.is_reserved()) && self.look_ahead(1, |t| *t == token::Colon) => { Some(ast::ExprField { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 77381ef46262..2e049ca908fd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,8 +1,12 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; -use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use super::{ + AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing, + TrailingToken, +}; use crate::errors::{self, MacroExpandsToAdtField}; use crate::fluent_generated as fluent; +use ast::token::IdentIsRaw; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; @@ -1076,7 +1080,7 @@ impl<'a> Parser<'a> { fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> { match self.token.ident() { - Some((ident @ Ident { name: kw::Underscore, .. }, false)) => { + Some((ident @ Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) => { self.bump(); Ok(ident) } @@ -1453,7 +1457,7 @@ impl<'a> Parser<'a> { let (variants, _) = if self.token == TokenKind::Semi { self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span }); self.bump(); - (thin_vec![], false) + (thin_vec![], Trailing::No) } else { self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span)) .map_err(|mut err| { @@ -1530,10 +1534,10 @@ impl<'a> Parser<'a> { err.span_label(span, "while parsing this enum"); err.help(help); err.emit(); - (thin_vec![], true) + (thin_vec![], Recovered::Yes) } }; - VariantData::Struct { fields, recovered } + VariantData::Struct { fields, recovered: recovered.into() } } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) { let body = match this.parse_tuple_struct_body() { Ok(body) => body, @@ -1618,7 +1622,7 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered } + VariantData::Struct { fields, recovered: recovered.into() } } // No `where` so: `struct Foo;` } else if self.eat(&token::Semi) { @@ -1630,7 +1634,7 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered } + VariantData::Struct { fields, recovered: recovered.into() } // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(Delimiter::Parenthesis) { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID); @@ -1659,14 +1663,14 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered } + VariantData::Struct { fields, recovered: recovered.into() } } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "union", class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered } + VariantData::Struct { fields, recovered: recovered.into() } } else { let token_str = super::token_descr(&self.token); let msg = format!("expected `where` or `{{` after union name, found {token_str}"); @@ -1683,14 +1687,14 @@ impl<'a> Parser<'a> { adt_ty: &str, ident_span: Span, parsed_where: bool, - ) -> PResult<'a, (ThinVec, /* recovered */ bool)> { + ) -> PResult<'a, (ThinVec, Recovered)> { let mut fields = ThinVec::new(); - let mut recovered = false; + let mut recovered = Recovered::No; if self.eat(&token::OpenDelim(Delimiter::Brace)) { while self.token != token::CloseDelim(Delimiter::Brace) { let field = self.parse_field_def(adt_ty).map_err(|e| { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No); - recovered = true; + recovered = Recovered::Yes; e }); match field { @@ -1962,7 +1966,7 @@ impl<'a> Parser<'a> { let (ident, is_raw) = self.ident_or_err(true)?; if ident.name == kw::Underscore { self.sess.gated_spans.gate(sym::unnamed_fields, lo); - } else if !is_raw && ident.is_reserved() { + } else if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = Visibility { @@ -2461,8 +2465,8 @@ impl<'a> Parser<'a> { // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't // account for this. match self.expect_one_of(&[], &[]) { - Ok(true) => {} - Ok(false) => unreachable!(), + Ok(Recovered::Yes) => {} + Ok(Recovered::No) => unreachable!(), Err(mut err) => { // Qualifier keywords ordering check enum WrongKw { @@ -2740,7 +2744,7 @@ impl<'a> Parser<'a> { fn parse_self_param(&mut self) -> PResult<'a, Option> { // Extract an identifier *after* having confirmed that the token is one. let expect_self_ident = |this: &mut Self| match this.token.ident() { - Some((ident, false)) => { + Some((ident, IdentIsRaw::No)) => { this.bump(); ident } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index dea2b9e6ca70..29dd2eeb56ab 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -11,6 +11,7 @@ mod stmt; mod ty; use crate::lexer::UnmatchedDelim; +use ast::token::IdentIsRaw; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; @@ -357,6 +358,25 @@ pub enum FollowedByType { No, } +/// Whether a function performed recovery +#[derive(Copy, Clone, Debug)] +pub enum Recovered { + No, + Yes, +} + +impl From for bool { + fn from(r: Recovered) -> bool { + matches!(r, Recovered::Yes) + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Trailing { + No, + Yes, +} + #[derive(Clone, Copy, PartialEq, Eq)] pub enum TokenDescription { ReservedIdentifier, @@ -455,11 +475,11 @@ impl<'a> Parser<'a> { } /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> { + pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> { if self.expected_tokens.is_empty() { if self.token == *t { self.bump(); - Ok(false) + Ok(Recovered::No) } else { self.unexpected_try_recover(t) } @@ -475,13 +495,13 @@ impl<'a> Parser<'a> { &mut self, edible: &[TokenKind], inedible: &[TokenKind], - ) -> PResult<'a, bool /* recovered */> { + ) -> PResult<'a, Recovered> { if edible.contains(&self.token.kind) { self.bump(); - Ok(false) + Ok(Recovered::No) } else if inedible.contains(&self.token.kind) { // leave it in the input - Ok(false) + Ok(Recovered::No) } else if self.token.kind != token::Eof && self.last_unexpected_token_span == Some(self.token.span) { @@ -499,7 +519,7 @@ impl<'a> Parser<'a> { fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(recover)?; - if !is_raw && ident.is_reserved() { + if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() { let err = self.expected_ident_found_err(); if recover { err.emit(); @@ -511,7 +531,7 @@ impl<'a> Parser<'a> { Ok(ident) } - fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, IdentIsRaw)> { match self.token.ident() { Some(ident) => Ok(ident), None => self.expected_ident_found(recover), @@ -568,7 +588,7 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() + && let Some((ident, IdentIsRaw::No)) = self.token.ident() && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { true @@ -598,7 +618,7 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() + && let Some((ident, IdentIsRaw::No)) = self.token.ident() && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() }); @@ -783,10 +803,10 @@ impl<'a> Parser<'a> { sep: SeqSep, expect: TokenExpectType, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */, bool /* recovered */)> { + ) -> PResult<'a, (ThinVec, Trailing, Recovered)> { let mut first = true; - let mut recovered = false; - let mut trailing = false; + let mut recovered = Recovered::No; + let mut trailing = Trailing::No; let mut v = ThinVec::new(); while !self.expect_any_with_type(kets, expect) { @@ -800,12 +820,12 @@ impl<'a> Parser<'a> { } else { // check for separator match self.expect(t) { - Ok(false) /* not recovered */ => { + Ok(Recovered::No) => { self.current_closure.take(); } - Ok(true) /* recovered */ => { + Ok(Recovered::Yes) => { self.current_closure.take(); - recovered = true; + recovered = Recovered::Yes; break; } Err(mut expect_err) => { @@ -900,7 +920,7 @@ impl<'a> Parser<'a> { } } if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { - trailing = true; + trailing = Trailing::Yes; break; } @@ -978,7 +998,7 @@ impl<'a> Parser<'a> { ket: &TokenKind, sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */, bool /* recovered */)> { + ) -> PResult<'a, (ThinVec, Trailing, Recovered)> { self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } @@ -990,9 +1010,9 @@ impl<'a> Parser<'a> { ket: &TokenKind, sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec, Trailing)> { let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if !recovered { + if matches!(recovered, Recovered::No) { self.eat(ket); } Ok((val, trailing)) @@ -1007,7 +1027,7 @@ impl<'a> Parser<'a> { ket: &TokenKind, sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec, Trailing)> { self.expect(bra)?; self.parse_seq_to_end(ket, sep, f) } @@ -1019,7 +1039,7 @@ impl<'a> Parser<'a> { &mut self, delim: Delimiter, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec, Trailing)> { self.parse_unspanned_seq( &token::OpenDelim(delim), &token::CloseDelim(delim), @@ -1034,7 +1054,7 @@ impl<'a> Parser<'a> { fn parse_paren_comma_seq( &mut self, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec, Trailing)> { self.parse_delim_comma_seq(Delimiter::Parenthesis, f) } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 071d6b72f3b9..f1572a18a8be 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -201,6 +201,6 @@ impl<'a> Parser<'a> { /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. -fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { +fn get_macro_ident(token: &Token) -> Option<(Ident, token::IdentIsRaw)> { token.ident().filter(|(ident, _)| ident.name != kw::Underscore) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 75fc013d3e6f..2ede19b11e04 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, Restrictions, TrailingToken}; +use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, @@ -311,7 +311,7 @@ impl<'a> Parser<'a> { matches!( &token.uninterpolate().kind, token::FatArrow // e.g. `a | => 0,`. - | token::Ident(kw::If, false) // e.g. `a | if expr`. + | token::Ident(kw::If, token::IdentIsRaw::No) // e.g. `a | if expr`. | token::Eq // e.g. `let a | = 0`. | token::Semi // e.g. `let a |;`. | token::Colon // e.g. `let a | :`. @@ -696,7 +696,9 @@ impl<'a> Parser<'a> { // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. - Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { + let paren_pattern = + fields.len() == 1 && !(matches!(trailing_comma, Trailing::Yes) || fields[0].is_rest()); + if paren_pattern { let pat = fields.into_iter().next().unwrap(); let close_paren = self.prev_token.span; @@ -714,7 +716,7 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(begin.clone(), form)? + self.parse_pat_range_begin_with(begin.clone(), form) } // recover ranges with parentheses around the `(start)..` PatKind::Err(_) @@ -729,15 +731,15 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)? + self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form) } // (pat) with optional parentheses - _ => PatKind::Paren(pat), + _ => Ok(PatKind::Paren(pat)), } } else { - PatKind::Tuple(fields) - }) + Ok(PatKind::Tuple(fields)) + } } /// Parse a mutable binding with the `mut` token already eaten. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 681039999a65..6e7bbe7e06d4 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -2,6 +2,7 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::errors::PathSingleColon; use crate::{errors, maybe_whole}; +use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::{ @@ -390,7 +391,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> { match self.token.ident() { - Some((ident, false)) if ident.is_path_segment_keyword() => { + Some((ident, IdentIsRaw::No)) if ident.is_path_segment_keyword() => { self.bump(); Ok(ident) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1bae5b322403..ee02b69c6140 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -11,6 +11,7 @@ use crate::errors; use crate::maybe_whole; use crate::errors::MalformedLoopLabel; +use crate::parser::Recovered; use ast::Label; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -661,7 +662,6 @@ impl<'a> Parser<'a> { if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. - // `expect_one_of` returns PResult<'a, bool /* recovered */> let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); @@ -669,7 +669,7 @@ impl<'a> Parser<'a> { let replace_with_err = 'break_recover: { match expect_result { // Recover from parser, skip type error to avoid extra errors. - Ok(true) => true, + Ok(Recovered::Yes) => true, Err(e) => { if self.recover_colon_as_semi() { // recover_colon_as_semi has already emitted a nicer error. @@ -691,7 +691,7 @@ impl<'a> Parser<'a> { token.kind, token::Ident( kw::For | kw::Loop | kw::While, - false + token::IdentIsRaw::No ) | token::OpenDelim(Delimiter::Brace) ) }) @@ -735,7 +735,7 @@ impl<'a> Parser<'a> { true } - Ok(false) => false, + Ok(Recovered::No) => false, } }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 23a92e6dd3dd..e3fe535bd5f8 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,4 +1,4 @@ -use super::{Parser, PathStyle, TokenType}; +use super::{Parser, PathStyle, TokenType, Trailing}; use crate::errors::{ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, @@ -415,7 +415,7 @@ impl<'a> Parser<'a> { Ok(ty) })?; - if ts.len() == 1 && !trailing { + if ts.len() == 1 && matches!(trailing, Trailing::No) { let ty = ts.into_iter().next().unwrap().into_inner(); let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index a24da4487660..f672051be5af 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1189,6 +1189,25 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { } Ok(matrix) } + + /// Recover row usefulness and intersection information from a processed specialized matrix. + /// `specialized` must come from `self.specialize_constructor`. + fn unspecialize(&mut self, specialized: Self) { + for child_row in specialized.rows() { + let parent_row_id = child_row.parent_row; + let parent_row = &mut self.rows[parent_row_id]; + // A parent row is useful if any of its children is. + parent_row.useful |= child_row.useful; + for child_intersection in child_row.intersects.iter() { + // Convert the intersecting ids into ids for the parent matrix. + let parent_intersection = specialized.rows[child_intersection].parent_row; + // Note: self-intersection can happen with or-patterns. + if parent_intersection != parent_row_id { + parent_row.intersects.insert(parent_intersection); + } + } + } + } } /// Pretty-printer for matrices of patterns, example: @@ -1558,21 +1577,6 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // Accumulate the found witnesses. ret.extend(witnesses); - for child_row in spec_matrix.rows() { - let parent_row_id = child_row.parent_row; - let parent_row = &mut matrix.rows[parent_row_id]; - // A parent row is useful if any of its children is. - parent_row.useful |= child_row.useful; - for child_intersection in child_row.intersects.iter() { - // Convert the intersecting ids into ids for the parent matrix. - let parent_intersection = spec_matrix.rows[child_intersection].parent_row; - // Note: self-intersection can happen with or-patterns. - if parent_intersection != parent_row_id { - parent_row.intersects.insert(parent_intersection); - } - } - } - // Detect ranges that overlap on their endpoints. if let Constructor::IntRange(overlap_range) = ctor { if overlap_range.is_singleton() @@ -1582,6 +1586,8 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( collect_overlapping_range_endpoints(mcx, overlap_range, matrix, &spec_matrix); } } + + matrix.unspecialize(spec_matrix); } // Record usefulness in the patterns. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d64a3b43aad3..222dd69dbc48 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1111,7 +1111,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { suggestions.extend( tmp_suggestions .into_iter() - .filter(|s| use_prelude || this.is_builtin_macro(s.res)), + .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)), ); } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 4583f991cabd..7e7424be303a 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -23,6 +23,18 @@ use Namespace::*; type Visibility = ty::Visibility; +#[derive(Copy, Clone)] +pub enum UsePrelude { + No, + Yes, +} + +impl From for bool { + fn from(up: UsePrelude) -> bool { + matches!(up, UsePrelude::Yes) + } +} + impl<'a, 'tcx> Resolver<'a, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -32,12 +44,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, ctxt: SyntaxContext, - mut visitor: impl FnMut( - &mut Self, - Scope<'a>, - /*use_prelude*/ bool, - SyntaxContext, - ) -> Option, + mut visitor: impl FnMut(&mut Self, Scope<'a>, UsePrelude, SyntaxContext) -> Option, ) -> Option { // General principles: // 1. Not controlled (user-defined) names should have higher priority than controlled names @@ -133,6 +140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if visit { + let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { return break_result; } @@ -579,7 +587,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ignore_binding, ) { - if use_prelude || this.is_builtin_macro(binding.res()) { + if matches!(use_prelude, UsePrelude::Yes) + || this.is_builtin_macro(binding.res()) + { result = Ok((binding, Flags::MISC_FROM_PRELUDE)); } } diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs index 22f6ee810557..70e40f60f22a 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs @@ -8,8 +8,7 @@ pub fn target() -> Target { arch: "arm".into(), options: TargetOptions { abi: "eabihf".into(), - // FIXME: change env to "gnu" when cfg_target_abi becomes stable - env: "gnueabihf".into(), + env: "gnu".into(), features: "+v6,+vfp2,-d32".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs index 84d9ceac04d4..ca0db5e56400 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs @@ -8,8 +8,6 @@ pub fn target() -> Target { arch: "arm".into(), options: TargetOptions { abi: "eabihf".into(), - // FIXME: remove env when cfg_target_abi becomes stable - env: "eabihf".into(), features: "+v6,+vfp2,-d32".into(), max_atomic_width: Some(64), mcount: "__mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index 9f4a432c6fa5..61b6d7a63e35 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -8,8 +8,7 @@ pub fn target() -> Target { arch: "arm".into(), options: TargetOptions { abi: "eabihf".into(), - // FIXME: change env to "gnu" when cfg_target_abi becomes stable - env: "gnueabihf".into(), + env: "gnu".into(), features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index e5518c6daecf..7afdb87b62ee 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -8,8 +8,6 @@ pub fn target() -> Target { arch: "arm".into(), options: TargetOptions { abi: "eabihf".into(), - // FIXME: remove env when cfg_target_abi becomes stable - env: "eabihf".into(), features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "__mcount".into(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ac0685994eab..e82171de3789 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -601,9 +601,24 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>( trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) } +#[derive(Debug, Copy, Clone)] +pub enum IsFirstInputType { + No, + Yes, +} + +impl From for IsFirstInputType { + fn from(b: bool) -> IsFirstInputType { + match b { + false => IsFirstInputType::No, + true => IsFirstInputType::Yes, + } + } +} + #[derive(Debug)] pub enum OrphanCheckErr<'tcx> { - NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>), + NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>), UncoveredTy(Ty<'tcx>, Option>), } @@ -754,7 +769,7 @@ struct OrphanChecker<'tcx, F> { /// Ignore orphan check failures and exclusively search for the first /// local type. search_first_local_ty: bool, - non_local_tys: Vec<(Ty<'tcx>, bool)>, + non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>, } impl<'tcx, F, E> OrphanChecker<'tcx, F> @@ -772,7 +787,7 @@ where } fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { - self.non_local_tys.push((t, self.in_self_ty)); + self.non_local_tys.push((t, self.in_self_ty.into())); ControlFlow::Continue(()) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9eec60ea06c2..32447aca390a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -42,7 +42,7 @@ use std::fmt::Debug; use std::ops::ControlFlow; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; -pub use self::coherence::{OrphanCheckErr, OverlapResult}; +pub use self::coherence::{IsFirstInputType, OrphanCheckErr, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 45f6e375e894..85740dce8668 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -396,6 +396,7 @@ pub trait AsMut { /// For example, take this code: /// /// ``` +/// # #![cfg_attr(not(bootstrap), allow(non_local_definitions))] /// struct Wrapper(Vec); /// impl From> for Vec { /// fn from(w: Wrapper) -> Vec { diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 153971a59c5c..bfdd28a7399f 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -454,6 +454,7 @@ pub trait Hasher { /// ``` /// #![feature(hasher_prefixfree_extras)] /// # // Stubs to make the `impl` below pass the compiler + /// # #![cfg_attr(not(bootstrap), allow(non_local_definitions))] /// # struct MyCollection(Option); /// # impl MyCollection { /// # fn len(&self) -> usize { todo!() } diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs index b4d61d28cb2e..29adf0b42fae 100644 --- a/library/core/tests/iter/adapters/step_by.rs +++ b/library/core/tests/iter/adapters/step_by.rs @@ -49,6 +49,7 @@ fn test_iterator_step_by_nth() { } #[test] +#[cfg_attr(not(bootstrap), allow(non_local_definitions))] fn test_iterator_step_by_nth_overflow() { #[cfg(target_pointer_width = "16")] type Bigger = u32; diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 6c008ab2cb19..d02dc45da34c 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -195,6 +195,7 @@ pub fn test_unwrap_or_default() { } #[test] +#[cfg_attr(not(bootstrap), allow(non_local_definitions))] pub fn test_into_ok() { fn infallible_op() -> Result { Ok(666) @@ -217,6 +218,7 @@ pub fn test_into_ok() { } #[test] +#[cfg_attr(not(bootstrap), allow(non_local_definitions))] pub fn test_into_err() { fn until_error_op() -> Result { Err(666) diff --git a/library/std/src/sys/pal/sgx/rwlock/tests.rs b/library/std/src/sys/locks/rwlock/sgx/tests.rs similarity index 100% rename from library/std/src/sys/pal/sgx/rwlock/tests.rs rename to library/std/src/sys/locks/rwlock/sgx/tests.rs diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 6b12d7db8b03..ad8e01bfa9b0 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -321,6 +321,21 @@ pub unsafe fn NtWriteFile( } } +// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library. +cfg_if::cfg_if! { +if #[cfg(not(target_vendor = "win7"))] { + #[cfg(target_arch = "x86")] + #[link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")] + extern "system" { + pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; + } + #[cfg(not(target_arch = "x86"))] + #[link(name = "bcryptprimitives", kind = "raw-dylib")] + extern "system" { + pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; + } +}} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 726f1c3df829..ab2a8caf5dfd 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2180,10 +2180,6 @@ Windows.Win32.Networking.WinSock.WSATRY_AGAIN Windows.Win32.Networking.WinSock.WSATYPE_NOT_FOUND Windows.Win32.Networking.WinSock.WSAVERNOTSUPPORTED Windows.Win32.Security.Authentication.Identity.RtlGenRandom -Windows.Win32.Security.Cryptography.BCRYPT_ALG_HANDLE -Windows.Win32.Security.Cryptography.BCRYPT_USE_SYSTEM_PREFERRED_RNG -Windows.Win32.Security.Cryptography.BCryptGenRandom -Windows.Win32.Security.Cryptography.BCRYPTGENRANDOM_FLAGS Windows.Win32.Security.SECURITY_ATTRIBUTES Windows.Win32.Security.TOKEN_ACCESS_MASK Windows.Win32.Security.TOKEN_ACCESS_PSEUDO_HANDLE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index c386b66a722d..8eb779373f7e 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -15,15 +15,6 @@ extern "system" { pub fn RtlGenRandom(randombuffer: *mut ::core::ffi::c_void, randombufferlength: u32) -> BOOLEAN; } -#[link(name = "bcrypt")] -extern "system" { - pub fn BCryptGenRandom( - halgorithm: BCRYPT_ALG_HANDLE, - pbbuffer: *mut u8, - cbbuffer: u32, - dwflags: BCRYPTGENRANDOM_FLAGS, - ) -> NTSTATUS; -} #[link(name = "kernel32")] extern "system" { pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> (); @@ -889,9 +880,6 @@ impl ::core::clone::Clone for ARM64_NT_NEON128_0 { *self } } -pub type BCRYPTGENRANDOM_FLAGS = u32; -pub type BCRYPT_ALG_HANDLE = *mut ::core::ffi::c_void; -pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: BCRYPTGENRANDOM_FLAGS = 2u32; pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; pub type BOOLEAN = u8; diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs index bd1ae6b06076..e427546222ae 100644 --- a/library/std/src/sys/pal/windows/rand.rs +++ b/library/std/src/sys/pal/windows/rand.rs @@ -1,42 +1,27 @@ -use crate::mem; -use crate::ptr; use crate::sys::c; +use core::mem; +use core::ptr; +#[cfg(not(target_vendor = "win7"))] +#[inline] pub fn hashmap_random_keys() -> (u64, u64) { let mut v = (0, 0); - let ret = unsafe { - c::BCryptGenRandom( - ptr::null_mut(), - core::ptr::addr_of_mut!(v) as *mut u8, - mem::size_of_val(&v) as c::ULONG, - c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - if c::nt_success(ret) { v } else { fallback_rng() } + let ret = unsafe { c::ProcessPrng(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v)) }; + // ProcessPrng is documented as always returning `TRUE`. + // https://learn.microsoft.com/en-us/windows/win32/seccng/processprng#return-value + debug_assert_eq!(ret, c::TRUE); + v } -/// Generate random numbers using the fallback RNG function (RtlGenRandom) -/// -/// This is necessary because of a failure to load the SysWOW64 variant of the -/// bcryptprimitives.dll library from code that lives in bcrypt.dll -/// See -#[cfg(not(target_vendor = "uwp"))] -#[inline(never)] -fn fallback_rng() -> (u64, u64) { +#[cfg(target_vendor = "win7")] +pub fn hashmap_random_keys() -> (u64, u64) { use crate::ffi::c_void; use crate::io; let mut v = (0, 0); let ret = unsafe { - c::RtlGenRandom(core::ptr::addr_of_mut!(v) as *mut c_void, mem::size_of_val(&v) as c::ULONG) + c::RtlGenRandom(ptr::addr_of_mut!(v).cast::(), mem::size_of_val(&v) as c::ULONG) }; - if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } -} - -/// We can't use RtlGenRandom with UWP, so there is no fallback -#[cfg(target_vendor = "uwp")] -#[inline(never)] -fn fallback_rng() -> (u64, u64) { - panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); + if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) } } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index f5988a4df136..a64f29046337 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -3,7 +3,7 @@ #![feature(link_cfg)] #![feature(staged_api)] #![feature(c_unwind)] -#![feature(cfg_target_abi)] +#![cfg_attr(bootstrap, feature(cfg_target_abi))] #![feature(strict_provenance)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] #![allow(internal_features)] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 3ac60f15ef67..f6f4253a3643 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -367,7 +367,7 @@ impl Step for CodegenBackend { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustAnalyzer { pub target: TargetSelection, } @@ -441,7 +441,7 @@ impl Step for RustAnalyzer { macro_rules! tool_check_step { ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => { - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { pub target: TargetSelection, } diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 4b993945f19f..17ca92f25a92 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -14,7 +14,7 @@ use crate::utils::cache::Interned; use crate::utils::helpers::t; use crate::{Build, Compiler, Mode, Subcommand}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CleanAll {} impl Step for CleanAll { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d349cd67fed2..938813044217 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -727,7 +727,7 @@ fn apple_darwin_sign_file(file_path: &Path) { assert!(status.success()); } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StartupObjects { pub compiler: Compiler, pub target: TargetSelection, @@ -1491,7 +1491,7 @@ pub fn compiler_file( PathBuf::from(out.trim()) } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Sysroot { pub compiler: Compiler, /// See [`Std::force_recompile`]. @@ -1653,7 +1653,7 @@ impl Step for Sysroot { } } -#[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] pub struct Assemble { /// The compiler which we will produce in this step. Assemble itself will /// take care of ensuring that the necessary prerequisites to do so exist, diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index d9ab18e7250b..fe50a787f9f0 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -50,7 +50,7 @@ fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool { builder.config.tools.as_ref().map_or(true, |tools| tools.contains(tool)) } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Docs { pub host: TargetSelection, } @@ -83,7 +83,7 @@ impl Step for Docs { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct JsonDocs { pub host: TargetSelection, } @@ -121,7 +121,7 @@ impl Step for JsonDocs { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcDocs { pub host: TargetSelection, } @@ -308,7 +308,7 @@ fn make_win_dist( } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Mingw { pub host: TargetSelection, } @@ -348,7 +348,7 @@ impl Step for Mingw { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Rustc { pub compiler: Compiler, } @@ -476,7 +476,7 @@ impl Step for Rustc { let man_src = builder.src.join("src/doc/man"); let man_dst = image.join("share/man/man1"); - // don't use our `bootstrap::{copy, cp_r}`, because those try + // don't use our `bootstrap::{copy_internal, cp_r}`, because those try // to hardlink, and we don't want to edit the source templates for file_entry in builder.read_dir(&man_src) { let page_src = file_entry.path(); @@ -617,7 +617,7 @@ fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Std { pub compiler: Compiler, pub target: TargetSelection, @@ -664,7 +664,7 @@ impl Step for Std { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { pub compiler: Compiler, pub target: TargetSelection, @@ -723,7 +723,7 @@ impl Step for RustcDev { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Analysis { pub compiler: Compiler, pub target: TargetSelection, @@ -870,7 +870,7 @@ fn copy_src_dirs( } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Src; impl Step for Src { @@ -931,7 +931,7 @@ impl Step for Src { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct PlainSourceTarball; impl Step for PlainSourceTarball { @@ -1031,7 +1031,7 @@ impl Step for PlainSourceTarball { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Cargo { pub compiler: Compiler, pub target: TargetSelection, @@ -1080,7 +1080,7 @@ impl Step for Cargo { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Rls { pub compiler: Compiler, pub target: TargetSelection, @@ -1122,7 +1122,7 @@ impl Step for Rls { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, pub target: TargetSelection, @@ -1164,7 +1164,7 @@ impl Step for RustAnalyzer { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Clippy { pub compiler: Compiler, pub target: TargetSelection, @@ -1212,7 +1212,7 @@ impl Step for Clippy { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Miri { pub compiler: Compiler, pub target: TargetSelection, @@ -1359,7 +1359,7 @@ impl Step for CodegenBackend { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { pub compiler: Compiler, pub target: TargetSelection, @@ -1404,7 +1404,7 @@ impl Step for Rustfmt { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustDemangler { pub compiler: Compiler, pub target: TargetSelection, @@ -1460,7 +1460,7 @@ impl Step for RustDemangler { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, host: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 7a122a8676ba..a4903ce23536 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -32,7 +32,7 @@ macro_rules! submodule_helper { macro_rules! book { ($($name:ident, $path:expr, $book_name:expr $(, submodule $(= $submodule:literal)? )? ;)+) => { $( - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { target: TargetSelection, } @@ -86,7 +86,7 @@ book!( StyleGuide, "src/doc/style-guide", "style-guide"; ); -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, } @@ -160,7 +160,7 @@ impl Step for RustbookSrc

{ } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct TheBook { compiler: Compiler, target: TargetSelection, @@ -286,7 +286,7 @@ fn invoke_rustdoc( builder.run(&mut cmd); } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Standalone { compiler: Compiler, target: TargetSelection, @@ -389,7 +389,7 @@ impl Step for Standalone { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Releases { compiler: Compiler, target: TargetSelection, @@ -492,7 +492,7 @@ pub struct SharedAssetsPaths { pub version_info: PathBuf, } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct SharedAssets { target: TargetSelection, } @@ -872,7 +872,7 @@ macro_rules! tool_doc { $(is_library = $is_library:expr,)? $(crates = $crates:expr)? ) => { - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $tool { target: TargetSelection, } @@ -1021,7 +1021,7 @@ tool_doc!( crates = ["bootstrap"] ); -#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { pub target: TargetSelection, } @@ -1056,7 +1056,7 @@ impl Step for ErrorIndex { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct UnstableBookGen { target: TargetSelection, } @@ -1112,7 +1112,7 @@ fn symlink_dir_force(config: &Config, original: &Path, link: &Path) { ); } -#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)] pub struct RustcBook { pub compiler: Compiler, pub target: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 29238b90225a..6726671ddd9b 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -159,7 +159,7 @@ macro_rules! install { only_hosts: $only_hosts:expr, $run_item:block $(, $c:ident)*;)+) => { $( - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { pub compiler: Compiler, pub target: TargetSelection, @@ -303,7 +303,7 @@ install!((self, builder, _config), }; ); -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Src { pub stage: u32, } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 9622321a74e7..4a92acfa3d90 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -242,7 +242,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: TargetSelection, } @@ -815,7 +815,7 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option { .or_else(|| env::var_os(var_base)) } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Lld { pub target: TargetSelection, } @@ -937,7 +937,7 @@ impl Step for Lld { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Sanitizers { pub target: TargetSelection, } @@ -1147,7 +1147,7 @@ impl HashStamp { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrtBeginEnd { pub target: TargetSelection, } @@ -1215,7 +1215,7 @@ impl Step for CrtBeginEnd { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Libunwind { pub target: TargetSelection, } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 27b0c7760f07..61ee2fc1f6f3 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -10,7 +10,7 @@ use crate::core::config::TargetSelection; use crate::utils::helpers::output; use crate::Mode; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ExpandYamlAnchors; impl Step for ExpandYamlAnchors { @@ -36,7 +36,7 @@ impl Step for ExpandYamlAnchors { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct BuildManifest; impl Step for BuildManifest { @@ -75,7 +75,7 @@ impl Step for BuildManifest { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct BumpStage0; impl Step for BumpStage0 { @@ -97,7 +97,7 @@ impl Step for BumpStage0 { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct ReplaceVersionPlaceholder; impl Step for ReplaceVersionPlaceholder { @@ -119,7 +119,7 @@ impl Step for ReplaceVersionPlaceholder { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Miri { stage: u32, host: TargetSelection, @@ -178,7 +178,7 @@ impl Step for Miri { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct CollectLicenseMetadata; impl Step for CollectLicenseMetadata { @@ -210,7 +210,7 @@ impl Step for CollectLicenseMetadata { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct GenerateCopyright; impl Step for GenerateCopyright { @@ -240,7 +240,7 @@ impl Step for GenerateCopyright { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct GenerateWindowsSys; impl Step for GenerateWindowsSys { @@ -262,7 +262,7 @@ impl Step for GenerateWindowsSys { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenerateCompletions; macro_rules! generate_completions { diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 74a5578b43ec..7bc68b5aec11 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -233,7 +233,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { } /// Creates a toolchain link for stage1 using `rustup` -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Link; impl Step for Link { type Output = (); @@ -444,7 +444,7 @@ fn prompt_user(prompt: &str) -> io::Result> { } /// Installs `src/etc/pre-push.sh` as a Git hook -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Hook; impl Step for Hook { @@ -516,7 +516,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." } /// Sets up or displays `src/etc/rust_analyzer_settings.json` -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Vscode; impl Step for Vscode { diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index a00835402ec8..89d50b5ffffa 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -12,7 +12,7 @@ use crate::core::config::TargetSelection; use crate::Compiler; use std::process::{Command, Stdio}; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct MirOptPanicAbortSyntheticTarget { pub(crate) compiler: Compiler, pub(crate) base: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 791f847a8661..a2c6e79d5e25 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -86,7 +86,7 @@ impl Step for CrateBootstrap { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Linkcheck { host: TargetSelection, } @@ -179,7 +179,7 @@ fn check_if_tidy_is_installed() -> bool { .map_or(false, |status| status.success()) } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct HtmlCheck { target: TargetSelection, } @@ -220,7 +220,7 @@ impl Step for HtmlCheck { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Cargotest { stage: u32, host: TargetSelection, @@ -266,7 +266,7 @@ impl Step for Cargotest { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Cargo { stage: u32, host: TargetSelection, @@ -327,7 +327,7 @@ impl Step for Cargo { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustAnalyzer { stage: u32, host: TargetSelection, @@ -386,7 +386,7 @@ impl Step for RustAnalyzer { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Rustfmt { stage: u32, host: TargetSelection, @@ -433,7 +433,7 @@ impl Step for Rustfmt { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustDemangler { stage: u32, host: TargetSelection, @@ -492,7 +492,7 @@ impl Step for RustDemangler { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Miri { stage: u32, host: TargetSelection, @@ -699,7 +699,7 @@ impl Step for Miri { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CompiletestTest { host: TargetSelection, } @@ -747,7 +747,7 @@ impl Step for CompiletestTest { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Clippy { stage: u32, host: TargetSelection, @@ -815,7 +815,7 @@ fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString { env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocTheme { pub compiler: Compiler, } @@ -852,7 +852,7 @@ impl Step for RustdocTheme { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSStd { pub target: TargetSelection, } @@ -912,7 +912,7 @@ impl Step for RustdocJSStd { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { pub target: TargetSelection, pub compiler: Compiler, @@ -966,7 +966,7 @@ fn get_browser_ui_test_version(npm: &Path) -> Option { .or_else(|| get_browser_ui_test_version_inner(npm, true)) } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocGUI { pub target: TargetSelection, pub compiler: Compiler, @@ -1060,7 +1060,7 @@ impl Step for RustdocGUI { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Tidy; impl Step for Tidy { @@ -1151,7 +1151,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ExpandYamlAnchors; impl Step for ExpandYamlAnchors { @@ -1251,7 +1251,7 @@ macro_rules! test_definitions { host: $host:expr, compare_mode: $compare_mode:expr }) => { - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { pub compiler: Compiler, pub target: TargetSelection, @@ -1294,7 +1294,7 @@ macro_rules! coverage_test_alias { default: $default:expr, only_hosts: $only_hosts:expr $(,)? }) => { - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { pub compiler: Compiler, pub target: TargetSelection, @@ -1376,7 +1376,7 @@ default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assem /// /// Each individual mode also has its own alias that will run the tests in /// just that mode. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Coverage { pub compiler: Compiler, pub target: TargetSelection, @@ -1438,7 +1438,7 @@ host_test!(CoverageRunRustdoc { }); // For the mir-opt suite we do not use macros, as we need custom behavior when blessing. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MirOpt { pub compiler: Compiler, pub target: TargetSelection, @@ -1494,7 +1494,7 @@ impl Step for MirOpt { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] struct Compiletest { compiler: Compiler, target: TargetSelection, @@ -2142,7 +2142,7 @@ impl BookTest { macro_rules! test_book { ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => { $( - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { compiler: Compiler, } @@ -2187,7 +2187,7 @@ test_book!( EditionGuide, "src/doc/edition-guide", "edition-guide", default=false; ); -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ErrorIndex { compiler: Compiler, } @@ -2264,7 +2264,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustcGuide; impl Step for RustcGuide { @@ -2537,7 +2537,7 @@ impl Step for Crate { } /// Rustdoc is special in various ways, which is why this step is different from `Crate`. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateRustdoc { host: TargetSelection, } @@ -2638,7 +2638,7 @@ impl Step for CrateRustdoc { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateRustdocJsonTypes { host: TargetSelection, } @@ -2708,7 +2708,7 @@ impl Step for CrateRustdocJsonTypes { /// QEMU we have to build our own tools so we've got conditional dependencies /// on those programs as well. Note that the remote test client is built for /// the build target (us) and the server is built for the target. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RemoteCopyLibs { compiler: Compiler, target: TargetSelection, @@ -2754,7 +2754,7 @@ impl Step for RemoteCopyLibs { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Distcheck; impl Step for Distcheck { @@ -2824,7 +2824,7 @@ impl Step for Distcheck { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Bootstrap; impl Step for Bootstrap { @@ -2876,7 +2876,7 @@ impl Step for Bootstrap { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { pub compiler: Compiler, } @@ -2926,7 +2926,7 @@ impl Step for TierCheck { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct LintDocs { pub compiler: Compiler, pub target: TargetSelection, @@ -2959,7 +2959,7 @@ impl Step for LintDocs { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustInstaller; impl Step for RustInstaller { @@ -3020,7 +3020,7 @@ impl Step for RustInstaller { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TestHelpers { pub target: TargetSelection, } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ba867a04ec55..889876f461df 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -15,7 +15,7 @@ use crate::Compiler; use crate::Mode; use crate::{gha, Kind}; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { InTree, Submodule, @@ -220,7 +220,7 @@ macro_rules! bootstrap_tool { $(,allow_features = $allow_features:expr)? ; )+) => { - #[derive(Copy, PartialEq, Eq, Clone)] + #[derive(PartialEq, Eq, Clone)] pub enum Tool { $( $name, @@ -241,7 +241,7 @@ macro_rules! bootstrap_tool { } $( - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { pub compiler: Compiler, pub target: TargetSelection, @@ -315,7 +315,7 @@ bootstrap_tool!( CoverageDump, "src/tools/coverage-dump", "coverage-dump"; ); -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct ErrorIndex { pub compiler: Compiler, } @@ -369,7 +369,7 @@ impl Step for ErrorIndex { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RemoteTestServer { pub compiler: Compiler, pub target: TargetSelection, @@ -403,7 +403,7 @@ impl Step for RemoteTestServer { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Rustdoc { /// This should only ever be 0 or 2. /// We sometimes want to reference the "bootstrap" rustdoc, which is why this option is here. @@ -515,7 +515,7 @@ impl Step for Rustdoc { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Cargo { pub compiler: Compiler, pub target: TargetSelection, @@ -560,7 +560,7 @@ impl Step for Cargo { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LldWrapper { pub compiler: Compiler, pub target: TargetSelection, @@ -589,7 +589,7 @@ impl Step for LldWrapper { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, pub target: TargetSelection, @@ -637,7 +637,7 @@ impl Step for RustAnalyzer { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzerProcMacroSrv { pub compiler: Compiler, pub target: TargetSelection, diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 0ec5e16de1da..e169cba3c13a 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1069,7 +1069,7 @@ impl<'a> Builder<'a> { /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned { - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct Libdir { compiler: Compiler, target: TargetSelection, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 834025c81887..875a4efae02f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1235,12 +1235,16 @@ impl Config { // Infer the rest of the configuration. // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, - // running on a completely machine from where it was compiled. + // running on a completely different machine from where it was compiled. let mut cmd = Command::new("git"); - // NOTE: we cannot support running from outside the repository because the only path we have available - // is set at compile time, which can be wrong if bootstrap was downloaded from source. + // NOTE: we cannot support running from outside the repository because the only other path we have available + // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. // We still support running outside the repository if we find we aren't in a git directory. - cmd.arg("rev-parse").arg("--show-toplevel"); + + // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path, + // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap + // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path. + cmd.arg("rev-parse").arg("--show-cdup"); // Discard stderr because we expect this to fail when building from a tarball. let output = cmd .stderr(std::process::Stdio::null()) @@ -1248,13 +1252,18 @@ impl Config { .ok() .and_then(|output| if output.status.success() { Some(output) } else { None }); if let Some(output) = output { - let git_root = String::from_utf8(output.stdout).unwrap(); - // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes. - let git_root = PathBuf::from(git_root.trim()).canonicalize().unwrap(); + let git_root_relative = String::from_utf8(output.stdout).unwrap(); + // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, + // and to resolve any relative components. + let git_root = env::current_dir() + .unwrap() + .join(PathBuf::from(git_root_relative.trim())) + .canonicalize() + .unwrap(); let s = git_root.to_str().unwrap(); // Bootstrap is quite bad at handling /? in front of paths - let src = match s.strip_prefix("\\\\?\\") { + let git_root = match s.strip_prefix("\\\\?\\") { Some(p) => PathBuf::from(p), None => git_root, }; @@ -1264,8 +1273,8 @@ impl Config { // // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. - if src.join("src").join("stage0.json").exists() { - config.src = src; + if git_root.join("src").join("stage0.json").exists() { + config.src = git_root; } } else { // We're building from a tarball, not git sources. diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index b813d82ca6f5..9a50ad4437e7 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -131,4 +131,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The \"codegen\"/\"llvm\" profile has been removed and replaced with \"compiler\", use it instead for the same behavior.", }, + ChangeInfo { + change_id: 118724, + severity: ChangeSeverity::Info, + summary: "`x install` now skips providing tarball sources (under 'build/dist' path) to speed up the installation process.", + }, ]; diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 573d923ed8fd..a14dfd1ca123 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -3,8 +3,8 @@ use std::{ process::Command, }; -use crate::core::build_steps::dist::distdir; use crate::core::builder::Builder; +use crate::core::{build_steps::dist::distdir, builder::Kind}; use crate::utils::channel; use crate::utils::helpers::t; @@ -325,7 +325,22 @@ impl<'a> Tarball<'a> { assert!(!formats.is_empty(), "dist.compression-formats can't be empty"); cmd.arg("--compression-formats").arg(formats.join(",")); } - cmd.args(["--compression-profile", &self.builder.config.dist_compression_profile]); + + // For `x install` tarball files aren't needed, so we can speed up the process by not producing them. + let compression_profile = if self.builder.kind == Kind::Install { + self.builder.verbose("Forcing dist.compression-profile = 'no-op' for `x install`."); + // "no-op" indicates that the rust-installer won't produce compressed tarball sources. + "no-op" + } else { + assert!( + self.builder.config.dist_compression_profile != "no-op", + "dist.compression-profile = 'no-op' can only be used for `x install`" + ); + + &self.builder.config.dist_compression_profile + }; + + cmd.args(&["--compression-profile", compression_profile]); self.builder.run(&mut cmd); // Ensure there are no symbolic links in the tarball. In particular, diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 9b0f477409a9..58d5dec9ba52 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -111,10 +111,31 @@ x--expand-yaml-anchors--remove: if: success() && !env.SKIP_JOB - &base-ci-job + defaults: + run: + shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} timeout-minutes: 600 runs-on: "${{ matrix.os }}" env: *shared-ci-variables steps: + - if: contains(matrix.os, 'windows') + uses: msys2/setup-msys2@v2.22.0 + with: + # i686 jobs use mingw32. x86_64 and cross-compile jobs use mingw64. + msystem: ${{ contains(matrix.name, 'i686') && 'mingw32' || 'mingw64' }} + # don't try to download updates for already installed packages + update: false + # don't try to use the msys that comes built-in to the github runner, + # so we can control what is installed (i.e. not python) + release: true + # Inherit the full path from the Windows environment, with MSYS2's */bin/ + # dirs placed in front. This lets us run Windows-native Python etc. + path-type: inherit + install: > + make + dos2unix + diffutils + - name: disable git crlf conversion run: git config --global core.autocrlf false diff --git a/src/ci/run.sh b/src/ci/run.sh index 1cdcffc1a754..3ad04c73d3da 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -76,7 +76,7 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set dist.compression-profile=balance # the LLVM build, as not to run out of memory. # This is an attempt to fix the spurious build error tracked by # https://github.com/rust-lang/rust/issues/108227. -if isWindows && [[ ${CUSTOM_MINGW-0} -eq 1 ]]; then +if isKnownToBeMingwBuild; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-jobs=1" fi diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index 77164ed4117a..aa7ff813f516 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -37,8 +37,7 @@ if isMacOS; then # Configure `AR` specifically so rustbuild doesn't try to infer it as # `clang-ar` by accident. ciCommandSetEnv AR "ar" -elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then - +elif isWindows && ! isKnownToBeMingwBuild; then # If we're compiling for MSVC then we, like most other distribution builders, # switch to clang as the compiler. This'll allow us eventually to enable LTO # amongst LLVM and rustc. Note that we only do this on MSVC as I don't think diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 7eccb9b86502..87b835b63db5 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -38,11 +38,11 @@ if isWindows; then ;; esac - if [[ "${CUSTOM_MINGW-0}" -ne 1 ]]; then - pacman -S --noconfirm --needed mingw-w64-$arch-toolchain mingw-w64-$arch-cmake \ - mingw-w64-$arch-gcc \ - mingw-w64-$arch-python # the python package is actually for python3 - ciCommandAddPath "$(ciCheckoutPath)/msys2/mingw${bits}/bin" + if [[ "${CUSTOM_MINGW:-0}" == 0 ]]; then + pacboy -S --noconfirm toolchain:p + # According to the comment in the Windows part of install-clang.sh, in the future we might + # want to do this instead: + # pacboy -S --noconfirm clang:p ... else mingw_dir="mingw${bits}" diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 0aa4b42a6a8f..905edf38a09d 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -1,17 +1,12 @@ #!/bin/bash -# Download and install MSYS2, needed primarily for the test suite (run-make) but -# also used by the MinGW toolchain for assembling things. +# Clean up and prepare the MSYS2 installation. MSYS2 is needed primarily for +# the test suite (run-make), but is also used by the MinGW toolchain for assembling things. set -euo pipefail IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - if isWindows; then - msys2Path="c:/msys64" - mkdir -p "${msys2Path}/home/${USERNAME}" - ciCommandAddPath "${msys2Path}/usr/bin" - # Detect the native Python version installed on the agent. On GitHub # Actions, the C:\hostedtoolcache\windows\Python directory contains a # subdirectory for each installed Python version. @@ -29,4 +24,33 @@ if isWindows; then fi ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" + + # Install pacboy for easily installing packages + pacman -S --noconfirm pactoys + + # Delete these pre-installed tools so we can't accidentally use them, because we are using the + # MSYS2 setup action versions instead. + # Delete pre-installed version of MSYS2 + rm -r "/c/msys64/" + # Delete Strawberry Perl, which contains a version of mingw + rm -r "/c/Strawberry/" + # Delete these other copies of mingw, I don't even know where they come from. + rm -r "/c/mingw64/" + rm -r "/c/mingw32/" + + if isKnownToBeMingwBuild; then + # Use the mingw version of CMake for mingw builds. + # However, the MSVC build needs native CMake, as it fails with the mingw one. + # Delete native CMake + rm -r "/c/Program Files/CMake/" + # Install mingw-w64-$arch-cmake + pacboy -S --noconfirm cmake:p + + # We use Git-for-Windows for MSVC builds, and MSYS2 Git for mingw builds, + # so that both are tested. + # Delete Windows-Git + rm -r "/c/Program Files/Git/" + # Install MSYS2 git + pacman -S --noconfirm git + fi fi diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 720394af249b..2b0a10e4d08d 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -52,6 +52,10 @@ function isLinux { [[ "${OSTYPE}" = "linux-gnu" ]] } +function isKnownToBeMingwBuild { + isGitHubActions && [[ "${CI_JOB_NAME}" == *mingw ]] +} + function isCiBranch { if [[ $# -ne 1 ]]; then echo "usage: $0 " diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index b736f4a79561..b6880cfc60fb 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, BinOpToken, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast_pretty::pprust::state::State as Printer; use rustc_ast_pretty::pprust::PrintState; @@ -148,7 +148,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) { (false, Other) } (Pound, token::Not) => (false, PoundBang), - (_, token::Ident(symbol, /* is_raw */ false)) + (_, token::Ident(symbol, IdentIsRaw::No)) if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) => { (true, Ident) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 09a90b62d97b..caad56146a74 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1207,6 +1207,13 @@ impl Tester for Collector { } } +#[cfg(test)] // used in tests +impl Tester for Vec { + fn add_test(&mut self, _test: String, _config: LangString, line: usize) { + self.push(line); + } +} + struct HirCollector<'a, 'hir, 'tcx> { sess: &'a Session, collector: &'a mut Collector, diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 4dd176b3a692..1de97e49b830 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -480,11 +480,6 @@ fn test_markdown_html_escape() { #[test] fn test_find_testable_code_line() { fn t(input: &str, expect: &[usize]) { - impl crate::doctest::Tester for Vec { - fn add_test(&mut self, _test: String, _config: LangString, line: usize) { - self.push(line); - } - } let mut lines = Vec::::new(); find_testable_code(input, &mut lines, ErrorCodes::No, false, None, true); assert_eq!(lines, expect); diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index a27813987606..8997073c8a55 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -4,7 +4,7 @@ //@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] -#![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)] +#![allow(deref_nullptr, non_local_definitions, clippy::let_unit_value, clippy::missing_safety_doc)] #![feature(lint_reasons)] extern crate proc_macro_unsafe; diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed index 02f1d09b8339..600380fd1420 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_comparison.fixed @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if)] +#![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] #![allow(clippy::non_canonical_partial_ord_impl)] diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs index 5ef696d855ec..910df6151f8c 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_comparison.rs @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if)] +#![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] #![allow(clippy::non_canonical_partial_ord_impl)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-4760.rs b/src/tools/clippy/tests/ui/crashes/ice-4760.rs index 08b06961760f..e1265169762f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4760.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4760.rs @@ -1,3 +1,5 @@ +#![allow(non_local_definitions)] + const COUNT: usize = 2; struct Thing; trait Dummy {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-6179.rs b/src/tools/clippy/tests/ui/crashes/ice-6179.rs index ce1895851e2d..fffc0f7d0d4f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6179.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6179.rs @@ -3,6 +3,7 @@ #![warn(clippy::use_self)] #![allow(dead_code, clippy::let_with_type_underscore)] +#![allow(non_local_definitions)] struct Foo; diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed index 2521bce6a58e..6d67488a7130 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::explicit_into_iter_loop)] fn main() { diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs index 9eac96d182b9..14630c07c5cc 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::explicit_into_iter_loop)] fn main() { diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr index c03647ab4336..a1e632271ed3 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:9:18 + --> $DIR/explicit_into_iter_loop.rs:10:18 | LL | for _ in iterator.into_iter() {} | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` @@ -8,31 +8,31 @@ LL | for _ in iterator.into_iter() {} = help: to override `-D warnings` add `#[allow(clippy::explicit_into_iter_loop)]` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:22:14 + --> $DIR/explicit_into_iter_loop.rs:23:14 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:25:14 + --> $DIR/explicit_into_iter_loop.rs:26:14 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:33:14 + --> $DIR/explicit_into_iter_loop.rs:34:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*mr` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:45:14 + --> $DIR/explicit_into_iter_loop.rs:46:14 | LL | for _ in u.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut u` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:48:14 + --> $DIR/explicit_into_iter_loop.rs:49:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed index f08397defa53..06229a52a18c 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed @@ -5,7 +5,8 @@ clippy::needless_borrow, clippy::deref_addrof, clippy::unnecessary_mut_passed, - dead_code + dead_code, + non_local_definitions, )] use core::slice; diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs index 2ee6825d445c..c2bf45ab2e99 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs @@ -5,7 +5,8 @@ clippy::needless_borrow, clippy::deref_addrof, clippy::unnecessary_mut_passed, - dead_code + dead_code, + non_local_definitions, )] use core::slice; diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr index 725d9b63cf8d..007606b52c29 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:17:14 + --> $DIR/explicit_iter_loop.rs:18:14 | LL | for _ in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -11,103 +11,103 @@ LL | #![deny(clippy::explicit_iter_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:18:14 + --> $DIR/explicit_iter_loop.rs:19:14 | LL | for _ in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:21:14 + --> $DIR/explicit_iter_loop.rs:22:14 | LL | for _ in rvec.iter() {} | ^^^^^^^^^^^ help: to write this more concisely, try: `rvec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:30:14 + --> $DIR/explicit_iter_loop.rs:31:14 | LL | for _ in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:34:14 + --> $DIR/explicit_iter_loop.rs:35:14 | LL | for _ in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:35:14 + --> $DIR/explicit_iter_loop.rs:36:14 | LL | for _ in [0; 33].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 33]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:38:14 + --> $DIR/explicit_iter_loop.rs:39:14 | LL | for _ in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:40:14 + --> $DIR/explicit_iter_loop.rs:41:14 | LL | for _ in rll.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:43:14 + --> $DIR/explicit_iter_loop.rs:44:14 | LL | for _ in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:45:14 + --> $DIR/explicit_iter_loop.rs:46:14 | LL | for _ in rvd.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rvd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:48:14 + --> $DIR/explicit_iter_loop.rs:49:14 | LL | for _ in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:51:14 + --> $DIR/explicit_iter_loop.rs:52:14 | LL | for _ in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:54:14 + --> $DIR/explicit_iter_loop.rs:55:14 | LL | for _ in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:57:14 + --> $DIR/explicit_iter_loop.rs:58:14 | LL | for _ in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:60:14 + --> $DIR/explicit_iter_loop.rs:61:14 | LL | for _ in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:149:14 + --> $DIR/explicit_iter_loop.rs:150:14 | LL | for _ in x.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `&x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:150:14 + --> $DIR/explicit_iter_loop.rs:151:14 | LL | for _ in x.iter_mut() {} | ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:153:14 + --> $DIR/explicit_iter_loop.rs:154:14 | LL | for _ in r.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index 4a68505ee0b1..a33c1ea5738b 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -1,5 +1,6 @@ #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] +#![allow(non_local_definitions)] #![allow(unused)] // this should throw an error diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index bf3ed0c2b642..6cd811ae401e 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -1,5 +1,6 @@ #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] +#![allow(non_local_definitions)] #![allow(unused)] // this should throw an error diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index f1370ed844fa..15b4e02a264f 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -1,5 +1,5 @@ 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:8:1 + --> $DIR/from_over_into.rs:9:1 | LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL ~ StringWrapper(val) | 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:16:1 + --> $DIR/from_over_into.rs:17:1 | LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL ~ SelfType(String::new()) | 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:31:1 + --> $DIR/from_over_into.rs:32:1 | LL | impl Into for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL ~ let _: X = val; | 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:43:1 + --> $DIR/from_over_into.rs:44:1 | LL | impl core::convert::Into for crate::ExplicitPaths { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ val.0 | 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:63:1 + --> $DIR/from_over_into.rs:64:1 | LL | impl Into for PathInExpansion { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL ~ fn from(val: PathInExpansion) -> Self { | 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:85:5 + --> $DIR/from_over_into.rs:86:5 | LL | impl Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ FromOverInto(val) | 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 + --> $DIR/from_over_into.rs:96:5 | LL | impl Into<()> for Hello { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed index 888a466278cc..5f2f1bd9916d 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.fixed +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs index a366351ffa45..3e3c7f4db4a2 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.rs +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr index 9a13aa972273..6eb6f2b85a8f 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.stderr +++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr @@ -1,5 +1,5 @@ error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:7:21 + --> $DIR/manual_str_repeat.rs:8:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` @@ -8,55 +8,55 @@ LL | let _: String = std::iter::repeat("test").take(10).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_str_repeat)]` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:8:21 + --> $DIR/manual_str_repeat.rs:9:21 | LL | let _: String = std::iter::repeat('x').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"x".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:9:21 + --> $DIR/manual_str_repeat.rs:10:21 | LL | let _: String = std::iter::repeat('\'').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"'".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:10:21 + --> $DIR/manual_str_repeat.rs:11:21 | LL | let _: String = std::iter::repeat('"').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"\"".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:14:13 + --> $DIR/manual_str_repeat.rs:15:13 | LL | let _ = repeat(x).take(count + 2).collect::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count + 2)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:23:21 + --> $DIR/manual_str_repeat.rs:24:21 | LL | let _: String = repeat(*x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*x).repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:32:21 + --> $DIR/manual_str_repeat.rs:33:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:44:21 + --> $DIR/manual_str_repeat.rs:45:21 | LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Cow::Borrowed("test").repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:47:21 + --> $DIR/manual_str_repeat.rs:48:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:62:21 + --> $DIR/manual_str_repeat.rs:63:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 23e8bf8a468f..998f5430fdf0 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -1,6 +1,7 @@ #![feature(lint_reasons)] #![allow( unused, + non_local_definitions, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 27771a8f15b3..acb2c74d849a 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -1,6 +1,7 @@ #![feature(lint_reasons)] #![allow( unused, + non_local_definitions, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index a21ed8382c14..9034bd83a0b0 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:15:15 + --> $DIR/needless_borrow.rs:16:15 | LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` @@ -8,157 +8,157 @@ LL | let _ = x(&&a); // warn = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:19:13 + --> $DIR/needless_borrow.rs:20:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:31:13 + --> $DIR/needless_borrow.rs:32:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:33:15 + --> $DIR/needless_borrow.rs:34:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:39:27 + --> $DIR/needless_borrow.rs:40:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:46:15 + --> $DIR/needless_borrow.rs:47:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:47:15 + --> $DIR/needless_borrow.rs:48:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:48:15 + --> $DIR/needless_borrow.rs:49:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:49:15 + --> $DIR/needless_borrow.rs:50:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:52:11 + --> $DIR/needless_borrow.rs:53:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:59:13 + --> $DIR/needless_borrow.rs:60:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:60:13 + --> $DIR/needless_borrow.rs:61:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:61:23 + --> $DIR/needless_borrow.rs:62:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:62:23 + --> $DIR/needless_borrow.rs:63:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:71:14 + --> $DIR/needless_borrow.rs:72:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:77:14 + --> $DIR/needless_borrow.rs:78:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:89:13 + --> $DIR/needless_borrow.rs:90:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:91:22 + --> $DIR/needless_borrow.rs:92:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:101:5 + --> $DIR/needless_borrow.rs:102:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:110:5 + --> $DIR/needless_borrow.rs:111:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:136:23 + --> $DIR/needless_borrow.rs:137:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:178:13 + --> $DIR/needless_borrow.rs:179:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:187:13 + --> $DIR/needless_borrow.rs:188:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:224:22 + --> $DIR/needless_borrow.rs:225:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:231:22 + --> $DIR/needless_borrow.rs:232:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:235:22 + --> $DIR/needless_borrow.rs:236:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:236:22 + --> $DIR/needless_borrow.rs:237:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index bddc30b8379b..fdd7fc5fad4e 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -427,6 +427,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } + "ProcessPrng" => { + let [ptr, len] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; + this.gen_random(ptr, len.into())?; + this.write_scalar(Scalar::from_i32(1), dest)?; + } "BCryptGenRandom" => { let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 62fbd57abc16..5a8b18e3fe1b 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -226,6 +226,11 @@ jobs: - name: download typos run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: check for typos run: typos diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml index be9f504e5996..de61b2389ae2 100644 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -67,7 +67,7 @@ jobs: other_metrics: strategy: matrix: - names: [self, rustc_tests, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18] + names: [self, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18] runs-on: ubuntu-latest needs: [setup_cargo, build_metrics] @@ -118,11 +118,6 @@ jobs: with: name: self-${{ github.sha }} - - name: Download rustc_tests metrics - uses: actions/download-artifact@v3 - with: - name: rustc_tests-${{ github.sha }} - - name: Download ripgrep-13.0.0 metrics uses: actions/download-artifact@v3 with: @@ -151,7 +146,7 @@ jobs: chmod 700 ~/.ssh git clone --depth 1 git@github.com:rust-analyzer/metrics.git - jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5] * .[6]" build.json self.json rustc_tests.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json + jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json cd metrics git add . git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈 diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index adb1c8505161..ac536d0fddea 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -59,7 +59,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: fetch-depth: ${{ env.FETCH_DEPTH }} @@ -78,9 +78,9 @@ jobs: rustup component add rust-src - name: Install Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 16 - name: Update apt repositories if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 7b29d7bb798d..3c87291dbadb 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1709,6 +1709,7 @@ dependencies = [ "dissimilar", "expect-test", "indexmap", + "itertools", "linked-hash-map", "lock_api", "oorandom", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index 8229b1ccf3d7..cd14f7b855a8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -6,8 +6,8 @@ use itertools::Itertools; use crate::{ hir::{ - Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, - Movability, Statement, + Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability, + Statement, }, pretty::{print_generic_args, print_path, print_type_ref}, type_ref::TypeRef, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index 540f643ae7d9..f07b1257662d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -40,7 +40,7 @@ pub struct StructData { } bitflags! { - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct StructFlags: u8 { const NO_FLAGS = 0; /// Indicates whether the struct is `PhantomData`. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 38cfcf0f2811..faa1eed15a45 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -477,7 +477,7 @@ mod tests { use expect_test::{expect, Expect}; use test_fixture::WithFixture; - use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup}; + use crate::{test_db::TestDB, ItemContainerId, Lookup}; use super::*; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index be16a5e31a23..bb36950f95ac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -44,13 +44,13 @@ use std::{ ops::{Index, Range}, }; -use ast::{AstNode, HasName, StructKind}; +use ast::{AstNode, StructKind}; use base_db::CrateId; use either::Either; use hir_expand::{ ast_id_map::{AstIdNode, FileAstId}, attrs::RawAttrs, - name::{name, AsName, Name}, + name::Name, ExpandTo, HirFileId, InFile, }; use intern::Interned; @@ -67,7 +67,7 @@ use crate::{ attr::Attrs, db::DefDatabase, generics::{GenericParams, LifetimeParamData, TypeOrConstParamData}, - path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, + path::{GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, visibility::{RawVisibility, VisibilityExplicitness}, BlockId, Lookup, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index b51cb5de0f49..37fdece87681 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -2,17 +2,33 @@ use std::collections::hash_map::Entry; -use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef}; -use syntax::ast::{HasModuleItem, HasTypeBounds, IsString}; +use hir_expand::{ + ast_id_map::AstIdMap, mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId, +}; +use la_arena::Arena; +use syntax::{ + ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString}, + AstNode, +}; +use triomphe::Arc; use crate::{ - generics::{GenericParamsCollector, TypeParamData, TypeParamProvenance}, - type_ref::{LifetimeRef, TraitBoundModifier}, + db::DefDatabase, + generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, + item_tree::{ + AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId, + Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias, + Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, + ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs, + RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, + Use, UseTree, UseTreeKind, Variant, + }, + path::AssociatedTypeBinding, + type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef}, + visibility::RawVisibility, LocalLifetimeParamId, LocalTypeOrConstParamId, }; -use super::*; - fn id(index: Idx) -> FileItemTreeId { FileItemTreeId(index) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index dae876f7ecbc..87c90a4c6ab9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -1,16 +1,22 @@ //! `ItemTree` debug printer. -use std::fmt::Write; +use std::fmt::{self, Write}; use span::ErasedFileAstId; use crate::{ - generics::{WherePredicate, WherePredicateTypeTarget}, + generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, + item_tree::{ + AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields, + FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2, + MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs, + RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union, + Use, UseTree, UseTreeKind, Variant, + }, pretty::{print_path, print_type_bounds, print_type_ref}, + visibility::RawVisibility, }; -use super::*; - pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String { let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 88838f58fe78..32825406505d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -2446,7 +2446,7 @@ mod tests { use base_db::SourceDatabase; use test_fixture::WithFixture; - use crate::{db::DefDatabase, test_db::TestDB}; + use crate::test_db::TestDB; use super::*; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs index bf89ea711a0a..d278b75e8158 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs @@ -1,10 +1,7 @@ use expect_test::expect; -use test_fixture::WithFixture; use itertools::Itertools; -use crate::nameres::tests::check; - use super::*; #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index bd243518fc60..e678a2fee132 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -1,7 +1,7 @@ //! The implementation of `RustIrDatabase` for Chalk, which provides information //! about the code that Chalk needs. use core::ops; -use std::{iter, sync::Arc}; +use std::{iter, ops::ControlFlow, sync::Arc}; use tracing::debug; @@ -10,9 +10,10 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use base_db::CrateId; use hir_def::{ + data::adt::StructFlags, hir::Movability, lang_item::{LangItem, LangItemTarget}, - AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, + AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId, }; use hir_expand::name::name; @@ -33,7 +34,7 @@ use crate::{ pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum; -pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum; +pub(crate) type AdtDatum = chalk_solve::rust_ir::AdtDatum; pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum; pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum; @@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { fn trait_datum(&self, trait_id: TraitId) -> Arc { self.db.trait_datum(self.krate, trait_id) } - fn adt_datum(&self, struct_id: AdtId) -> Arc { - self.db.struct_datum(self.krate, struct_id) + fn adt_datum(&self, struct_id: AdtId) -> Arc { + self.db.adt_datum(self.krate, struct_id) } fn adt_repr(&self, _struct_id: AdtId) -> Arc> { // FIXME: keep track of these @@ -136,81 +137,92 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), }; - let trait_module = trait_.module(self.db.upcast()); - let type_module = match self_ty_fp { - Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())), - Some(TyFingerprint::ForeignType(type_id)) => { - Some(from_foreign_def_id(type_id).module(self.db.upcast())) - } - Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())), - _ => None, - }; - - let mut def_blocks = - [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]; - - // Note: Since we're using impls_for_trait, only impls where the trait - // can be resolved should ever reach Chalk. impl_datum relies on that - // and will panic if the trait can't be resolved. - let in_deps = self.db.trait_impls_in_deps(self.krate); - let in_self = self.db.trait_impls_in_crate(self.krate); - - let block_impls = iter::successors(self.block, |&block_id| { - cov_mark::hit!(block_local_impls); - self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block()) - }) - .inspect(|&block_id| { - // make sure we don't search the same block twice - def_blocks.iter_mut().for_each(|block| { - if *block == Some(block_id) { - *block = None; - } - }); - }) - .filter_map(|block_id| self.db.trait_impls_in_block(block_id)); - let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); + let mut result = vec![]; - match fps { - [] => { - debug!("Unrestricted search for {:?} impls...", trait_); - let mut f = |impls: &TraitImpls| { - result.extend(impls.for_trait(trait_).map(id_to_chalk)); - }; - f(&in_self); - in_deps.iter().map(ops::Deref::deref).for_each(&mut f); - block_impls.for_each(|it| f(&it)); - def_blocks - .into_iter() - .flatten() - .filter_map(|it| self.db.trait_impls_in_block(it)) - .for_each(|it| f(&it)); - } - fps => { - let mut f = - |impls: &TraitImpls| { - result.extend(fps.iter().flat_map(|fp| { - impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) - })); - }; - f(&in_self); - in_deps.iter().map(ops::Deref::deref).for_each(&mut f); - block_impls.for_each(|it| f(&it)); - def_blocks - .into_iter() - .flatten() - .filter_map(|it| self.db.trait_impls_in_block(it)) - .for_each(|it| f(&it)); - } - } + if fps.is_empty() { + debug!("Unrestricted search for {:?} impls...", trait_); + self.for_trait_impls(trait_, self_ty_fp, |impls| { + result.extend(impls.for_trait(trait_).map(id_to_chalk)); + ControlFlow::Continue(()) + }) + } else { + self.for_trait_impls(trait_, self_ty_fp, |impls| { + result.extend( + fps.iter().flat_map(move |fp| { + impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) + }), + ); + ControlFlow::Continue(()) + }) + }; debug!("impls_for_trait returned {} impls", result.len()); result } + fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind) -> bool { debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind); - false // FIXME + + let trait_id = from_chalk_trait_id(auto_trait_id); + let self_ty = kind.clone().intern(Interner); + // We cannot filter impls by `TyFingerprint` for the following types: + let self_ty_fp = match kind { + // because we need to find any impl whose Self type is a ref with the same mutability + // (we don't care about the inner type). + TyKind::Ref(..) => None, + // because we need to find any impl whose Self type is a tuple with the same arity. + TyKind::Tuple(..) => None, + _ => TyFingerprint::for_trait_impl(&self_ty), + }; + + let check_kind = |impl_id| { + let impl_self_ty = self.db.impl_self_ty(impl_id); + // NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions. + let impl_self_kind = impl_self_ty.skip_binders().kind(Interner); + + match (kind, impl_self_kind) { + (TyKind::Adt(id_a, _), TyKind::Adt(id_b, _)) => id_a == id_b, + (TyKind::AssociatedType(id_a, _), TyKind::AssociatedType(id_b, _)) => id_a == id_b, + (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b, + (TyKind::Error, TyKind::Error) + | (TyKind::Str, TyKind::Str) + | (TyKind::Slice(_), TyKind::Slice(_)) + | (TyKind::Never, TyKind::Never) + | (TyKind::Array(_, _), TyKind::Array(_, _)) => true, + (TyKind::Tuple(arity_a, _), TyKind::Tuple(arity_b, _)) => arity_a == arity_b, + (TyKind::OpaqueType(id_a, _), TyKind::OpaqueType(id_b, _)) => id_a == id_b, + (TyKind::FnDef(id_a, _), TyKind::FnDef(id_b, _)) => id_a == id_b, + (TyKind::Ref(id_a, _, _), TyKind::Ref(id_b, _, _)) + | (TyKind::Raw(id_a, _), TyKind::Raw(id_b, _)) => id_a == id_b, + (TyKind::Closure(id_a, _), TyKind::Closure(id_b, _)) => id_a == id_b, + (TyKind::Coroutine(id_a, _), TyKind::Coroutine(id_b, _)) + | (TyKind::CoroutineWitness(id_a, _), TyKind::CoroutineWitness(id_b, _)) => { + id_a == id_b + } + (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a == id_b, + (_, _) => false, + } + }; + + if let Some(fp) = self_ty_fp { + self.for_trait_impls(trait_id, self_ty_fp, |impls| { + match impls.for_trait_and_self_ty(trait_id, fp).any(check_kind) { + true => ControlFlow::Break(()), + false => ControlFlow::Continue(()), + } + }) + } else { + self.for_trait_impls(trait_id, self_ty_fp, |impls| { + match impls.for_trait(trait_id).any(check_kind) { + true => ControlFlow::Break(()), + false => ControlFlow::Continue(()), + } + }) + } + .is_break() } + fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { self.db.associated_ty_value(self.krate, id) } @@ -489,6 +501,59 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { } } +impl<'a> ChalkContext<'a> { + fn for_trait_impls( + &self, + trait_id: hir_def::TraitId, + self_ty_fp: Option, + mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>, + ) -> ControlFlow<()> { + // Note: Since we're using `impls_for_trait` and `impl_provided_for`, + // only impls where the trait can be resolved should ever reach Chalk. + // `impl_datum` relies on that and will panic if the trait can't be resolved. + let in_deps = self.db.trait_impls_in_deps(self.krate); + let in_self = self.db.trait_impls_in_crate(self.krate); + let trait_module = trait_id.module(self.db.upcast()); + let type_module = match self_ty_fp { + Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())), + Some(TyFingerprint::ForeignType(type_id)) => { + Some(from_foreign_def_id(type_id).module(self.db.upcast())) + } + Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())), + _ => None, + }; + + let mut def_blocks = + [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]; + + let block_impls = iter::successors(self.block, |&block_id| { + cov_mark::hit!(block_local_impls); + self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block()) + }) + .inspect(|&block_id| { + // make sure we don't search the same block twice + def_blocks.iter_mut().for_each(|block| { + if *block == Some(block_id) { + *block = None; + } + }); + }) + .filter_map(|block_id| self.db.trait_impls_in_block(block_id)); + f(&in_self)?; + for it in in_deps.iter().map(ops::Deref::deref) { + f(it)?; + } + for it in block_impls { + f(&it)?; + } + for it in def_blocks.into_iter().flatten().filter_map(|it| self.db.trait_impls_in_block(it)) + { + f(&it)?; + } + ControlFlow::Continue(()) + } +} + impl chalk_ir::UnificationDatabase for &dyn HirDatabase { fn fn_def_variance( &self, @@ -590,7 +655,7 @@ pub(crate) fn trait_datum_query( coinductive: false, // only relevant for Chalk testing // FIXME: set these flags correctly marker: false, - fundamental: false, + fundamental: trait_data.fundamental, }; let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect(); @@ -649,35 +714,74 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem { } } -pub(crate) fn struct_datum_query( +pub(crate) fn adt_datum_query( db: &dyn HirDatabase, krate: CrateId, - struct_id: AdtId, -) -> Arc { - debug!("struct_datum {:?}", struct_id); - let chalk_ir::AdtId(adt_id) = struct_id; + chalk_ir::AdtId(adt_id): AdtId, +) -> Arc { + debug!("adt_datum {:?}", adt_id); let generic_params = generics(db.upcast(), adt_id.into()); - let upstream = adt_id.module(db.upcast()).krate() != krate; - let where_clauses = { - let generic_params = generics(db.upcast(), adt_id.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - convert_where_clauses(db, adt_id.into(), &bound_vars) + let bound_vars_subst = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); + let where_clauses = convert_where_clauses(db, adt_id.into(), &bound_vars_subst); + + let (fundamental, phantom_data) = match adt_id { + hir_def::AdtId::StructId(s) => { + let flags = db.struct_data(s).flags; + ( + flags.contains(StructFlags::IS_FUNDAMENTAL), + flags.contains(StructFlags::IS_PHANTOM_DATA), + ) + } + // FIXME set fundamental flags correctly + hir_def::AdtId::UnionId(_) => (false, false), + hir_def::AdtId::EnumId(_) => (false, false), }; let flags = rust_ir::AdtFlags { - upstream, - // FIXME set fundamental and phantom_data flags correctly - fundamental: false, - phantom_data: false, + upstream: adt_id.module(db.upcast()).krate() != krate, + fundamental, + phantom_data, }; - // FIXME provide enum variants properly (for auto traits) - let variant = rust_ir::AdtVariantDatum { - fields: Vec::new(), // FIXME add fields (only relevant for auto traits), + + // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it + let _variant_id_to_fields = |id: VariantId| { + let variant_data = &id.variant_data(db.upcast()); + let fields = if variant_data.fields().is_empty() { + vec![] + } else { + let field_types = db.field_types(id); + variant_data + .fields() + .iter() + .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst)) + .filter(|it| !it.contains_unknown()) + .collect() + }; + rust_ir::AdtVariantDatum { fields } }; - let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses }; - let struct_datum = StructDatum { - // FIXME set ADT kind - kind: rust_ir::AdtKind::Struct, - id: struct_id, + let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] }; + + let (kind, variants) = match adt_id { + hir_def::AdtId::StructId(id) => { + (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())]) + } + hir_def::AdtId::EnumId(id) => { + let variants = db + .enum_data(id) + .variants + .iter() + .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into())) + .collect(); + (rust_ir::AdtKind::Enum, variants) + } + hir_def::AdtId::UnionId(id) => { + (rust_ir::AdtKind::Union, vec![variant_id_to_fields(id.into())]) + } + }; + + let struct_datum_bound = rust_ir::AdtDatumBound { variants, where_clauses }; + let struct_datum = AdtDatum { + kind, + id: chalk_ir::AdtId(adt_id), binders: make_binders(db, &generic_params, struct_datum_bound), flags, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index fbd366864a43..f9e8cff55393 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -90,7 +90,7 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders; - /// Returns the type of the value of the given constant, or `None` if the the `ValueTyDefId` is + /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. #[salsa::invoke(crate::lower::value_ty_query)] fn value_ty(&self, def: ValueTyDefId) -> Option>; @@ -220,12 +220,12 @@ pub trait HirDatabase: DefDatabase + Upcast { trait_id: chalk_db::TraitId, ) -> sync::Arc; - #[salsa::invoke(chalk_db::struct_datum_query)] - fn struct_datum( + #[salsa::invoke(chalk_db::adt_datum_query)] + fn adt_datum( &self, krate: CrateId, struct_id: chalk_db::AdtId, - ) -> sync::Arc; + ) -> sync::Arc; #[salsa::invoke(chalk_db::impl_datum_query)] fn impl_datum( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index c4329a7b82bf..6c8a18751657 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -12,6 +12,8 @@ use hir_expand::name; use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_pattern_analysis::usefulness::{compute_match_usefulness, ValidityConstraint}; +use syntax::{ast, AstNode}; +use tracing::debug; use triomphe::Arc; use typed_arena::Arena; @@ -44,6 +46,10 @@ pub enum BodyValidationDiagnostic { match_expr: ExprId, uncovered_patterns: String, }, + NonExhaustiveLet { + pat: PatId, + uncovered_patterns: String, + }, RemoveTrailingReturn { return_expr: ExprId, }, @@ -57,7 +63,8 @@ impl BodyValidationDiagnostic { let _p = tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); - let mut validator = ExprValidator::new(owner, infer); + let body = db.body(owner); + let mut validator = ExprValidator { owner, body, infer, diagnostics: Vec::new() }; validator.validate_body(db); validator.diagnostics } @@ -65,18 +72,16 @@ impl BodyValidationDiagnostic { struct ExprValidator { owner: DefWithBodyId, + body: Arc, infer: Arc, - pub(super) diagnostics: Vec, + diagnostics: Vec, } impl ExprValidator { - fn new(owner: DefWithBodyId, infer: Arc) -> ExprValidator { - ExprValidator { owner, infer, diagnostics: Vec::new() } - } - fn validate_body(&mut self, db: &dyn HirDatabase) { - let body = db.body(self.owner); let mut filter_map_next_checker = None; + // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint + let body = Arc::clone(&self.body); if matches!(self.owner, DefWithBodyId::FunctionId(_)) { self.check_for_trailing_return(body.body_expr, &body); @@ -104,7 +109,10 @@ impl ExprValidator { self.check_for_trailing_return(*body_expr, &body); } Expr::If { .. } => { - self.check_for_unnecessary_else(id, expr, &body); + self.check_for_unnecessary_else(id, expr, db); + } + Expr::Block { .. } => { + self.validate_block(db, expr); } _ => {} } @@ -162,8 +170,6 @@ impl ExprValidator { arms: &[MatchArm], db: &dyn HirDatabase, ) { - let body = db.body(self.owner); - let scrut_ty = &self.infer[scrutinee_expr]; if scrut_ty.is_unknown() { return; @@ -191,12 +197,12 @@ impl ExprValidator { .as_reference() .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) .unwrap_or(false)) - && types_of_subpatterns_do_match(arm.pat, &body, &self.infer) + && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer) { // If we had a NotUsefulMatchArm diagnostic, we could // check the usefulness of each pattern as we added it // to the matrix here. - let pat = self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors); + let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors); let m_arm = pat_analysis::MatchArm { pat: pattern_arena.alloc(pat), has_guard: arm.guard.is_some(), @@ -234,20 +240,63 @@ impl ExprValidator { if !witnesses.is_empty() { self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr, - uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, arms), + uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, m_arms.is_empty()), }); } } + fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) { + let Expr::Block { statements, .. } = expr else { return }; + let pattern_arena = Arena::new(); + let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db); + for stmt in &**statements { + let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { + continue; + }; + let Some(initializer) = initializer else { continue }; + let ty = &self.infer[initializer]; + + let mut have_errors = false; + let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors); + let match_arm = rustc_pattern_analysis::MatchArm { + pat: pattern_arena.alloc(deconstructed_pat), + has_guard: false, + arm_data: (), + }; + if have_errors { + continue; + } + + let report = match compute_match_usefulness( + &cx, + &[match_arm], + ty.clone(), + ValidityConstraint::ValidOnly, + ) { + Ok(v) => v, + Err(e) => { + debug!(?e, "match usefulness error"); + continue; + } + }; + let witnesses = report.non_exhaustiveness_witnesses; + if !witnesses.is_empty() { + self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet { + pat, + uncovered_patterns: missing_match_arms(&cx, ty, witnesses, false), + }); + } + } + } + fn lower_pattern<'p>( &self, cx: &MatchCheckCtx<'p>, pat: PatId, db: &dyn HirDatabase, - body: &Body, have_errors: &mut bool, ) -> DeconstructedPat<'p> { - let mut patcx = match_check::PatCtxt::new(db, &self.infer, body); + let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body); let pattern = patcx.lower_pattern(pat); let pattern = cx.lower_pat(&pattern); if !patcx.errors.is_empty() { @@ -288,12 +337,12 @@ impl ExprValidator { } } - fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, body: &Body) { + fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) { if let Expr::If { condition: _, then_branch, else_branch } = expr { if else_branch.is_none() { return; } - if let Expr::Block { statements, tail, .. } = &body.exprs[*then_branch] { + if let Expr::Block { statements, tail, .. } = &self.body.exprs[*then_branch] { let last_then_expr = tail.or_else(|| match statements.last()? { Statement::Expr { expr, .. } => Some(*expr), _ => None, @@ -301,6 +350,36 @@ impl ExprValidator { if let Some(last_then_expr) = last_then_expr { let last_then_expr_ty = &self.infer[last_then_expr]; if last_then_expr_ty.is_never() { + // Only look at sources if the then branch diverges and we have an else branch. + let (_, source_map) = db.body_with_source_map(self.owner); + let Ok(source_ptr) = source_map.expr_syntax(id) else { + return; + }; + let root = source_ptr.file_syntax(db.upcast()); + let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else { + return; + }; + let mut top_if_expr = if_expr; + loop { + let parent = top_if_expr.syntax().parent(); + let has_parent_expr_stmt_or_stmt_list = + parent.as_ref().map_or(false, |node| { + ast::ExprStmt::can_cast(node.kind()) + | ast::StmtList::can_cast(node.kind()) + }); + if has_parent_expr_stmt_or_stmt_list { + // Only emit diagnostic if parent or direct ancestor is either + // an expr stmt or a stmt list. + break; + } + let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else { + // Bail if parent is neither an if expr, an expr stmt nor a stmt list. + return; + }; + // Check parent if expr. + top_if_expr = parent_if_expr; + } + self.diagnostics .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id }) } @@ -448,7 +527,7 @@ fn missing_match_arms<'p>( cx: &MatchCheckCtx<'p>, scrut_ty: &Ty, witnesses: Vec>, - arms: &[MatchArm], + arms_is_empty: bool, ) -> String { struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>); impl fmt::Display for DisplayWitness<'_, '_> { @@ -463,7 +542,7 @@ fn missing_match_arms<'p>( Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(), _ => false, }; - if arms.is_empty() && !non_empty_enum { + if arms_is_empty && !non_empty_enum { format!("type `{}` is non-empty", scrut_ty.display(cx.db)) } else { let pat_display = |witness| DisplayWitness(witness, cx); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 1977f00517cd..9cea414e1a00 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -221,6 +221,9 @@ pub enum InferenceDiagnostic { UnresolvedAssocItem { id: ExprOrPatId, }, + UnresolvedIdent { + expr: ExprId, + }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { expr: ExprId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 428ed6748c6c..c377a51e7d3b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -13,7 +13,7 @@ use hir_def::{ ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp, }, lang_item::{LangItem, LangItemTarget}, - path::{GenericArg, GenericArgs}, + path::{GenericArg, GenericArgs, Path}, BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId, }; use hir_expand::name::{name, Name}; @@ -439,7 +439,17 @@ impl InferenceContext<'_> { } Expr::Path(p) => { let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr); - let ty = self.infer_path(p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()); + let ty = match self.infer_path(p, tgt_expr.into()) { + Some(ty) => ty, + None => { + if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident()) { + self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { + expr: tgt_expr, + }); + } + self.err_ty() + } + }; self.resolver.reset_to_guard(g); ty } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index fbe6a982d6f8..628a1fe2d283 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1,12 +1,20 @@ //! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation //! is not available. - +//! use std::cmp; use chalk_ir::TyKind; -use hir_def::builtin_type::{BuiltinInt, BuiltinUint}; +use hir_def::{ + builtin_type::{BuiltinInt, BuiltinUint}, + resolver::HasResolver, +}; -use super::*; +use crate::mir::eval::{ + name, pad16, static_lifetime, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, + HasModule, HirDisplay, Interned, InternedClosure, Interner, Interval, IntervalAndTy, + IntervalOrOwned, ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, + ModPath, Mutability, Result, Substitution, Ty, TyBuilder, TyExt, +}; mod simd; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index eddfd0acfb98..e229a4ab3172 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -2,6 +2,7 @@ use std::cmp::Ordering; +use crate::consteval::try_const_usize; use crate::TyKind; use super::*; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 9fe3d5b77aec..ed316f972689 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1,6 +1,6 @@ //! This module generates a polymorphic MIR from a hir body -use std::{fmt::Write, mem}; +use std::{fmt::Write, iter, mem}; use base_db::{salsa::Cycle, FileId}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; @@ -14,27 +14,37 @@ use hir_def::{ lang_item::{LangItem, LangItemTarget}, path::Path, resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs}, - AdtId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, + AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, TypeOrConstParamId, }; use hir_expand::name::Name; +use la_arena::ArenaMap; +use rustc_hash::FxHashMap; use syntax::TextRange; use triomphe::Arc; use crate::{ consteval::ConstEvalError, - db::InternedClosure, + db::{HirDatabase, InternedClosure}, + display::HirDisplay, infer::{CaptureKind, CapturedItem, TypeMismatch}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, + mapping::ToChalk, + mir::{ + intern_const_scalar, return_slot, AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, + BorrowKind, CastKind, ClosureId, ConstScalar, Either, Expr, FieldId, Idx, InferenceResult, + Interner, Local, LocalId, MemoryMap, MirBody, MirSpan, Mutability, Operand, Place, + PlaceElem, PointerCast, ProjectionElem, ProjectionStore, RawIdx, Rvalue, Statement, + StatementKind, Substitution, SwitchTargets, Terminator, TerminatorKind, TupleFieldId, Ty, + UnOp, VariantId, + }, static_lifetime, traits::FnTrait, utils::{generics, ClosureSubst}, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; -use super::*; - mod as_place; mod pattern_matching; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 02b1494062fe..85c8d1685b87 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -1,10 +1,17 @@ //! MIR lowering for patterns -use hir_def::AssocItemId; +use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId}; -use crate::BindingMode; - -use super::*; +use crate::{ + mir::lower::{ + BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner, + MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place, + PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, + Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, + ValueNs, VariantData, VariantId, + }, + BindingMode, +}; macro_rules! not_supported { ($x: expr) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index db14addaf185..879c69c758fc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4553,3 +4553,58 @@ fn foo() { "#, ); } + +#[test] +fn auto_trait_bound() { + check_types( + r#" +//- minicore: sized +auto trait Send {} +impl !Send for *const T {} + +struct Yes; +trait IsSend { const IS_SEND: Yes; } +impl IsSend for T { const IS_SEND: Yes = Yes; } + +struct Struct(T); +enum Enum { A, B(T) } +union Union { t: T } + +#[lang = "phantom_data"] +struct PhantomData; + +fn f() { + T::IS_SEND; + //^^^^^^^^^^Yes + U::IS_SEND; + //^^^^^^^^^^{unknown} + <*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^{unknown} + Struct::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^Yes + Struct::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^Yes + Struct::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes + Enum::::IS_SEND; + //^^^^^^^^^^^^^^^^^^Yes + Enum::::IS_SEND; + //^^^^^^^^^^^^^^^^^^Yes + Enum::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^Yes + Union::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^Yes + Union::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^Yes + Union::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes + PhantomData::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^Yes + PhantomData::::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^{unknown} + PhantomData::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown} +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 08843a6c9994..80cd0c9c794b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -64,6 +64,7 @@ diagnostics![ MissingUnsafe, MovedOutOfRef, NeedMut, + NonExhaustiveLet, NoSuchField, PrivateAssocItem, PrivateField, @@ -86,6 +87,7 @@ diagnostics![ UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, + UnresolvedIdent, UnresolvedProcMacro, UnusedMut, UnusedVariable, @@ -241,6 +243,11 @@ pub struct UnresolvedAssocItem { pub expr_or_pat: InFile>>>, } +#[derive(Debug)] +pub struct UnresolvedIdent { + pub expr: InFile>, +} + #[derive(Debug)] pub struct PrivateField { pub expr: InFile>, @@ -280,6 +287,12 @@ pub struct MissingMatchArms { pub uncovered_patterns: String, } +#[derive(Debug)] +pub struct NonExhaustiveLet { + pub pat: InFile>, + pub uncovered_patterns: String, +} + #[derive(Debug)] pub struct TypeMismatch { pub expr_or_pat: InFile>>, @@ -456,6 +469,22 @@ impl AnyDiagnostic { Err(SyntheticSyntax) => (), } } + BodyValidationDiagnostic::NonExhaustiveLet { pat, uncovered_patterns } => { + match source_map.pat_syntax(pat) { + Ok(source_ptr) => { + if let Some(ast_pat) = source_ptr.value.cast::() { + return Some( + NonExhaustiveLet { + pat: InFile::new(source_ptr.file_id, ast_pat), + uncovered_patterns, + } + .into(), + ); + } + } + Err(SyntheticSyntax) => {} + } + } BodyValidationDiagnostic::RemoveTrailingReturn { return_expr } => { if let Ok(source_ptr) = source_map.expr_syntax(return_expr) { // Filters out desugared return expressions (e.g. desugared try operators). @@ -565,6 +594,10 @@ impl AnyDiagnostic { }; UnresolvedAssocItem { expr_or_pat }.into() } + &InferenceDiagnostic::UnresolvedIdent { expr } => { + let expr = expr_syntax(expr); + UnresolvedIdent { expr }.into() + } &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => { let expr = expr_syntax(expr); BreakOutsideOfLoop { expr, is_break, bad_value_break }.into() diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 08f7bb14caa3..2d8811cf5ebe 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2653,6 +2653,37 @@ impl ItemInNs { } } +/// Invariant: `inner.as_extern_assoc_item(db).is_some()` +/// We do not actively enforce this invariant. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ExternAssocItem { + Function(Function), + Static(Static), + TypeAlias(TypeAlias), +} + +pub trait AsExternAssocItem { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option; +} + +impl AsExternAssocItem for Function { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option { + as_extern_assoc_item(db, ExternAssocItem::Function, self.id) + } +} + +impl AsExternAssocItem for Static { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option { + as_extern_assoc_item(db, ExternAssocItem::Static, self.id) + } +} + +impl AsExternAssocItem for TypeAlias { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option { + as_extern_assoc_item(db, ExternAssocItem::TypeAlias, self.id) + } +} + /// Invariant: `inner.as_assoc_item(db).is_some()` /// We do not actively enforce this invariant. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -2727,6 +2758,63 @@ where } } +fn as_extern_assoc_item<'db, ID, DEF, LOC>( + db: &(dyn HirDatabase + 'db), + ctor: impl FnOnce(DEF) -> ExternAssocItem, + id: ID, +) -> Option +where + ID: Lookup = dyn DefDatabase + 'db, Data = AssocItemLoc>, + DEF: From, + LOC: ItemTreeNode, +{ + match id.lookup(db.upcast()).container { + ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), + ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) | ItemContainerId::ModuleId(_) => { + None + } + } +} + +impl ExternAssocItem { + pub fn name(self, db: &dyn HirDatabase) -> Name { + match self { + Self::Function(it) => it.name(db), + Self::Static(it) => it.name(db), + Self::TypeAlias(it) => it.name(db), + } + } + + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + Self::Function(f) => f.module(db), + Self::Static(c) => c.module(db), + Self::TypeAlias(t) => t.module(db), + } + } + + pub fn as_function(self) -> Option { + match self { + Self::Function(v) => Some(v), + _ => None, + } + } + + pub fn as_static(self) -> Option { + match self { + Self::Static(v) => Some(v), + _ => None, + } + } + + pub fn as_type_alias(self) -> Option { + match self { + Self::TypeAlias(v) => Some(v), + _ => None, + } + } +} + impl AssocItem { pub fn name(self, db: &dyn HirDatabase) -> Option { match self { @@ -3798,9 +3886,9 @@ impl Type { // For non-phantom_data adts we check variants/fields as well as generic parameters TyKind::Adt(adt_id, substitution) - if !db.struct_datum(krate, *adt_id).flags.phantom_data => + if !db.adt_datum(krate, *adt_id).flags.phantom_data => { - let adt_datum = &db.struct_datum(krate, *adt_id); + let adt_datum = &db.adt_datum(krate, *adt_id); let adt_datum_bound = adt_datum.binders.clone().substitute(Interner, substitution); adt_datum_bound diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index 666d63ac1558..edbf75affe64 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -281,14 +281,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) { return None; } - let fileds = it.fields(db); + let fields = it.fields(db); // Check if all fields are visible, otherwise we cannot fill them - if fileds.iter().any(|it| !it.is_visible_from(db, module)) { + if fields.iter().any(|it| !it.is_visible_from(db, module)) { return None; } // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = fileds + let param_exprs: Vec> = fields .into_iter() .map(|field| lookup.find(db, &field.ty(db))) .collect::>()?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index c2c0641961a6..4bab2886851a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -308,7 +308,7 @@ impl CompletionRelevance { // When a fn is bumped due to return type: // Bump Constructor or Builder methods with no arguments, - // over them tha with self arguments + // over them than with self arguments if fn_score > 0 { if !asf.has_params { // bump associated functions diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs index 296253aa1ee1..2b2df144d6dd 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs @@ -17,7 +17,7 @@ impl RootDatabase { pub fn request_cancellation(&mut self) { let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::request_cancellation").entered(); - self.salsa_runtime_mut().synthetic_write(Durability::LOW); + self.synthetic_write(Durability::LOW); } pub fn apply_change(&mut self, change: Change) { @@ -124,7 +124,7 @@ impl RootDatabase { hir::db::InternCoroutineQuery hir::db::AssociatedTyDataQuery hir::db::TraitDatumQuery - hir::db::StructDatumQuery + hir::db::AdtDatumQuery hir::db::ImplDatumQuery hir::db::FnDefDatumQuery hir::db::FnDefVarianceQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index d95d94ec72e2..1b6ff8bad53c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -8,11 +8,11 @@ use arrayvec::ArrayVec; use either::Either; use hir::{ - Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, - DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam, - HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, - Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, - Visibility, + Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, + Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, + Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, + ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, + TypeAlias, Variant, VariantDef, Visibility, }; use stdx::{format_to, impl_from}; use syntax::{ @@ -213,8 +213,8 @@ impl Definition { }) } - pub fn label(&self, db: &RootDatabase) -> Option { - let label = match *self { + pub fn label(&self, db: &RootDatabase) -> String { + match *self { Definition::Macro(it) => it.display(db).to_string(), Definition::Field(it) => it.display(db).to_string(), Definition::TupleField(it) => it.display(db).to_string(), @@ -241,7 +241,11 @@ impl Definition { } } Definition::SelfType(impl_def) => { - impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? + let self_ty = &impl_def.self_ty(db); + match self_ty.as_adt() { + Some(it) => it.display(db).to_string(), + None => self_ty.display(db).to_string(), + } } Definition::GenericParam(it) => it.display(db).to_string(), Definition::Label(it) => it.name(db).display(db).to_string(), @@ -249,8 +253,7 @@ impl Definition { Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)), Definition::ToolModule(it) => it.name(db).to_string(), Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), - }; - Some(label) + } } } @@ -739,6 +742,17 @@ impl AsAssocItem for Definition { } } +impl AsExternAssocItem for Definition { + fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { + match self { + Definition::Function(it) => it.as_extern_assoc_item(db), + Definition::Static(it) => it.as_extern_assoc_item(db), + Definition::TypeAlias(it) => it.as_extern_assoc_item(db), + _ => None, + } + } +} + impl From for Definition { fn from(assoc_item: AssocItem) -> Self { match assoc_item { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 6b0fecae2675..10c285a13fbc 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1,4 +1,3 @@ -use hir::PrefixKind; use stdx::trim_indent; use test_fixture::WithFixture; use test_utils::{assert_eq_text, CURSOR_MARKER}; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 2881748dd477..d31dad514aa5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -280,7 +280,7 @@ impl RootDatabase { // hir_db::InternCoroutineQuery hir_db::AssociatedTyDataQuery hir_db::TraitDatumQuery - hir_db::StructDatumQuery + hir_db::AdtDatumQuery hir_db::ImplDatumQuery hir_db::FnDefDatumQuery hir_db::FnDefVarianceQuery diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 722161282fe6..c65467a43249 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -394,7 +394,6 @@ impl Query { mod tests { use expect_test::expect_file; - use hir::symbols::SymbolCollector; use test_fixture::WithFixture; use super::*; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs index 7db5ea04fbd0..785a42352bfa 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -60,6 +60,7 @@ fn f() { #[cfg(a)] let x = 0; // let statement //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + fn abc() {} abc(#[cfg(a)] 0); //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled let x = Struct { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 5e2541795ca1..db28928a24ea 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -512,7 +512,7 @@ impl BAD_TRAIT for () { fn BadFunction() {} } "#, - std::iter::once("unused_variables".to_owned()), + &["unused_variables"], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index c70f39eb286f..09daefd084dc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -634,7 +634,8 @@ struct TestStruct { one: i32, two: i64 } fn test_fn() { let one = 1; - let s = TestStruct{ ..a }; + let a = TestStruct{ one, two: 2 }; + let _ = TestStruct{ ..a }; } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 7632fdf1d090..8596f5792e0f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -18,7 +18,9 @@ pub(crate) fn missing_match_arms( #[cfg(test)] mod tests { use crate::{ - tests::{check_diagnostics, check_diagnostics_with_config}, + tests::{ + check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled, + }, DiagnosticsConfig, }; @@ -282,7 +284,7 @@ fn main() { cov_mark::check_count!(validate_match_bailed_out, 4); // Match statements with arms that don't match the // expression pattern do not fire this diagnostic. - check_diagnostics( + check_diagnostics_with_disabled( r#" enum Either { A, B } enum Either2 { C, D } @@ -307,6 +309,7 @@ fn main() { match Unresolved::Bar { Unresolved::Baz => () } } "#, + &["E0425"], ); } @@ -397,11 +400,11 @@ fn main() { match loop {} { Either::A => (), } - match loop { break Foo::A } { - //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered + match loop { break Either::A } { + //^^^^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered Either::A => (), } - match loop { break Foo::A } { + match loop { break Either::A } { Either::A => (), Either::B => (), } @@ -977,7 +980,7 @@ fn f(ty: Enum) { #[test] fn unexpected_ty_fndef() { cov_mark::check!(validate_match_bailed_out); - check_diagnostics( + check_diagnostics_with_disabled( r" enum Exp { Tuple(()), @@ -987,6 +990,7 @@ fn f() { Exp::Tuple => {} } }", + &["E0425"], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index bdb55a9d98a2..91f1058d65bb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -448,7 +448,7 @@ fn main(b: bool) { &mut x; } "#, - std::iter::once("remove-unnecessary-else".to_owned()), + &["remove-unnecessary-else"], ); check_diagnostics_with_disabled( r#" @@ -463,7 +463,7 @@ fn main(b: bool) { &mut x; } "#, - std::iter::once("remove-unnecessary-else".to_owned()), + &["remove-unnecessary-else"], ); } @@ -817,7 +817,7 @@ fn f() { //- minicore: option fn f(_: i32) {} fn main() { - let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)); + let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)) else { return }; //^^^^^ 💡 warn: variable does not need to be mutable f(x); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs new file mode 100644 index 000000000000..1a4d2877ef25 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs @@ -0,0 +1,47 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: non-exhaustive-let +// +// This diagnostic is triggered if a `let` statement without an `else` branch has a non-exhaustive +// pattern. +pub(crate) fn non_exhaustive_let( + ctx: &DiagnosticsContext<'_>, + d: &hir::NonExhaustiveLet, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0005"), + format!("non-exhaustive pattern: {}", d.uncovered_patterns), + d.pat.map(Into::into), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn option_nonexhaustive() { + check_diagnostics( + r#" +//- minicore: option +fn main() { + let None = Some(5); + //^^^^ error: non-exhaustive pattern: `Some(_)` not covered +} +"#, + ); + } + + #[test] + fn option_exhaustive() { + check_diagnostics( + r#" +//- minicore: option +fn main() { + let Some(_) | None = Some(5); +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs index b7667dc318f0..7a040e46e338 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs @@ -140,7 +140,7 @@ fn foo(x: usize) -> u8 { } //^^^^^^^^^ 💡 weak: replace return ; with } "#, - std::iter::once("remove-unnecessary-else".to_owned()), + &["remove-unnecessary-else"], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs index ae8241ec2c69..47844876dc54 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs @@ -2,7 +2,10 @@ use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt}; use ide_db::{assists::Assist, source_change::SourceChange}; use itertools::Itertools; use syntax::{ - ast::{self, edit::IndentLevel}, + ast::{ + self, + edit::{AstNodeEdit, IndentLevel}, + }, AstNode, SyntaxToken, TextRange, }; use text_edit::TextEdit; @@ -41,10 +44,15 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option { - block.statements().map(|stmt| format!("\n{indent}{stmt}")).join("") - } - ast::ElseBranch::IfExpr(ref nested_if_expr) => { + ast::ElseBranch::Block(block) => block + .statements() + .map(|stmt| format!("\n{indent}{stmt}")) + .chain(block.tail_expr().map(|tail| format!("\n{indent}{tail}"))) + .join(""), + ast::ElseBranch::IfExpr(mut nested_if_expr) => { + if has_parent_if_expr { + nested_if_expr = nested_if_expr.indent(IndentLevel(1)) + } format!("\n{indent}{nested_if_expr}") } }; @@ -87,15 +95,11 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option i32 { + if a { + return 1; + } else { + //^^^^ 💡 weak: remove unnecessary else block + 0 + } +} +"#, + &["needless_return", "E0425"], + ); + check_fix( + r#" +fn test(a: bool) -> i32 { + if a { + return 1; + } else$0 { + 0 + } +} +"#, + r#" +fn test(a: bool) -> i32 { + if a { + return 1; + } + 0 +} +"#, + ); + } + #[test] fn remove_unnecessary_else_for_return_in_child_if_expr() { - check_diagnostics_with_needless_return_disabled( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -186,6 +228,7 @@ fn test() { } } "#, + &["needless_return", "E0425"], ); check_fix( r#" @@ -214,9 +257,44 @@ fn test() { ); } + #[test] + fn remove_unnecessary_else_for_return_in_child_if_expr2() { + check_fix( + r#" +fn test() { + if foo { + do_something(); + } else if qux { + return bar; + } else$0 if quux { + do_something_else(); + } else { + do_something_else2(); + } +} +"#, + r#" +fn test() { + if foo { + do_something(); + } else { + if qux { + return bar; + } + if quux { + do_something_else(); + } else { + do_something_else2(); + } + } +} +"#, + ); + } + #[test] fn remove_unnecessary_else_for_break() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn test() { loop { @@ -229,6 +307,7 @@ fn test() { } } "#, + &["E0425"], ); check_fix( r#" @@ -257,7 +336,7 @@ fn test() { #[test] fn remove_unnecessary_else_for_continue() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn test() { loop { @@ -270,6 +349,7 @@ fn test() { } } "#, + &["E0425"], ); check_fix( r#" @@ -298,7 +378,7 @@ fn test() { #[test] fn remove_unnecessary_else_for_never() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -313,6 +393,7 @@ fn never() -> ! { loop {} } "#, + &["E0425"], ); check_fix( r#" @@ -345,7 +426,7 @@ fn never() -> ! { #[test] fn no_diagnostic_if_no_else_branch() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -355,12 +436,13 @@ fn test() { do_something_else(); } "#, + &["E0425"], ); } #[test] fn no_diagnostic_if_no_divergence() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -370,12 +452,13 @@ fn test() { } } "#, + &["E0425"], ); } #[test] fn no_diagnostic_if_no_divergence_in_else_branch() { - check_diagnostics_with_needless_return_disabled( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -385,6 +468,43 @@ fn test() { } } "#, + &["needless_return", "E0425"], + ); + } + + #[test] + fn no_diagnostic_if_not_expr_stmt() { + check_diagnostics_with_disabled( + r#" +fn test1() { + let _x = if a { + return; + } else { + 1 + }; +} + +fn test2() { + let _x = if a { + return; + } else if b { + return; + } else if c { + 1 + } else { + return; + }; +} +"#, + &["needless_return", "E0425"], + ); + check_diagnostics_with_disabled( + r#" +fn test3() -> u8 { + foo(if a { return 1 } else { 0 }) +} +"#, + &["E0425"], ); } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 8c97281b7832..4c255322280f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -730,7 +730,7 @@ fn f() -> i32 { } fn g() { return; } "#, - std::iter::once("needless_return".to_owned()), + &["needless_return"], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs index a6a0fdc655fb..97943b7e8b34 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -38,10 +38,12 @@ fn foo() { fn while_let_loop_with_label_in_condition() { check_diagnostics( r#" +//- minicore: option + fn foo() { let mut optional = Some(0); - 'my_label: while let Some(a) = match optional { + 'my_label: while let Some(_) = match optional { None => break 'my_label, Some(val) => Some(val), } { @@ -59,8 +61,8 @@ fn foo() { r#" //- minicore: iterator fn foo() { - 'xxx: for _ in unknown { - 'yyy: for _ in unknown { + 'xxx: for _ in [] { + 'yyy: for _ in [] { break 'xxx; continue 'yyy; break 'zzz; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 65abfd8a294b..4c01a2d155a2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -78,7 +78,9 @@ fn method_fix( #[cfg(test)] mod tests { use crate::{ - tests::{check_diagnostics, check_diagnostics_with_config}, + tests::{ + check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled, + }, DiagnosticsConfig, }; @@ -148,7 +150,7 @@ fn foo() { #[test] fn no_diagnostic_on_unknown() { - check_diagnostics( + check_diagnostics_with_disabled( r#" fn foo() { x.foo; @@ -156,6 +158,7 @@ fn foo() { (&((x,),),).foo; } "#, + &["E0425"], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs new file mode 100644 index 000000000000..295c8a2c615f --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs @@ -0,0 +1,46 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: unresolved-ident +// +// This diagnostic is triggered if an expr-position ident is invalid. +pub(crate) fn unresolved_ident( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnresolvedIdent, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0425"), + "no such value in this scope", + d.expr.map(Into::into), + ) + .experimental() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn missing() { + check_diagnostics( + r#" +fn main() { + let _ = x; + //^ error: no such value in this scope +} +"#, + ); + } + + #[test] + fn present() { + check_diagnostics( + r#" +fn main() { + let x = 5; + let _ = x; +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 648d081898ce..0614fdc5514a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -335,8 +335,8 @@ fn main() { r#" struct Foo { bar: i32 } fn foo() { - Foo { bar: i32 }.bar(); - // ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists + Foo { bar: 0 }.bar(); + // ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs index 863a7ab783ec..79bcaa0a9c4c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -4,7 +4,7 @@ use ide_db::{ source_change::SourceChange, }; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxNode}; +use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; @@ -43,7 +43,7 @@ pub(crate) fn useless_braces( "Unnecessary braces in use statement".to_owned(), FileRange { file_id, range: use_range }, ) - .with_main_node(InFile::new(file_id.into(), node.clone())) + .with_main_node(InFile::new(file_id.into(), SyntaxNodePtr::new(node))) .with_fixes(Some(vec![fix( "remove_braces", "Remove unnecessary braces", diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 9d21bb4cd9fb..9f4368b04e79 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -41,6 +41,7 @@ mod handlers { pub(crate) mod moved_out_of_ref; pub(crate) mod mutability_errors; pub(crate) mod no_such_field; + pub(crate) mod non_exhaustive_let; pub(crate) mod private_assoc_item; pub(crate) mod private_field; pub(crate) mod remove_trailing_return; @@ -58,6 +59,7 @@ mod handlers { pub(crate) mod unresolved_assoc_item; pub(crate) mod unresolved_extern_crate; pub(crate) mod unresolved_field; + pub(crate) mod unresolved_ident; pub(crate) mod unresolved_import; pub(crate) mod unresolved_macro_call; pub(crate) mod unresolved_method; @@ -140,7 +142,7 @@ pub struct Diagnostic { pub experimental: bool, pub fixes: Option>, // The node that will be affected by `#[allow]` and similar attributes. - pub main_node: Option>, + pub main_node: Option>, } impl Diagnostic { @@ -172,9 +174,8 @@ impl Diagnostic { message: impl Into, node: InFile, ) -> Diagnostic { - let file_id = node.file_id; Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node)) - .with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id)))) + .with_main_node(node) } fn experimental(mut self) -> Diagnostic { @@ -182,7 +183,7 @@ impl Diagnostic { self } - fn with_main_node(mut self, main_node: InFile) -> Diagnostic { + fn with_main_node(mut self, main_node: InFile) -> Diagnostic { self.main_node = Some(main_node); self } @@ -359,6 +360,7 @@ pub fn diagnostics( AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d), AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d), + AnyDiagnostic::NonExhaustiveLet(d) => handlers::non_exhaustive_let::non_exhaustive_let(&ctx, &d), AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), @@ -375,6 +377,7 @@ pub fn diagnostics( AnyDiagnostic::UnresolvedAssocItem(d) => handlers::unresolved_assoc_item::unresolved_assoc_item(&ctx, &d), AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), AnyDiagnostic::UnresolvedField(d) => handlers::unresolved_field::unresolved_field(&ctx, &d), + AnyDiagnostic::UnresolvedIdent(d) => handlers::unresolved_ident::unresolved_ident(&ctx, &d), AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d), @@ -390,8 +393,17 @@ pub fn diagnostics( res.push(d) } - let mut diagnostics_of_range = - res.iter_mut().filter_map(|x| Some((x.main_node.clone()?, x))).collect::>(); + let mut diagnostics_of_range = res + .iter_mut() + .filter_map(|it| { + Some(( + it.main_node + .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id)))) + .clone()?, + it, + )) + }) + .collect::>(); let mut rustc_stack: FxHashMap> = FxHashMap::default(); let mut clippy_stack: FxHashMap> = FxHashMap::default(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 4e4a851f67e0..901ceffbb266 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -198,12 +198,9 @@ pub(crate) fn check_diagnostics(ra_fixture: &str) { } #[track_caller] -pub(crate) fn check_diagnostics_with_disabled( - ra_fixture: &str, - disabled: impl Iterator, -) { +pub(crate) fn check_diagnostics_with_disabled(ra_fixture: &str, disabled: &[&str]) { let mut config = DiagnosticsConfig::test_sample(); - config.disabled.extend(disabled); + config.disabled.extend(disabled.iter().map(|&s| s.to_owned())); check_diagnostics_with_config(config, ra_fixture) } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 19b181ae3b61..4a7350feb385 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -147,7 +147,7 @@ fn hover_simple( if let Some(doc_comment) = token_as_doc_comment(&original_token) { cov_mark::hit!(no_highlight_on_comment_hover); return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| { - let res = hover_for_definition(sema, file_id, def, &node, config)?; + let res = hover_for_definition(sema, file_id, def, &node, config); Some(RangeInfo::new(range, res)) }); } @@ -161,7 +161,7 @@ fn hover_simple( Definition::from(resolution?), &original_token.parent()?, config, - )?; + ); return Some(RangeInfo::new(range, res)); } @@ -215,7 +215,7 @@ fn hover_simple( }) .flatten() .unique_by(|&(def, _)| def) - .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) + .map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { acc.actions.extend(actions); acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup)); @@ -373,9 +373,9 @@ pub(crate) fn hover_for_definition( def: Definition, scope_node: &SyntaxNode, config: &HoverConfig, -) -> Option { +) -> HoverResult { let famous_defs = match &def { - Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())), + Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())), _ => None, }; @@ -396,20 +396,19 @@ pub(crate) fn hover_for_definition( }; let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); - render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config).map(|markup| { - HoverResult { - markup: render::process_markup(sema.db, def, &markup, config), - actions: [ - show_implementations_action(sema.db, def), - show_fn_references_action(sema.db, def), - runnable_action(sema, def, file_id), - goto_type_action_for_def(sema.db, def, ¬able_traits), - ] - .into_iter() - .flatten() - .collect(), - } - }) + let markup = render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config); + HoverResult { + markup: render::process_markup(sema.db, def, &markup, config), + actions: [ + show_implementations_action(sema.db, def), + show_fn_references_action(sema.db, def), + runnable_action(sema, def, file_id), + goto_type_action_for_def(sema.db, def, ¬able_traits), + ] + .into_iter() + .flatten() + .collect(), + } } fn notable_traits( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index eff055c95992..563e78253a8a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -3,8 +3,8 @@ use std::{mem, ops::Not}; use either::Either; use hir::{ - Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name, - Semantics, Trait, Type, TypeInfo, + Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, + LayoutError, Name, Semantics, Trait, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -264,7 +264,7 @@ pub(super) fn keyword( let markup = process_markup( sema.db, Definition::Module(doc_owner), - &markup(Some(docs.into()), description, None)?, + &markup(Some(docs.into()), description, None), config, ); Some(HoverResult { markup, actions }) @@ -369,12 +369,20 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option match def { Definition::Field(f) => Some(f.parent_def(db).name(db)), Definition::Local(l) => l.parent(db).name(db), - Definition::Function(f) => match f.as_assoc_item(db)?.container(db) { - hir::AssocItemContainer::Trait(t) => Some(t.name(db)), - hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), - }, Definition::Variant(e) => Some(e.parent_enum(db).name(db)), - _ => None, + + d => { + if let Some(assoc_item) = d.as_assoc_item(db) { + match assoc_item.container(db) { + hir::AssocItemContainer::Trait(t) => Some(t.name(db)), + hir::AssocItemContainer::Impl(i) => { + i.self_ty(db).as_adt().map(|adt| adt.name(db)) + } + } + } else { + return d.as_extern_assoc_item(db).map(|_| "".to_owned()); + } + } } .map(|name| name.display(db).to_string()) } @@ -396,11 +404,11 @@ pub(super) fn definition( famous_defs: Option<&FamousDefs<'_, '_>>, notable_traits: &[(Trait, Vec<(Option, Name)>)], config: &HoverConfig, -) -> Option { +) -> Markup { let mod_path = definition_mod_path(db, &def); - let label = def.label(db)?; + let label = def.label(db); let docs = def.docs(db, famous_defs); - let value = match def { + let value = (|| match def { Definition::Variant(it) => { if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { @@ -436,7 +444,7 @@ pub(super) fn definition( Some(body.to_string()) } _ => None, - }; + })(); let layout_info = match def { Definition::Field(it) => render_memory_layout( @@ -683,7 +691,7 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) } -fn markup(docs: Option, desc: String, mod_path: Option) -> Option { +fn markup(docs: Option, desc: String, mod_path: Option) -> Markup { let mut buf = String::new(); if let Some(mod_path) = mod_path { @@ -696,7 +704,7 @@ fn markup(docs: Option, desc: String, mod_path: Option) -> Optio if let Some(doc) = docs { format_to!(buf, "\n___\n\n{}", doc); } - Some(buf.into()) + buf.into() } fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 69ddc1e45efb..ead4f91595f0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -1202,7 +1202,7 @@ fn main() { *C* ```rust - test + test::X ``` ```rust @@ -1279,11 +1279,11 @@ impl Thing { ); check( r#" - enum Thing { A } - impl Thing { - pub fn thing(a: Self$0) {} - } - "#, +enum Thing { A } +impl Thing { + pub fn thing(a: Self$0) {} +} +"#, expect![[r#" *Self* @@ -1298,6 +1298,42 @@ impl Thing { ``` "#]], ); + check( + r#" +impl usize { + pub fn thing(a: Self$0) {} +} +"#, + expect![[r#" + *Self* + + ```rust + test + ``` + + ```rust + usize + ``` + "#]], + ); + check( + r#" +impl fn() -> usize { + pub fn thing(a: Self$0) {} +} +"#, + expect![[r#" + *Self* + + ```rust + test + ``` + + ```rust + fn() -> usize + ``` + "#]], + ); } #[test] @@ -2241,7 +2277,7 @@ fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } } *foo* ```rust - test + test:: ``` ```rust @@ -4230,7 +4266,7 @@ fn main() { *B* ```rust - test + test::T ``` ```rust @@ -4259,7 +4295,7 @@ fn main() { *B* ```rust - test + test::T ``` ```rust @@ -4291,7 +4327,7 @@ fn main() { *B* ```rust - test + test::T ``` ```rust @@ -4883,7 +4919,7 @@ fn test() { *FOO* ```rust - test + test::S ``` ```rust @@ -5248,7 +5284,7 @@ impl T1 for Foo { *Bar* ```rust - test::t2 + test::t2::T2 ``` ```rust @@ -5270,7 +5306,7 @@ trait A { *Assoc* ```rust - test + test::A ``` ```rust @@ -5291,7 +5327,7 @@ trait A { *Assoc* ```rust - test + test::A ``` ```rust @@ -5310,7 +5346,7 @@ trait A where *Assoc* ```rust - test + test::A ``` ```rust @@ -6596,7 +6632,7 @@ fn test() { *A* ```rust - test + test::S ``` ```rust @@ -6625,7 +6661,7 @@ fn test() { *A* ```rust - test + test::S ``` ```rust @@ -6655,7 +6691,7 @@ mod m { *A* ```rust - test + test::S ``` ```rust @@ -7201,6 +7237,65 @@ impl Iterator for S { ); } +#[test] +fn extern_items() { + check( + r#" +extern "C" { + static STATIC$0: (); +} +"#, + expect![[r#" + *STATIC* + + ```rust + test:: + ``` + + ```rust + static STATIC: () + ``` + "#]], + ); + check( + r#" +extern "C" { + fn fun$0(); +} +"#, + expect![[r#" + *fun* + + ```rust + test:: + ``` + + ```rust + unsafe fn fun() + ``` + "#]], + ); + check( + r#" +extern "C" { + type Ty$0; +} +"#, + expect![[r#" + *Ty* + + ```rust + test:: + ``` + + ```rust + // size = 0, align = 1 + type Ty + ``` + "#]], + ); +} + #[test] fn notable_ranged() { check_hover_range( diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs index fef0ec35ba09..815a4ba7fd70 100644 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs @@ -303,7 +303,6 @@ fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { #[cfg(test)] mod tests { - use syntax::SourceFile; use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; use super::*; diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index f2eedfa43169..f78153df38bd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -9,6 +9,7 @@ use ide_db::{ base_db::{FileId, FileRange}, defs::{Definition, NameClass, NameRefClass}, rename::{bail, format_err, source_edit_from_references, IdentifierKind}, + source_change::SourceChangeBuilder, RootDatabase, }; use itertools::Itertools; @@ -90,24 +91,60 @@ pub(crate) fn rename( let syntax = source_file.syntax(); let defs = find_definitions(&sema, syntax, position)?; + let alias_fallback = alias_fallback(syntax, position, new_name); - let ops: RenameResult> = defs - .map(|(.., def)| { - if let Definition::Local(local) = def { - if let Some(self_param) = local.as_self_param(sema.db) { - cov_mark::hit!(rename_self_to_param); - return rename_self_to_param(&sema, local, self_param, new_name); + let ops: RenameResult> = match alias_fallback { + Some(_) => defs + // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can + // properly find "direct" usages/references. + .map(|(.., def)| { + match IdentifierKind::classify(new_name)? { + IdentifierKind::Ident => (), + IdentifierKind::Lifetime => { + bail!("Cannot alias reference to a lifetime identifier") + } + IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), + }; + + let mut usages = def.usages(&sema).all(); + + // FIXME: hack - removes the usage that triggered this rename operation. + match usages.references.get_mut(&position.file_id).and_then(|refs| { + refs.iter() + .position(|ref_| ref_.range.contains_inclusive(position.offset)) + .map(|idx| refs.remove(idx)) + }) { + Some(_) => (), + None => never!(), + }; + + let mut source_change = SourceChange::default(); + source_change.extend(usages.iter().map(|(&file_id, refs)| { + (file_id, source_edit_from_references(refs, def, new_name)) + })); + + Ok(source_change) + }) + .collect(), + None => defs + .map(|(.., def)| { + if let Definition::Local(local) = def { + if let Some(self_param) = local.as_self_param(sema.db) { + cov_mark::hit!(rename_self_to_param); + return rename_self_to_param(&sema, local, self_param, new_name); + } + if new_name == "self" { + cov_mark::hit!(rename_to_self); + return rename_to_self(&sema, local); + } } - if new_name == "self" { - cov_mark::hit!(rename_to_self); - return rename_to_self(&sema, local); - } - } - def.rename(&sema, new_name) - }) - .collect(); + def.rename(&sema, new_name) + }) + .collect(), + }; ops?.into_iter() + .chain(alias_fallback) .reduce(|acc, elem| acc.merge(elem)) .ok_or_else(|| format_err!("No references found at position")) } @@ -130,6 +167,38 @@ pub(crate) fn will_rename_file( Some(change) } +// FIXME: Should support `extern crate`. +fn alias_fallback( + syntax: &SyntaxNode, + FilePosition { file_id, offset }: FilePosition, + new_name: &str, +) -> Option { + let use_tree = syntax + .token_at_offset(offset) + .flat_map(|syntax| syntax.parent_ancestors()) + .find_map(ast::UseTree::cast)?; + + let last_path_segment = use_tree.path()?.segments().last()?.name_ref()?; + if !last_path_segment.syntax().text_range().contains_inclusive(offset) { + return None; + }; + + let mut builder = SourceChangeBuilder::new(file_id); + + match use_tree.rename() { + Some(rename) => { + let offset = rename.syntax().text_range(); + builder.replace(offset, format!("as {new_name}")); + } + None => { + let offset = use_tree.syntax().text_range().end(); + builder.insert(offset, format!(" as {new_name}")); + } + } + + Some(builder.finish()) +} + fn find_definitions( sema: &Semantics<'_, RootDatabase>, syntax: &SyntaxNode, @@ -2626,7 +2695,8 @@ use qux as frob; //- /lib.rs crate:lib new_source_root:library pub struct S; //- /main.rs crate:main deps:lib new_source_root:local -use lib::S$0; +use lib::S; +fn main() { let _: S$0; } "#, "error: Cannot rename a non-local definition", ); @@ -2686,4 +2756,27 @@ fn test() { "#, ); } + + #[test] + fn rename_path_inside_use_tree() { + check( + "Baz", + r#" +mod foo { pub struct Foo; } +mod bar { use super::Foo; } + +use foo::Foo$0; + +fn main() { let _: Foo; } +"#, + r#" +mod foo { pub struct Foo; } +mod bar { use super::Baz; } + +use foo::Foo as Baz; + +fn main() { let _: Baz; } +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 5feaf21aa979..2929a7522e59 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -186,7 +186,7 @@ impl StaticIndex<'_> { } else { let it = self.tokens.insert(TokenStaticData { documentation: documentation_for_definition(&sema, def, &node), - hover: hover_for_definition(&sema, file_id, def, &node, &hover_config), + hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)), definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| { FileRange { file_id: it.file_id, range: it.focus_or_full_range() } }), @@ -196,7 +196,7 @@ impl StaticIndex<'_> { enclosing_moniker: current_crate .zip(def.enclosing_definition(self.db)) .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)), - signature: def.label(self.db), + signature: Some(def.label(self.db)), kind: def_to_kind(self.db, def), }); self.def_map.insert(def, it); diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 8c5592da63ec..830d19a709c4 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -309,6 +309,10 @@ fn load_crate_graph( vfs: &mut vfs::Vfs, receiver: &Receiver, ) -> AnalysisHost { + let (ProjectWorkspace::Cargo { toolchain, target_layout, .. } + | ProjectWorkspace::Json { toolchain, target_layout, .. } + | ProjectWorkspace::DetachedFiles { toolchain, target_layout, .. }) = ws; + let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); let mut host = AnalysisHost::new(lru_cap); let mut analysis_change = Change::new(); @@ -344,14 +348,9 @@ fn load_crate_graph( let num_crates = crate_graph.len(); analysis_change.set_crate_graph(crate_graph); analysis_change.set_proc_macros(proc_macros); - if let ProjectWorkspace::Cargo { toolchain, target_layout, .. } - | ProjectWorkspace::Json { toolchain, target_layout, .. } = ws - { - analysis_change.set_target_data_layouts( - iter::repeat(target_layout.clone()).take(num_crates).collect(), - ); - analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect()); - } + analysis_change + .set_target_data_layouts(iter::repeat(target_layout.clone()).take(num_crates).collect()); + analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect()); host.apply_change(analysis_change); host diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs index 12eafcea442d..72f95643c8b5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs @@ -45,7 +45,7 @@ impl ProcMacroProcessSrv { }) }; let mut srv = create_srv(true)?; - tracing::info!("sending version check"); + tracing::info!("sending proc-macro server version check"); match srv.version_check() { Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new( io::ErrorKind::Other, @@ -55,14 +55,15 @@ impl ProcMacroProcessSrv { ), )), Ok(v) => { - tracing::info!("got version {v}"); + tracing::info!("Proc-macro server version: {v}"); srv = create_srv(false)?; srv.version = v; - if srv.version > RUST_ANALYZER_SPAN_SUPPORT { + if srv.version >= RUST_ANALYZER_SPAN_SUPPORT { if let Ok(mode) = srv.enable_rust_analyzer_spans() { srv.mode = mode; } } + tracing::info!("Proc-macro server span mode: {:?}", srv.mode); Ok(srv) } Err(e) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs index 3fe968c81ca1..686d5b0438aa 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs @@ -64,7 +64,7 @@ impl ProcMacros { &bridge::server::SameThread, S::make_server(call_site, def_site, mixed_site), parsed_body, - false, + cfg!(debug_assertions), ); return res .map(|it| it.into_subtree(call_site)) @@ -75,7 +75,7 @@ impl ProcMacros { &bridge::server::SameThread, S::make_server(call_site, def_site, mixed_site), parsed_body, - false, + cfg!(debug_assertions), ); return res .map(|it| it.into_subtree(call_site)) @@ -87,7 +87,7 @@ impl ProcMacros { S::make_server(call_site, def_site, mixed_site), parsed_attributes, parsed_body, - false, + cfg!(debug_assertions), ); return res .map(|it| it.into_subtree(call_site)) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs index ff8fd295d884..5a814e23e7af 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs @@ -93,7 +93,14 @@ impl LiteralFormatter { let hashes = get_hashes_str(n); f(&["br", hashes, "\"", symbol, "\"", hashes, suffix]) } - _ => f(&[symbol, suffix]), + bridge::LitKind::CStr => f(&["c\"", symbol, "\"", suffix]), + bridge::LitKind::CStrRaw(n) => { + let hashes = get_hashes_str(n); + f(&["cr", hashes, "\"", symbol, "\"", hashes, suffix]) + } + bridge::LitKind::Integer | bridge::LitKind::Float | bridge::LitKind::ErrWithGuar => { + f(&[symbol, suffix]) + } }) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs index c6a0a6665553..15d260d5182b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs @@ -10,16 +10,16 @@ use std::{ ops::{Bound, Range}, }; -use ::tt::{TextRange, TextSize}; use proc_macro::bridge::{self, server}; use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use tt::{TextRange, TextSize}; use crate::server::{ delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; mod tt { - pub use ::tt::*; + pub use tt::*; pub type Subtree = ::tt::Subtree; pub type TokenTree = ::tt::TokenTree; @@ -97,22 +97,33 @@ impl server::FreeFunctions for RaSpanServer { } let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) }; - let kind = match kind { - LiteralKind::Int { .. } => LitKind::Integer, - LiteralKind::Float { .. } => LitKind::Float, - LiteralKind::Char { .. } => LitKind::Char, - LiteralKind::Byte { .. } => LitKind::Byte, - LiteralKind::Str { .. } => LitKind::Str, - LiteralKind::ByteStr { .. } => LitKind::ByteStr, - LiteralKind::CStr { .. } => LitKind::CStr, - LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()), - LiteralKind::RawByteStr { n_hashes } => { - LitKind::ByteStrRaw(n_hashes.unwrap_or_default()) - } - LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()), + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), }; let (lit, suffix) = s.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; let suffix = match suffix { "" | "_" => None, suffix => Some(Symbol::intern(self.interner, suffix)), @@ -248,12 +259,8 @@ impl server::TokenStream for RaSpanServer { } tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { - // FIXME: handle literal kinds - kind: bridge::LitKind::Integer, // dummy - symbol: Symbol::intern(self.interner, &lit.text), - // FIXME: handle suffixes - suffix: None, span: lit.span, + ..server::FreeFunctions::literal_from_str(self, &lit.text).unwrap() }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs index 7e9d8057ac9a..f40c850b2539 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs @@ -14,7 +14,7 @@ use crate::server::{ mod tt { pub use proc_macro_api::msg::TokenId; - pub use ::tt::*; + pub use tt::*; pub type Subtree = ::tt::Subtree; pub type TokenTree = ::tt::TokenTree; @@ -89,22 +89,34 @@ impl server::FreeFunctions for TokenIdServer { } let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) }; - let kind = match kind { - LiteralKind::Int { .. } => LitKind::Integer, - LiteralKind::Float { .. } => LitKind::Float, - LiteralKind::Char { .. } => LitKind::Char, - LiteralKind::Byte { .. } => LitKind::Byte, - LiteralKind::Str { .. } => LitKind::Str, - LiteralKind::ByteStr { .. } => LitKind::ByteStr, - LiteralKind::CStr { .. } => LitKind::CStr, - LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()), - LiteralKind::RawByteStr { n_hashes } => { - LitKind::ByteStrRaw(n_hashes.unwrap_or_default()) - } - LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()), + + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), }; let (lit, suffix) = s.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; let suffix = match suffix { "" | "_" => None, suffix => Some(Symbol::intern(self.interner, suffix)), @@ -233,12 +245,9 @@ impl server::TokenStream for TokenIdServer { } tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { - // FIXME: handle literal kinds - kind: bridge::LitKind::Integer, // dummy - symbol: Symbol::intern(self.interner, &lit.text), - // FIXME: handle suffixes - suffix: None, span: lit.span, + ..server::FreeFunctions::literal_from_str(self, &lit.text) + .unwrap_or_else(|_| panic!("`{}`", lit.text)) }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs index 5edaa720fc7e..408db60e872b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs @@ -115,8 +115,6 @@ pub(super) mod token_stream { } } - type LexError = String; - /// Attempts to break the string into tokens and parse those tokens into a token stream. /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters /// or characters not existing in the language. @@ -124,13 +122,10 @@ pub(super) mod token_stream { /// /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to /// change these errors into `LexError`s later. - #[rustfmt::skip] - impl /*FromStr for*/ TokenStream { - // type Err = LexError; - - pub(crate) fn from_str(src: &str, call_site: S) -> Result, LexError> { + impl TokenStream { + pub(crate) fn from_str(src: &str, call_site: S) -> Result, String> { let subtree = - mbe::parse_to_token_tree_static_span(call_site, src).ok_or("Failed to parse from mbe")?; + mbe::parse_to_token_tree_static_span(call_site, src).ok_or("lexing error")?; Ok(TokenStream::with_subtree(subtree)) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index e5bfe5ee92cd..54a20357d262 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -169,7 +169,7 @@ fn test_fn_like_mk_idents() { fn test_fn_like_macro_clone_literals() { assert_expand( "fn_like_clone_tokens", - r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##"###, + r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##, 'a', b'b', c"null""###, expect![[r###" SUBTREE $$ 1 1 LITERAL 1u16 1 @@ -181,11 +181,17 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL 3.14f32 1 PUNCH , [alone] 1 - LITERAL ""hello bridge"" 1 + LITERAL "hello bridge" 1 PUNCH , [alone] 1 - LITERAL ""suffixed""suffix 1 + LITERAL "suffixed"suffix 1 PUNCH , [alone] 1 - LITERAL r##"r##"raw"##"## 1"###]], + LITERAL r##"raw"## 1 + PUNCH , [alone] 1 + LITERAL 'a' 1 + PUNCH , [alone] 1 + LITERAL b'b' 1 + PUNCH , [alone] 1 + LITERAL c"null" 1"###]], expect![[r###" SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } LITERAL 1u16 SpanData { range: 0..4, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } @@ -197,11 +203,17 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] SpanData { range: 18..19, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } LITERAL 3.14f32 SpanData { range: 20..27, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } PUNCH , [alone] SpanData { range: 27..28, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } - LITERAL ""hello bridge"" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + LITERAL "hello bridge" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } PUNCH , [alone] SpanData { range: 43..44, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } - LITERAL ""suffixed""suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + LITERAL "suffixed"suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } PUNCH , [alone] SpanData { range: 61..62, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } - LITERAL r##"r##"raw"##"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]], + LITERAL r##"raw"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + PUNCH , [alone] SpanData { range: 73..74, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + LITERAL 'a' SpanData { range: 75..78, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + PUNCH , [alone] SpanData { range: 78..79, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + LITERAL b'b' SpanData { range: 80..84, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + PUNCH , [alone] SpanData { range: 84..85, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + LITERAL c"null" SpanData { range: 86..93, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]], ); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index ab72f1fba09d..621b6ca3efa4 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -138,7 +138,7 @@ impl WorkspaceBuildScripts { toolchain: &Option, sysroot: Option<&Sysroot>, ) -> io::Result { - const RUST_1_62: Version = Version::new(1, 62, 0); + const RUST_1_75: Version = Version::new(1, 75, 0); let current_dir = match &config.invocation_location { InvocationLocation::Root(root) if config.run_build_script_command.is_some() => { @@ -162,7 +162,7 @@ impl WorkspaceBuildScripts { progress, ) { Ok(WorkspaceBuildScripts { error: Some(error), .. }) - if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => + if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) => { // building build scripts failed, attempt to build with --keep-going so // that we potentially get more build data @@ -172,7 +172,8 @@ impl WorkspaceBuildScripts { &workspace.workspace_root().to_path_buf(), sysroot, )?; - cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); + + cmd.args(["--keep-going"]); let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; res.error = Some(error); Ok(res) diff --git a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs index af635dda5782..98917351c5e8 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs @@ -32,7 +32,16 @@ pub fn get( Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot); cmd.envs(extra_env); cmd.current_dir(cargo_toml.parent()) - .args(["rustc", "--", "-Z", "unstable-options", "--print", "target-spec-json"]) + .args([ + "rustc", + "-Z", + "unstable-options", + "--print", + "target-spec-json", + "--", + "-Z", + "unstable-options", + ]) .env("RUSTC_BOOTSTRAP", "1"); if let Some(target) = target { cmd.args(["--target", target]); diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index b7ae76be8cec..bcb5dcadb5b9 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -100,6 +100,8 @@ pub enum ProjectWorkspace { /// Holds cfg flags for the current target. We get those by running /// `rustc --print cfg`. rustc_cfg: Vec, + toolchain: Option, + target_layout: TargetLayoutLoadResult, }, } @@ -145,16 +147,24 @@ impl fmt::Debug for ProjectWorkspace { debug_struct.field("n_sysroot_crates", &sysroot.num_packages()); } debug_struct - .field("toolchain", &toolchain) .field("n_rustc_cfg", &rustc_cfg.len()) + .field("toolchain", &toolchain) .field("data_layout", &data_layout); debug_struct.finish() } - ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f + ProjectWorkspace::DetachedFiles { + files, + sysroot, + rustc_cfg, + toolchain, + target_layout, + } => f .debug_struct("DetachedFiles") .field("n_files", &files.len()) .field("sysroot", &sysroot.is_ok()) .field("n_rustc_cfg", &rustc_cfg.len()) + .field("toolchain", &toolchain) + .field("data_layout", &target_layout) .finish(), } } @@ -403,32 +413,54 @@ impl ProjectWorkspace { detached_files: Vec, config: &CargoConfig, ) -> anyhow::Result { + let dir = detached_files + .first() + .and_then(|it| it.parent()) + .ok_or_else(|| format_err!("No detached files to load"))?; let sysroot = match &config.sysroot { Some(RustLibSource::Path(path)) => { Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata) .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}"))) } - Some(RustLibSource::Discover) => { - let dir = &detached_files - .first() - .and_then(|it| it.parent()) - .ok_or_else(|| format_err!("No detached files to load"))?; - Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata).map_err( - |e| { - Some(format!( - "Failed to find sysroot for {dir}. Is rust-src installed? {e}" - )) - }, - ) - } + Some(RustLibSource::Discover) => Sysroot::discover( + dir, + &config.extra_env, + config.sysroot_query_metadata, + ) + .map_err(|e| { + Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}")) + }), None => Err(None), }; - let rustc_cfg = rustc_cfg::get( + + let sysroot_ref = sysroot.as_ref().ok(); + let toolchain = match get_toolchain_version( + dir, + sysroot_ref, + toolchain::Tool::Rustc, + &config.extra_env, + "rustc ", + ) { + Ok(it) => it, + Err(e) => { + tracing::error!("{e}"); + None + } + }; + + let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref)); + let data_layout = target_data_layout::get( + RustcDataLayoutConfig::Rustc(sysroot_ref), None, - &FxHashMap::default(), - RustcCfgConfig::Rustc(sysroot.as_ref().ok()), + &config.extra_env, ); - Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) + Ok(ProjectWorkspace::DetachedFiles { + files: detached_files, + sysroot, + rustc_cfg, + toolchain, + target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + }) } /// Runs the build scripts for this [`ProjectWorkspace`]. @@ -724,7 +756,13 @@ impl ProjectWorkspace { cfg_overrides, build_scripts, ), - ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { + ProjectWorkspace::DetachedFiles { + files, + sysroot, + rustc_cfg, + toolchain: _, + target_layout: _, + } => { detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot.as_ref().ok()) } }; @@ -786,9 +824,21 @@ impl ProjectWorkspace { && toolchain == o_toolchain } ( - Self::DetachedFiles { files, sysroot, rustc_cfg }, - Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg }, - ) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg, + Self::DetachedFiles { files, sysroot, rustc_cfg, toolchain, target_layout }, + Self::DetachedFiles { + files: o_files, + sysroot: o_sysroot, + rustc_cfg: o_rustc_cfg, + toolchain: o_toolchain, + target_layout: o_target_layout, + }, + ) => { + files == o_files + && sysroot == o_sysroot + && rustc_cfg == o_rustc_cfg + && toolchain == o_toolchain + && target_layout == o_target_layout + } _ => false, } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs index f9f26178259c..815a98980b93 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs @@ -208,7 +208,6 @@ fn required_features(cfg_expr: &CfgExpr, features: &mut Vec) { mod tests { use super::*; - use cfg::CfgExpr; use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY}; use syntax::{ ast::{self, AstNode}, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 493e614dce68..3f68c5d053b7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -30,7 +30,7 @@ xflags::xflags! { default cmd lsp-server { /// Print version. - optional --version + optional -V, --version /// Dump a LSP config JSON schema. optional --print-config-schema diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 64ea246a4587..7062b60cbfc1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -1,11 +1,16 @@ //! Run all tests in a project, similar to `cargo test`, but using the mir interpreter. +use std::convert::identity; +use std::thread::Builder; +use std::time::{Duration, Instant}; use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf}; use hir::{Change, Crate}; use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; +use itertools::Either; use profile::StopWatch; -use project_model::{CargoConfig, ProjectWorkspace, RustLibSource, Sysroot}; +use project_model::target_data_layout::RustcDataLayoutConfig; +use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot}; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use rustc_hash::FxHashMap; @@ -60,15 +65,22 @@ impl Tester { std::fs::write(&tmp_file, "")?; let cargo_config = CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() }; + + let sysroot = + Ok(Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env, false) + .unwrap()); + let data_layout = target_data_layout::get( + RustcDataLayoutConfig::Rustc(sysroot.as_ref().ok()), + None, + &cargo_config.extra_env, + ); + let workspace = ProjectWorkspace::DetachedFiles { files: vec![tmp_file.clone()], - sysroot: Ok(Sysroot::discover( - tmp_file.parent().unwrap(), - &cargo_config.extra_env, - false, - ) - .unwrap()), + sysroot, rustc_cfg: vec![], + toolchain: None, + target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: false, @@ -92,6 +104,7 @@ impl Tester { } fn test(&mut self, p: PathBuf) { + println!("{}", p.display()); if p.parent().unwrap().file_name().unwrap() == "auxiliary" { // These are not tests return; @@ -124,15 +137,44 @@ impl Tester { self.host.apply_change(change); let diagnostic_config = DiagnosticsConfig::test_sample(); + let res = std::thread::scope(|s| { + let worker = Builder::new() + .stack_size(40 * 1024 * 1024) + .spawn_scoped(s, { + let diagnostic_config = &diagnostic_config; + let main = std::thread::current(); + let analysis = self.host.analysis(); + let root_file = self.root_file; + move || { + let res = std::panic::catch_unwind(move || { + analysis.diagnostics( + diagnostic_config, + ide::AssistResolveStrategy::None, + root_file, + ) + }); + main.unpark(); + res + } + }) + .unwrap(); + + let timeout = Duration::from_secs(5); + let now = Instant::now(); + while now.elapsed() <= timeout && !worker.is_finished() { + std::thread::park_timeout(timeout - now.elapsed()); + } + + if !worker.is_finished() { + // attempt to cancel the worker, won't work for chalk hangs unfortunately + self.host.request_cancellation(); + } + worker.join().and_then(identity) + }); let mut actual = FxHashMap::default(); - let panicked = match std::panic::catch_unwind(|| { - self.host - .analysis() - .diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file) - .unwrap() - }) { - Err(e) => Some(e), - Ok(diags) => { + let panicked = match res { + Err(e) => Some(Either::Left(e)), + Ok(Ok(diags)) => { for diag in diags { if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) { continue; @@ -144,6 +186,7 @@ impl Tester { } None } + Ok(Err(e)) => Some(Either::Right(e)), }; // Ignore tests with diagnostics that we don't emit. ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k)); @@ -151,14 +194,19 @@ impl Tester { println!("{p:?} IGNORE"); self.ignore_count += 1; } else if let Some(panic) = panicked { - if let Some(msg) = panic - .downcast_ref::() - .map(String::as_str) - .or_else(|| panic.downcast_ref::<&str>().copied()) - { - println!("{msg:?} ") + match panic { + Either::Left(panic) => { + if let Some(msg) = panic + .downcast_ref::() + .map(String::as_str) + .or_else(|| panic.downcast_ref::<&str>().copied()) + { + println!("{msg:?} ") + } + println!("{p:?} PANIC"); + } + Either::Right(_) => println!("{p:?} CANCELLED"), } - println!("PANIC"); self.fail_count += 1; } else if actual == expected { println!("{p:?} PASS"); @@ -228,6 +276,7 @@ impl flags::RustcTests { pub fn run(self) -> Result<()> { let mut tester = Tester::new()?; let walk_dir = WalkDir::new(self.rustc_repo.join("tests/ui")); + eprintln!("Running tests for tests/ui"); for i in walk_dir { let i = i?; let p = i.into_path(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 2d56830c87f3..27869a5a7e63 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -324,7 +324,7 @@ fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol { #[cfg(test)] mod test { use super::*; - use ide::{AnalysisHost, FilePosition, StaticIndex, TextSize}; + use ide::{AnalysisHost, FilePosition, TextSize}; use scip::symbol::format_symbol; use test_fixture::ChangeFixture; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 293807a383ba..b2d507491b17 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -301,19 +301,12 @@ impl GlobalState { if let Some(path) = vfs_path.as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.kind()) { - workspace_structure_change = Some(( - path.clone(), - false, - AsRef::::as_ref(&path).ends_with("build.rs"), - )); + workspace_structure_change = Some((path.clone(), false)); } if file.is_created_or_deleted() { has_structure_changes = true; - workspace_structure_change = Some(( - path, - self.crate_graph_file_dependencies.contains(vfs_path), - false, - )); + workspace_structure_change = + Some((path, self.crate_graph_file_dependencies.contains(vfs_path))); } else if path.extension() == Some("rs".as_ref()) { modified_rust_files.push(file.file_id); } @@ -365,16 +358,11 @@ impl GlobalState { // FIXME: ideally we should only trigger a workspace fetch for non-library changes // but something's going wrong with the source root business when we add a new local // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 - if let Some((path, force_crate_graph_reload, build_scripts_touched)) = - workspace_structure_change - { + if let Some((path, force_crate_graph_reload)) = workspace_structure_change { self.fetch_workspaces_queue.request_op( format!("workspace vfs file change: {path}"), force_crate_graph_reload, ); - if build_scripts_touched { - self.fetch_build_data_queue.request_op(format!("build.rs changed: {path}"), ()); - } } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index eb9d4bf0f02d..04a043954299 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -16,6 +16,7 @@ use ide::{ ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; +use itertools::Itertools; use lsp_server::ErrorCode; use lsp_types::{ CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, @@ -1055,9 +1056,8 @@ pub(crate) fn handle_references( let exclude_imports = snap.config.find_all_refs_exclude_imports(); let exclude_tests = snap.config.find_all_refs_exclude_tests(); - let refs = match snap.analysis.find_all_refs(position, None)? { - None => return Ok(None), - Some(refs) => refs, + let Some(refs) = snap.analysis.find_all_refs(position, None)? else { + return Ok(None); }; let include_declaration = params.context.include_declaration; @@ -1084,6 +1084,7 @@ pub(crate) fn handle_references( }) .chain(decl) }) + .unique() .filter_map(|frange| to_proto::location(&snap, frange).ok()) .collect(); @@ -1802,10 +1803,10 @@ fn show_ref_command_link( .into_iter() .flat_map(|res| res.references) .flat_map(|(file_id, ranges)| { - ranges.into_iter().filter_map(move |(range, _)| { - to_proto::location(snap, FileRange { file_id, range }).ok() - }) + ranges.into_iter().map(move |(range, _)| FileRange { file_id, range }) }) + .unique() + .filter_map(|range| to_proto::location(snap, range).ok()) .collect(); let title = to_proto::reference_title(locations.len()); let command = to_proto::command::show_references(title, &uri, position, locations); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 727007bba083..481ebfefd4ee 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -904,15 +904,16 @@ pub(crate) fn goto_definition_response( if snap.config.location_link() { let links = targets .into_iter() + .unique_by(|nav| (nav.file_id, nav.full_range, nav.focus_range)) .map(|nav| location_link(snap, src, nav)) .collect::>>()?; Ok(links.into()) } else { let locations = targets .into_iter() - .map(|nav| { - location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - }) + .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) + .unique() + .map(|range| location(snap, range)) .collect::>>()?; Ok(locations.into()) } @@ -1001,10 +1002,8 @@ fn merge_text_and_snippet_edits( let mut new_text = current_indel.insert; // find which snippet bits need to be escaped - let escape_places = new_text - .rmatch_indices(['\\', '$', '{', '}']) - .map(|(insert, _)| insert) - .collect_vec(); + let escape_places = + new_text.rmatch_indices(['\\', '$', '}']).map(|(insert, _)| insert).collect_vec(); let mut escape_places = escape_places.into_iter().peekable(); let mut escape_prior_bits = |new_text: &mut String, up_to: usize| { for before in escape_places.peeking_take_while(|insert| *insert >= up_to) { @@ -2175,7 +2174,7 @@ fn bar(_: usize) {} character: 0, }, }, - new_text: "\\$${1:ab\\{\\}\\$c\\\\d}ef", + new_text: "\\$${1:ab{\\}\\$c\\\\d}ef", insert_text_format: Some( Snippet, ), @@ -2271,7 +2270,7 @@ struct ProcMacro { character: 5, }, }, - new_text: "$0disabled = false;\n ProcMacro \\{\n disabled,\n \\}", + new_text: "$0disabled = false;\n ProcMacro {\n disabled,\n \\}", insert_text_format: Some( Snippet, ), @@ -2335,7 +2334,7 @@ struct P { character: 5, }, }, - new_text: "$0disabled = false;\n ProcMacro \\{\n disabled,\n \\}", + new_text: "$0disabled = false;\n ProcMacro {\n disabled,\n \\}", insert_text_format: Some( Snippet, ), @@ -2400,7 +2399,7 @@ struct ProcMacro { character: 5, }, }, - new_text: "${0:disabled} = false;\n ProcMacro \\{\n disabled,\n \\}", + new_text: "${0:disabled} = false;\n ProcMacro {\n disabled,\n \\}", insert_text_format: Some( Snippet, ), @@ -2465,7 +2464,7 @@ struct P { character: 5, }, }, - new_text: "${0:disabled} = false;\n ProcMacro \\{\n disabled,\n \\}", + new_text: "${0:disabled} = false;\n ProcMacro {\n disabled,\n \\}", insert_text_format: Some( Snippet, ), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs index 10335cb14533..800c0eee53a0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs @@ -134,6 +134,7 @@ impl GlobalState { let token = lsp_types::ProgressToken::String( cancel_token.unwrap_or_else(|| format!("rustAnalyzer/{title}")), ); + tracing::debug!(?token, ?state, "report_progress {message:?}"); let work_done_progress = match state { Progress::Begin => { self.send_request::( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 5895459d1fcf..f6bc032c0198 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -411,10 +411,7 @@ impl GlobalState { if *force_reload_crate_graph { self.recreate_crate_graph(cause); } - if self.build_deps_changed && self.config.run_build_scripts() { - self.build_deps_changed = false; - self.fetch_build_data_queue.request_op("build_deps_changed".to_owned(), ()); - } + // Current build scripts do not match the version of the active // workspace, so there's nothing for us to update. return; @@ -424,7 +421,7 @@ impl GlobalState { // Here, we completely changed the workspace (Cargo.toml edit), so // we don't care about build-script results, they are stale. - // FIXME: can we abort the build scripts here? + // FIXME: can we abort the build scripts here if they are already running? self.workspaces = Arc::new(workspaces); if self.config.run_build_scripts() { @@ -525,13 +522,14 @@ impl GlobalState { } fn recreate_crate_graph(&mut self, cause: String) { - { + // crate graph construction relies on these paths, record them so when one of them gets + // deleted or created we trigger a reconstruction of the crate graph + let mut crate_graph_file_dependencies = FxHashSet::default(); + + let (crate_graph, proc_macro_paths, layouts, toolchains) = { // Create crate graph from all the workspaces let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; - // crate graph construction relies on these paths, record them so when one of them gets - // deleted or created we trigger a reconstruction of the crate graph - let mut crate_graph_file_dependencies = FxHashSet::default(); let load = |path: &AbsPath| { let _p = tracing::span!(tracing::Level::DEBUG, "switch_workspaces::load").entered(); @@ -548,25 +546,24 @@ impl GlobalState { } }; - let (crate_graph, proc_macro_paths, layouts, toolchains) = - ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load); - - let mut change = Change::new(); - if self.config.expand_proc_macros() { - change.set_proc_macros( - crate_graph - .iter() - .map(|id| (id, Err("Proc-macros have not been built yet".to_owned()))) - .collect(), - ); - self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); - } - change.set_crate_graph(crate_graph); - change.set_target_data_layouts(layouts); - change.set_toolchains(toolchains); - self.analysis_host.apply_change(change); - self.crate_graph_file_dependencies = crate_graph_file_dependencies; + ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load) + }; + let mut change = Change::new(); + if self.config.expand_proc_macros() { + change.set_proc_macros( + crate_graph + .iter() + .map(|id| (id, Err("Proc-macros have not been built yet".to_owned()))) + .collect(), + ); + self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); } + change.set_crate_graph(crate_graph); + change.set_target_data_layouts(layouts); + change.set_toolchains(toolchains); + self.analysis_host.apply_change(change); + self.crate_graph_file_dependencies = crate_graph_file_dependencies; + self.process_changes(); self.reload_flycheck(); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 392a71702070..dfd25abc70f6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -243,7 +243,7 @@ impl Server { to_string_pretty(actual_part).unwrap(), ); } else { - tracing::debug!("sucessfully matched notification"); + tracing::debug!("successfully matched notification"); return; } } else { diff --git a/src/tools/rust-analyzer/crates/salsa/Cargo.toml b/src/tools/rust-analyzer/crates/salsa/Cargo.toml index 4ccbc3de846d..9eec21f6a15f 100644 --- a/src/tools/rust-analyzer/crates/salsa/Cargo.toml +++ b/src/tools/rust-analyzer/crates/salsa/Cargo.toml @@ -21,6 +21,7 @@ rustc-hash = "1.0" smallvec = "1.0.0" oorandom = "11" triomphe = "0.1.11" +itertools.workspace = true salsa-macros = { version = "0.0.0", path = "salsa-macros" } diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs index 0ec75bb043db..223da9b5290f 100644 --- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs +++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs @@ -154,8 +154,8 @@ pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream { self.#db_storage_field.salsa_runtime() } - fn ops_salsa_runtime_mut(&mut self) -> &mut salsa::Runtime { - self.#db_storage_field.salsa_runtime_mut() + fn synthetic_write(&mut self, durability: salsa::Durability) { + self.#db_storage_field.salsa_runtime_mut().synthetic_write(durability) } fn fmt_index( diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs index 5d1678ef1200..a868d920b666 100644 --- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs +++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs @@ -526,7 +526,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream fmt_ops.extend(quote! { #query_index => { salsa::plumbing::QueryStorageOps::fmt_index( - &*self.#fn_name, db, input, fmt, + &*self.#fn_name, db, input.key_index(), fmt, ) } }); @@ -537,7 +537,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream maybe_changed_ops.extend(quote! { #query_index => { salsa::plumbing::QueryStorageOps::maybe_changed_after( - &*self.#fn_name, db, input, revision + &*self.#fn_name, db, input.key_index(), revision ) } }); diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived.rs b/src/tools/rust-analyzer/crates/salsa/src/derived.rs index d63167100581..153df999f534 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/derived.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/derived.rs @@ -102,13 +102,13 @@ where let mut write = self.slot_map.write(); let entry = write.entry(key.clone()); - let key_index = u32::try_from(entry.index()).unwrap(); + let key_index = entry.index() as u32; let database_key_index = DatabaseKeyIndex { group_index: self.group_index, query_index: Q::QUERY_INDEX, key_index, }; - entry.or_insert_with(|| Arc::new(Slot::new(key.clone(), database_key_index))).clone() + entry.or_insert_with(|| Arc::new(Slot::new(database_key_index))).clone() } } @@ -131,34 +131,36 @@ where fn fmt_index( &self, _db: &>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - assert_eq!(index.group_index, self.group_index); - assert_eq!(index.query_index, Q::QUERY_INDEX); let slot_map = self.slot_map.read(); - let key = slot_map.get_index(index.key_index as usize).unwrap().0; + let key = slot_map.get_index(index as usize).unwrap().0; write!(fmt, "{}({:?})", Q::QUERY_NAME, key) } fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + index: u32, revision: Revision, ) -> bool { - assert_eq!(input.group_index, self.group_index); - assert_eq!(input.query_index, Q::QUERY_INDEX); debug_assert!(revision < db.salsa_runtime().current_revision()); - let slot = self.slot_map.read().get_index(input.key_index as usize).unwrap().1.clone(); - slot.maybe_changed_after(db, revision) + let read = self.slot_map.read(); + let Some((key, slot)) = read.get_index(index as usize) else { + return false; + }; + let (key, slot) = (key.clone(), slot.clone()); + // note: this drop is load-bearing. removing it would causes deadlocks. + drop(read); + slot.maybe_changed_after(db, revision, &key) } fn fetch(&self, db: &>::DynDb, key: &Q::Key) -> Q::Value { db.unwind_if_cancelled(); let slot = self.slot(key); - let StampedValue { value, durability, changed_at } = slot.read(db); + let StampedValue { value, durability, changed_at } = slot.read(db, key); if let Some(evicted) = self.lru_list.record_use(&slot) { evicted.evict(); @@ -182,7 +184,7 @@ where C: std::iter::FromIterator>, { let slot_map = self.slot_map.read(); - slot_map.values().filter_map(|slot| slot.as_table_entry()).collect() + slot_map.iter().filter_map(|(key, slot)| slot.as_table_entry(key)).collect() } } diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs index 4fad791a26ae..75204c8ff604 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs @@ -26,8 +26,8 @@ where Q: QueryFunction, MP: MemoizationPolicy, { - key: Q::Key, - database_key_index: DatabaseKeyIndex, + key_index: u32, + group_index: u16, state: RwLock>, policy: PhantomData, lru_index: LruIndex, @@ -110,10 +110,10 @@ where Q: QueryFunction, MP: MemoizationPolicy, { - pub(super) fn new(key: Q::Key, database_key_index: DatabaseKeyIndex) -> Self { + pub(super) fn new(database_key_index: DatabaseKeyIndex) -> Self { Self { - key, - database_key_index, + key_index: database_key_index.key_index, + group_index: database_key_index.group_index, state: RwLock::new(QueryState::NotComputed), lru_index: LruIndex::default(), policy: PhantomData, @@ -121,10 +121,18 @@ where } pub(super) fn database_key_index(&self) -> DatabaseKeyIndex { - self.database_key_index + DatabaseKeyIndex { + group_index: self.group_index, + query_index: Q::QUERY_INDEX, + key_index: self.key_index, + } } - pub(super) fn read(&self, db: &>::DynDb) -> StampedValue { + pub(super) fn read( + &self, + db: &>::DynDb, + key: &Q::Key, + ) -> StampedValue { let runtime = db.salsa_runtime(); // NB: We don't need to worry about people modifying the @@ -147,7 +155,7 @@ where } } - self.read_upgrade(db, revision_now) + self.read_upgrade(db, key, revision_now) } /// Second phase of a read operation: acquires an upgradable-read @@ -157,6 +165,7 @@ where fn read_upgrade( &self, db: &>::DynDb, + key: &Q::Key, revision_now: Revision, ) -> StampedValue { let runtime = db.salsa_runtime(); @@ -186,8 +195,8 @@ where } }; - let panic_guard = PanicGuard::new(self.database_key_index, self, runtime); - let active_query = runtime.push_query(self.database_key_index); + let panic_guard = PanicGuard::new(self, runtime); + let active_query = runtime.push_query(self.database_key_index()); // If we have an old-value, it *may* now be stale, since there // has been a new revision since the last time we checked. So, @@ -200,7 +209,7 @@ where db.salsa_event(Event { runtime_id: runtime.id(), kind: EventKind::DidValidateMemoizedValue { - database_key: self.database_key_index, + database_key: self.database_key_index(), }, }); @@ -210,7 +219,7 @@ where } } - self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo) + self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo, key) } fn execute( @@ -221,22 +230,23 @@ where active_query: ActiveQueryGuard<'_>, panic_guard: PanicGuard<'_, Q, MP>, old_memo: Option>, + key: &Q::Key, ) -> StampedValue { - tracing::info!("{:?}: executing query", self.database_key_index.debug(db)); + tracing::info!("{:?}: executing query", self.database_key_index().debug(db)); db.salsa_event(Event { runtime_id: db.salsa_runtime().id(), - kind: EventKind::WillExecute { database_key: self.database_key_index }, + kind: EventKind::WillExecute { database_key: self.database_key_index() }, }); // Query was not previously executed, or value is potentially // stale, or value is absent. Let's execute! - let value = match Cycle::catch(|| Q::execute(db, self.key.clone())) { + let value = match Cycle::catch(|| Q::execute(db, key.clone())) { Ok(v) => v, Err(cycle) => { tracing::debug!( "{:?}: caught cycle {:?}, have strategy {:?}", - self.database_key_index.debug(db), + self.database_key_index().debug(db), cycle, Q::CYCLE_STRATEGY, ); @@ -248,12 +258,12 @@ where crate::plumbing::CycleRecoveryStrategy::Fallback => { if let Some(c) = active_query.take_cycle() { assert!(c.is(&cycle)); - Q::cycle_fallback(db, &cycle, &self.key) + Q::cycle_fallback(db, &cycle, key) } else { // we are not a participant in this cycle debug_assert!(!cycle .participant_keys() - .any(|k| k == self.database_key_index)); + .any(|k| k == self.database_key_index())); cycle.throw() } } @@ -303,7 +313,7 @@ where }; let memo_value = - if self.should_memoize_value(&self.key) { Some(new_value.value.clone()) } else { None }; + if self.should_memoize_value(key) { Some(new_value.value.clone()) } else { None }; debug!("read_upgrade({:?}): result.revisions = {:#?}", self, revisions,); @@ -395,13 +405,11 @@ where } } - pub(super) fn as_table_entry(&self) -> Option> { + pub(super) fn as_table_entry(&self, key: &Q::Key) -> Option> { match &*self.state.read() { QueryState::NotComputed => None, - QueryState::InProgress { .. } => Some(TableEntry::new(self.key.clone(), None)), - QueryState::Memoized(memo) => { - Some(TableEntry::new(self.key.clone(), memo.value.clone())) - } + QueryState::InProgress { .. } => Some(TableEntry::new(key.clone(), None)), + QueryState::Memoized(memo) => Some(TableEntry::new(key.clone(), memo.value.clone())), } } @@ -436,6 +444,7 @@ where &self, db: &>::DynDb, revision: Revision, + key: &Q::Key, ) -> bool { let runtime = db.salsa_runtime(); let revision_now = runtime.current_revision(); @@ -458,7 +467,7 @@ where MaybeChangedSinceProbeState::ChangedAt(changed_at) => return changed_at > revision, MaybeChangedSinceProbeState::Stale(state) => { drop(state); - return self.maybe_changed_after_upgrade(db, revision); + return self.maybe_changed_after_upgrade(db, revision, key); } } } @@ -495,6 +504,7 @@ where &self, db: &>::DynDb, revision: Revision, + key: &Q::Key, ) -> bool { let runtime = db.salsa_runtime(); let revision_now = runtime.current_revision(); @@ -513,7 +523,9 @@ where // If another thread was active, then the cache line is going to be // either verified or cleared out. Just recurse to figure out which. // Note that we don't need an upgradable read. - MaybeChangedSinceProbeState::Retry => return self.maybe_changed_after(db, revision), + MaybeChangedSinceProbeState::Retry => { + return self.maybe_changed_after(db, revision, key) + } MaybeChangedSinceProbeState::Stale(state) => { type RwLockUpgradableReadGuard<'a, T> = @@ -527,8 +539,8 @@ where } }; - let panic_guard = PanicGuard::new(self.database_key_index, self, runtime); - let active_query = runtime.push_query(self.database_key_index); + let panic_guard = PanicGuard::new(self, runtime); + let active_query = runtime.push_query(self.database_key_index()); if old_memo.verify_revisions(db.ops_database(), revision_now, &active_query) { let maybe_changed = old_memo.revisions.changed_at > revision; @@ -538,8 +550,15 @@ where // We found that this memoized value may have changed // but we have an old value. We can re-run the code and // actually *check* if it has changed. - let StampedValue { changed_at, .. } = - self.execute(db, runtime, revision_now, active_query, panic_guard, Some(old_memo)); + let StampedValue { changed_at, .. } = self.execute( + db, + runtime, + revision_now, + active_query, + panic_guard, + Some(old_memo), + key, + ); changed_at > revision } else { // We found that inputs to this memoized value may have chanced @@ -560,7 +579,7 @@ where ) { runtime.block_on_or_unwind( db.ops_database(), - self.database_key_index, + self.database_key_index(), other_id, mutex_guard, ) @@ -585,7 +604,6 @@ where Q: QueryFunction, MP: MemoizationPolicy, { - database_key_index: DatabaseKeyIndex, slot: &'me Slot, runtime: &'me Runtime, } @@ -595,12 +613,8 @@ where Q: QueryFunction, MP: MemoizationPolicy, { - fn new( - database_key_index: DatabaseKeyIndex, - slot: &'me Slot, - runtime: &'me Runtime, - ) -> Self { - Self { database_key_index, slot, runtime } + fn new(slot: &'me Slot, runtime: &'me Runtime) -> Self { + Self { slot, runtime } } /// Indicates that we have concluded normally (without panicking). @@ -616,17 +630,18 @@ where /// inserted; if others were blocked, waiting for us to finish, /// then notify them. fn overwrite_placeholder(&mut self, wait_result: WaitResult, opt_memo: Option>) { - let mut write = self.slot.state.write(); + let old_value = { + let mut write = self.slot.state.write(); + match opt_memo { + // Replace the `InProgress` marker that we installed with the new + // memo, thus releasing our unique access to this key. + Some(memo) => std::mem::replace(&mut *write, QueryState::Memoized(memo)), - let old_value = match opt_memo { - // Replace the `InProgress` marker that we installed with the new - // memo, thus releasing our unique access to this key. - Some(memo) => std::mem::replace(&mut *write, QueryState::Memoized(memo)), - - // We had installed an `InProgress` marker, but we panicked before - // it could be removed. At this point, we therefore "own" unique - // access to our slot, so we can just remove the key. - None => std::mem::replace(&mut *write, QueryState::NotComputed), + // We had installed an `InProgress` marker, but we panicked before + // it could be removed. At this point, we therefore "own" unique + // access to our slot, so we can just remove the key. + None => std::mem::replace(&mut *write, QueryState::NotComputed), + } }; match old_value { @@ -638,7 +653,8 @@ where // acquire a mutex; the mutex will guarantee that all writes // we are interested in are visible. if anyone_waiting.load(Ordering::Relaxed) { - self.runtime.unblock_queries_blocked_on(self.database_key_index, wait_result); + self.runtime + .unblock_queries_blocked_on(self.slot.database_key_index(), wait_result); } } _ => panic!( @@ -692,10 +708,10 @@ where return None; } if self.verify_revisions(db, revision_now, active_query) { - Some(StampedValue { + self.value.clone().map(|value| StampedValue { durability: self.revisions.durability, changed_at: self.revisions.changed_at, - value: self.value.as_ref().unwrap().clone(), + value, }) } else { None @@ -748,7 +764,7 @@ where // input changed *again*. QueryInputs::Tracked { inputs } => { let changed_input = - inputs.iter().find(|&&input| db.maybe_changed_after(input, verified_at)); + inputs.slice.iter().find(|&&input| db.maybe_changed_after(input, verified_at)); if let Some(input) = changed_input { debug!("validate_memoized_value: `{:?}` may have changed", input); @@ -788,7 +804,7 @@ where MP: MemoizationPolicy, { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "{:?}({:?})", Q::default(), self.key) + write!(fmt, "{:?}", Q::default()) } } diff --git a/src/tools/rust-analyzer/crates/salsa/src/durability.rs b/src/tools/rust-analyzer/crates/salsa/src/durability.rs index 0c82f6345ab6..44abae3170f6 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/durability.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/durability.rs @@ -42,9 +42,9 @@ impl Durability { pub(crate) const MAX: Durability = Self::HIGH; /// Number of durability levels. - pub(crate) const LEN: usize = 3; + pub(crate) const LEN: usize = Self::MAX.index() + 1; - pub(crate) fn index(self) -> usize { + pub(crate) const fn index(self) -> usize { self.0 as usize } } diff --git a/src/tools/rust-analyzer/crates/salsa/src/input.rs b/src/tools/rust-analyzer/crates/salsa/src/input.rs index c2539570e0f9..922ec5a77521 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/input.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/input.rs @@ -29,7 +29,7 @@ where } struct Slot { - database_key_index: DatabaseKeyIndex, + key_index: u32, stamped_value: RwLock>, } @@ -54,27 +54,25 @@ where fn fmt_index( &self, _db: &>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - assert_eq!(index.group_index, self.group_index); - assert_eq!(index.query_index, Q::QUERY_INDEX); let slot_map = self.slots.read(); - let key = slot_map.get_index(index.key_index as usize).unwrap().0; + let key = slot_map.get_index(index as usize).unwrap().0; write!(fmt, "{}({:?})", Q::QUERY_NAME, key) } fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + index: u32, revision: Revision, ) -> bool { - assert_eq!(input.group_index, self.group_index); - assert_eq!(input.query_index, Q::QUERY_INDEX); debug_assert!(revision < db.salsa_runtime().current_revision()); let slots = &self.slots.read(); - let slot = slots.get_index(input.key_index as usize).unwrap().1; + let Some((_, slot)) = slots.get_index(index as usize) else { + return true; + }; debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,); @@ -96,7 +94,11 @@ where let StampedValue { value, durability, changed_at } = slot.stamped_value.read().clone(); db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted( - slot.database_key_index, + DatabaseKeyIndex { + group_index: self.group_index, + query_index: Q::QUERY_INDEX, + key_index: slot.key_index, + }, durability, changed_at, ); @@ -174,16 +176,8 @@ where } Entry::Vacant(entry) => { - let key_index = u32::try_from(entry.index()).unwrap(); - let database_key_index = DatabaseKeyIndex { - group_index: self.group_index, - query_index: Q::QUERY_INDEX, - key_index, - }; - entry.insert(Slot { - database_key_index, - stamped_value: RwLock::new(stamped_value), - }); + let key_index = entry.index() as u32; + entry.insert(Slot { key_index, stamped_value: RwLock::new(stamped_value) }); None } } @@ -196,7 +190,6 @@ pub struct UnitInputStorage where Q: Query, { - group_index: u16, slot: UnitSlot, } @@ -222,36 +215,32 @@ where fn new(group_index: u16) -> Self { let database_key_index = DatabaseKeyIndex { group_index, query_index: Q::QUERY_INDEX, key_index: 0 }; - UnitInputStorage { - group_index, - slot: UnitSlot { database_key_index, stamped_value: RwLock::new(None) }, - } + UnitInputStorage { slot: UnitSlot { database_key_index, stamped_value: RwLock::new(None) } } } fn fmt_index( &self, _db: &>::DynDb, - index: DatabaseKeyIndex, + _index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - assert_eq!(index.group_index, self.group_index); - assert_eq!(index.query_index, Q::QUERY_INDEX); write!(fmt, "{}", Q::QUERY_NAME) } fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + _index: u32, revision: Revision, ) -> bool { - assert_eq!(input.group_index, self.group_index); - assert_eq!(input.query_index, Q::QUERY_INDEX); debug_assert!(revision < db.salsa_runtime().current_revision()); debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,); - let changed_at = self.slot.stamped_value.read().as_ref().unwrap().changed_at; + let Some(value) = &*self.slot.stamped_value.read() else { + return true; + }; + let changed_at = value.changed_at; debug!("maybe_changed_after: changed_at = {:?}", changed_at); diff --git a/src/tools/rust-analyzer/crates/salsa/src/interned.rs b/src/tools/rust-analyzer/crates/salsa/src/interned.rs index 822219f51859..c065e7e2bde5 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/interned.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/interned.rs @@ -265,12 +265,10 @@ where fn fmt_index( &self, _db: &>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - assert_eq!(index.group_index, self.group_index); - assert_eq!(index.query_index, Q::QUERY_INDEX); - let intern_id = InternId::from(index.key_index); + let intern_id = InternId::from(index); let slot = self.lookup_value(intern_id); write!(fmt, "{}({:?})", Q::QUERY_NAME, slot.value) } @@ -278,13 +276,11 @@ where fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + input: u32, revision: Revision, ) -> bool { - assert_eq!(input.group_index, self.group_index); - assert_eq!(input.query_index, Q::QUERY_INDEX); debug_assert!(revision < db.salsa_runtime().current_revision()); - let intern_id = InternId::from(input.key_index); + let intern_id = InternId::from(input); let slot = self.lookup_value(intern_id); slot.maybe_changed_after(revision) } @@ -388,7 +384,7 @@ where fn fmt_index( &self, db: &>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let group_storage = @@ -400,7 +396,7 @@ where fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + input: u32, revision: Revision, ) -> bool { let group_storage = diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs index 668dcfd925d8..fe8075988730 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs @@ -54,7 +54,7 @@ pub trait Database: plumbing::DatabaseOps { /// runtime. It permits the database to be customized and to /// inject logging or other custom behavior. fn salsa_event(&self, event_fn: Event) { - #![allow(unused_variables)] + _ = event_fn; } /// Starts unwinding the stack if the current revision is cancelled. @@ -96,11 +96,16 @@ pub trait Database: plumbing::DatabaseOps { self.ops_salsa_runtime() } - /// Gives access to the underlying salsa runtime. + /// A "synthetic write" causes the system to act *as though* some + /// input of durability `durability` has changed. This is mostly + /// useful for profiling scenarios. /// - /// This method should not be overridden by `Database` implementors. - fn salsa_runtime_mut(&mut self) -> &mut Runtime { - self.ops_salsa_runtime_mut() + /// **WARNING:** Just like an ordinary write, this method triggers + /// cancellation. If you invoke it while a snapshot exists, it + /// will block until that snapshot is dropped -- if that snapshot + /// is owned by the current thread, this could trigger deadlock. + fn synthetic_write(&mut self, durability: Durability) { + plumbing::DatabaseOps::synthetic_write(self, durability) } } @@ -456,12 +461,12 @@ pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> { /// Name of the query method (e.g., `foo`) const QUERY_NAME: &'static str; - /// Extact storage for this query from the storage for its group. + /// Extract storage for this query from the storage for its group. fn query_storage<'a>( group_storage: &'a >::GroupStorage, ) -> &'a std::sync::Arc; - /// Extact storage for this query from the storage for its group. + /// Extract storage for this query from the storage for its group. fn query_storage_mut<'a>( group_storage: &'a >::GroupStorage, ) -> &'a std::sync::Arc; diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs index c6b9778f20ad..1ff85a3ea458 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/lru.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/lru.rs @@ -40,7 +40,7 @@ pub(crate) trait LruNode: Sized + Debug { #[derive(Debug)] pub(crate) struct LruIndex { - /// Index in the approprate LRU list, or std::usize::MAX if not a + /// Index in the appropriate LRU list, or std::usize::MAX if not a /// member. index: AtomicUsize, } diff --git a/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs index 71332e39cadb..1a8ff33b2efc 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs @@ -38,8 +38,15 @@ pub trait DatabaseOps { /// Gives access to the underlying salsa runtime. fn ops_salsa_runtime(&self) -> &Runtime; - /// Gives access to the underlying salsa runtime. - fn ops_salsa_runtime_mut(&mut self) -> &mut Runtime; + /// A "synthetic write" causes the system to act *as though* some + /// input of durability `durability` has changed. This is mostly + /// useful for profiling scenarios. + /// + /// **WARNING:** Just like an ordinary write, this method triggers + /// cancellation. If you invoke it while a snapshot exists, it + /// will block until that snapshot is dropped -- if that snapshot + /// is owned by the current thread, this could trigger deadlock. + fn synthetic_write(&mut self, durability: Durability); /// Formats a database key index in a human readable fashion. fn fmt_index( @@ -166,7 +173,7 @@ where fn fmt_index( &self, db: &>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result; @@ -179,7 +186,7 @@ where fn maybe_changed_after( &self, db: &>::DynDb, - input: DatabaseKeyIndex, + index: u32, revision: Revision, ) -> bool; // ANCHOR_END:maybe_changed_after diff --git a/src/tools/rust-analyzer/crates/salsa/src/revision.rs b/src/tools/rust-analyzer/crates/salsa/src/revision.rs index d97aaf9debab..559b03386087 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/revision.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/revision.rs @@ -46,7 +46,7 @@ pub(crate) struct AtomicRevision { } impl AtomicRevision { - pub(crate) fn start() -> Self { + pub(crate) const fn start() -> Self { Self { data: AtomicU32::new(START) } } diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs index 40b8856991f9..a7d5a2457823 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs @@ -4,13 +4,14 @@ use crate::hash::FxIndexSet; use crate::plumbing::CycleRecoveryStrategy; use crate::revision::{AtomicRevision, Revision}; use crate::{Cancelled, Cycle, Database, DatabaseKeyIndex, Event, EventKind}; +use itertools::Itertools; use parking_lot::lock_api::{RawRwLock, RawRwLockRecursive}; use parking_lot::{Mutex, RwLock}; use std::hash::Hash; use std::panic::panic_any; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use tracing::debug; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; mod dependency_graph; use dependency_graph::DependencyGraph; @@ -297,8 +298,7 @@ impl Runtime { // (at least for this execution, not necessarily across executions), // no matter where it started on the stack. Find the minimum // key and rotate it to the front. - let min = v.iter().min().unwrap(); - let index = v.iter().position(|p| p == min).unwrap(); + let index = v.iter().position_min().unwrap_or_default(); v.rotate_left(index); // No need to store extra memory. @@ -440,7 +440,7 @@ impl Runtime { /// State that will be common to all threads (when we support multiple threads) struct SharedState { /// Stores the next id to use for a snapshotted runtime (starts at 1). - next_id: AtomicUsize, + next_id: AtomicU32, /// Whenever derived queries are executing, they acquire this lock /// in read mode. Mutating inputs (and thus creating a new @@ -457,50 +457,46 @@ struct SharedState { /// revision is cancelled). pending_revision: AtomicRevision, - /// Stores the "last change" revision for values of each duration. + /// Stores the "last change" revision for values of each Durability. /// This vector is always of length at least 1 (for Durability 0) - /// but its total length depends on the number of durations. The + /// but its total length depends on the number of Durabilities. The /// element at index 0 is special as it represents the "current /// revision". In general, we have the invariant that revisions /// in here are *declining* -- that is, `revisions[i] >= /// revisions[i + 1]`, for all `i`. This is because when you /// modify a value with durability D, that implies that values /// with durability less than D may have changed too. - revisions: Vec, + revisions: [AtomicRevision; Durability::LEN], /// The dependency graph tracks which runtimes are blocked on one /// another, waiting for queries to terminate. dependency_graph: Mutex, } -impl SharedState { - fn with_durabilities(durabilities: usize) -> Self { +impl std::panic::RefUnwindSafe for SharedState {} + +impl Default for SharedState { + fn default() -> Self { + #[allow(clippy::declare_interior_mutable_const)] + const START: AtomicRevision = AtomicRevision::start(); SharedState { - next_id: AtomicUsize::new(1), + next_id: AtomicU32::new(1), query_lock: Default::default(), - revisions: (0..durabilities).map(|_| AtomicRevision::start()).collect(), - pending_revision: AtomicRevision::start(), + revisions: [START; Durability::LEN], + pending_revision: START, dependency_graph: Default::default(), } } } -impl std::panic::RefUnwindSafe for SharedState {} - -impl Default for SharedState { - fn default() -> Self { - Self::with_durabilities(Durability::LEN) - } -} - impl std::fmt::Debug for SharedState { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let query_lock = if self.query_lock.try_write().is_some() { - "" - } else if self.query_lock.try_read().is_some() { + let query_lock = if self.query_lock.is_locked_exclusive() { + "" + } else if self.query_lock.is_locked() { "" } else { - "" + "" }; fmt.debug_struct("SharedState") .field("query_lock", &query_lock) @@ -570,7 +566,9 @@ impl ActiveQuery { if dependencies.is_empty() { QueryInputs::NoInputs } else { - QueryInputs::Tracked { inputs: dependencies.iter().copied().collect() } + QueryInputs::Tracked { + inputs: ThinArc::from_header_and_iter((), dependencies.iter().copied()), + } } } }; @@ -616,7 +614,7 @@ impl ActiveQuery { /// complete, its `RuntimeId` may potentially be re-used. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct RuntimeId { - counter: usize, + counter: u32, } #[derive(Clone, Debug)] diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs index e41eb280deee..dd223eeeba9f 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs @@ -12,7 +12,7 @@ type QueryStack = Vec; #[derive(Debug, Default)] pub(super) struct DependencyGraph { - /// A `(K -> V)` pair in this map indicates that the the runtime + /// A `(K -> V)` pair in this map indicates that the runtime /// `K` is blocked on some query executing in the runtime `V`. /// This encodes a graph that must be acyclic (or else deadlock /// will result). diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs index 91b95dffe78a..7ac21dec1a89 100644 --- a/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs +++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs @@ -1,5 +1,6 @@ //! use tracing::debug; +use triomphe::ThinArc; use crate::durability::Durability; use crate::runtime::ActiveQuery; @@ -7,7 +8,6 @@ use crate::runtime::Revision; use crate::Cycle; use crate::DatabaseKeyIndex; use std::cell::RefCell; -use triomphe::Arc; /// State that is specific to a single execution thread. /// @@ -43,7 +43,7 @@ pub(crate) struct QueryRevisions { #[derive(Debug, Clone)] pub(crate) enum QueryInputs { /// Non-empty set of inputs, fully known - Tracked { inputs: Arc<[DatabaseKeyIndex]> }, + Tracked { inputs: ThinArc<(), DatabaseKeyIndex> }, /// Empty set of inputs, fully known. NoInputs, @@ -145,8 +145,7 @@ impl LocalState { /// the current thread is blocking. The stack must be restored /// with [`Self::restore_query_stack`] when the thread unblocks. pub(super) fn take_query_stack(&self) -> Vec { - assert!(self.query_stack.borrow().is_some(), "query stack already taken"); - self.query_stack.take().unwrap() + self.query_stack.take().expect("query stack already taken") } /// Restores a query stack taken with [`Self::take_query_stack`] once diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs index 6dc5030063b7..3dcc32eece37 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs @@ -58,7 +58,7 @@ fn revalidate() { // Second generation: volatile will change (to 1) but memoized1 // will not (still 0, as 1/2 = 0) - query.salsa_runtime_mut().synthetic_write(Durability::LOW); + query.synthetic_write(Durability::LOW); query.memoized2(); query.assert_log(&["Volatile invoked", "Memoized1 invoked"]); query.memoized2(); @@ -67,7 +67,7 @@ fn revalidate() { // Third generation: volatile will change (to 2) and memoized1 // will too (to 1). Therefore, after validating that Memoized1 // changed, we now invoke Memoized2. - query.salsa_runtime_mut().synthetic_write(Durability::LOW); + query.synthetic_write(Durability::LOW); query.memoized2(); query.assert_log(&["Volatile invoked", "Memoized1 invoked", "Memoized2 invoked"]); diff --git a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs index 5d0e4866442e..677d633ee7cc 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs @@ -111,7 +111,7 @@ fn on_demand_input_durability() { } "#]].assert_debug_eq(&events); - db.salsa_runtime_mut().synthetic_write(Durability::LOW); + db.synthetic_write(Durability::LOW); events.replace(vec![]); assert_eq!(db.c(1), 10); assert_eq!(db.c(2), 20); @@ -128,7 +128,7 @@ fn on_demand_input_durability() { } "#]].assert_debug_eq(&events); - db.salsa_runtime_mut().synthetic_write(Durability::HIGH); + db.synthetic_write(Durability::HIGH); events.replace(vec![]); assert_eq!(db.c(1), 10); assert_eq!(db.c(2), 20); diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs index f75c7c142feb..8e2f9b03cb9a 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs @@ -20,7 +20,7 @@ fn volatile_twice() { let v2 = db.volatile(); // volatiles are cached, so 2nd read returns the same assert_eq!(v1, v2); - db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches + db.synthetic_write(Durability::LOW); // clears volatile caches let v3 = db.volatile(); // will re-increment the counter let v4 = db.volatile(); // second call will be cached @@ -40,7 +40,7 @@ fn intermingled() { assert_eq!(v1, v3); assert_eq!(v2, v4); - db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches + db.synthetic_write(Durability::LOW); // clears volatile caches let v5 = db.memoized(); // re-executes volatile, caches new result let v6 = db.memoized(); // re-use cached result diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 9a9ebae74e8c..0504ca50b882 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -302,6 +302,22 @@ pub fn slice_tails(this: &[T]) -> impl Iterator { (0..this.len()).map(|i| &this[i..]) } +pub trait IsNoneOr { + type Type; + #[allow(clippy::wrong_self_convention)] + fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool; +} +#[allow(unstable_name_collisions)] +impl IsNoneOr for Option { + type Type = T; + fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { + match self { + Some(v) => f(v), + None => true, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 3d33d255ad49..849fae5cf24b 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -4,7 +4,11 @@ import * as ra from "./lsp_ext"; import * as path from "path"; import type { Ctx, Cmd, CtxInit } from "./ctx"; -import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; +import { + applySnippetWorkspaceEdit, + applySnippetTextEdits, + type SnippetTextDocumentEdit, +} from "./snippets"; import { spawnSync } from "child_process"; import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; import { AstInspector } from "./ast_inspector"; @@ -1006,7 +1010,6 @@ export function resolveCodeAction(ctx: CtxInit): Cmd { return; } const itemEdit = item.edit; - const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit); // filter out all text edits and recreate the WorkspaceEdit without them so we can apply // snippet edits on our own const lcFileSystemEdit = { @@ -1017,16 +1020,71 @@ export function resolveCodeAction(ctx: CtxInit): Cmd { lcFileSystemEdit, ); await vscode.workspace.applyEdit(fileSystemEdit); - await applySnippetWorkspaceEdit(edit); + + // replace all text edits so that we can convert snippet text edits into `vscode.SnippetTextEdit`s + // FIXME: this is a workaround until vscode-languageclient supports doing the SnippeTextEdit conversion itself + // also need to carry the snippetTextDocumentEdits separately, since we can't retrieve them again using WorkspaceEdit.entries + const [workspaceTextEdit, snippetTextDocumentEdits] = asWorkspaceSnippetEdit(ctx, itemEdit); + await applySnippetWorkspaceEdit(workspaceTextEdit, snippetTextDocumentEdits); if (item.command != null) { await vscode.commands.executeCommand(item.command.command, item.command.arguments); } }; } +function asWorkspaceSnippetEdit( + ctx: CtxInit, + item: lc.WorkspaceEdit, +): [vscode.WorkspaceEdit, SnippetTextDocumentEdit[]] { + const client = ctx.client; + + // partially borrowed from https://github.com/microsoft/vscode-languageserver-node/blob/295aaa393fda8ecce110c38880a00466b9320e63/client/src/common/protocolConverter.ts#L1060-L1101 + const result = new vscode.WorkspaceEdit(); + + if (item.documentChanges) { + const snippetTextDocumentEdits: SnippetTextDocumentEdit[] = []; + + for (const change of item.documentChanges) { + if (lc.TextDocumentEdit.is(change)) { + const uri = client.protocol2CodeConverter.asUri(change.textDocument.uri); + const snippetTextEdits: (vscode.TextEdit | vscode.SnippetTextEdit)[] = []; + + for (const edit of change.edits) { + if ( + "insertTextFormat" in edit && + edit.insertTextFormat === lc.InsertTextFormat.Snippet + ) { + // is a snippet text edit + snippetTextEdits.push( + new vscode.SnippetTextEdit( + client.protocol2CodeConverter.asRange(edit.range), + new vscode.SnippetString(edit.newText), + ), + ); + } else { + // always as a text document edit + snippetTextEdits.push( + vscode.TextEdit.replace( + client.protocol2CodeConverter.asRange(edit.range), + edit.newText, + ), + ); + } + } + + snippetTextDocumentEdits.push([uri, snippetTextEdits]); + } + } + return [result, snippetTextDocumentEdits]; + } else { + // we don't handle WorkspaceEdit.changes since it's not relevant for code actions + return [result, []]; + } +} + export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd { return async (edit: vscode.WorkspaceEdit) => { - await applySnippetWorkspaceEdit(edit); + await applySnippetWorkspaceEdit(edit, edit.entries()); }; } diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts index d81765649ffb..b3982bdf2be4 100644 --- a/src/tools/rust-analyzer/editors/code/src/snippets.ts +++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts @@ -3,20 +3,28 @@ import * as vscode from "vscode"; import { assert } from "./util"; import { unwrapUndefinable } from "./undefinable"; -export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { - if (edit.entries().length === 1) { - const [uri, edits] = unwrapUndefinable(edit.entries()[0]); +export type SnippetTextDocumentEdit = [vscode.Uri, (vscode.TextEdit | vscode.SnippetTextEdit)[]]; + +export async function applySnippetWorkspaceEdit( + edit: vscode.WorkspaceEdit, + editEntries: SnippetTextDocumentEdit[], +) { + if (editEntries.length === 1) { + const [uri, edits] = unwrapUndefinable(editEntries[0]); const editor = await editorFromUri(uri); - if (editor) await applySnippetTextEdits(editor, edits); + if (editor) { + edit.set(uri, removeLeadingWhitespace(editor, edits)); + await vscode.workspace.applyEdit(edit); + } return; } - for (const [uri, edits] of edit.entries()) { + for (const [uri, edits] of editEntries) { const editor = await editorFromUri(uri); if (editor) { await editor.edit((builder) => { for (const indel of edits) { assert( - !parseSnippet(indel.newText), + !(indel instanceof vscode.SnippetTextEdit), `bad ws edit: snippet received with multiple edits: ${JSON.stringify( edit, )}`, @@ -39,53 +47,97 @@ async function editorFromUri(uri: vscode.Uri): Promise { - for (const indel of edits) { - const parsed = parseSnippet(indel.newText); - if (parsed) { - const [newText, [placeholderStart, placeholderLength]] = parsed; - const prefix = newText.substr(0, placeholderStart); - const lastNewline = prefix.lastIndexOf("\n"); + const edit = new vscode.WorkspaceEdit(); + const snippetEdits = toSnippetTextEdits(edits); + edit.set(editor.document.uri, removeLeadingWhitespace(editor, snippetEdits)); + await vscode.workspace.applyEdit(edit); +} - const startLine = indel.range.start.line + lineDelta + countLines(prefix); - const startColumn = - lastNewline === -1 - ? indel.range.start.character + placeholderStart - : prefix.length - lastNewline - 1; - const endColumn = startColumn + placeholderLength; - selections.push( - new vscode.Selection( - new vscode.Position(startLine, startColumn), - new vscode.Position(startLine, endColumn), - ), - ); - builder.replace(indel.range, newText); - } else { - builder.replace(indel.range, indel.newText); - } - lineDelta += - countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); +function hasSnippet(snip: string): boolean { + const m = snip.match(/\$\d+|\{\d+:[^}]*\}/); + return m != null; +} + +function toSnippetTextEdits( + edits: vscode.TextEdit[], +): (vscode.TextEdit | vscode.SnippetTextEdit)[] { + return edits.map((textEdit) => { + // Note: text edits without any snippets are returned as-is instead of + // being wrapped in a SnippetTextEdit, as otherwise it would be + // treated as if it had a tab stop at the end. + if (hasSnippet(textEdit.newText)) { + return new vscode.SnippetTextEdit( + textEdit.range, + new vscode.SnippetString(textEdit.newText), + ); + } else { + return textEdit; } }); - if (selections.length > 0) editor.selections = selections; - if (selections.length === 1) { - const selection = unwrapUndefinable(selections[0]); - editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport); +} + +/** + * Removes the leading whitespace from snippet edits, so as to not double up + * on indentation. + * + * Snippet edits by default adjust any multi-line snippets to match the + * indentation of the line to insert at. Unfortunately, we (the server) also + * include the required indentation to match what we line insert at, so we end + * up doubling up the indentation. Since there isn't any way to tell vscode to + * not fixup indentation for us, we instead opt to remove the indentation and + * then let vscode add it back in. + * + * This assumes that the source snippet text edits have the required + * indentation, but that's okay as even without this workaround and the problem + * to workaround, those snippet edits would already be inserting at the wrong + * indentation. + */ +function removeLeadingWhitespace( + editor: vscode.TextEditor, + edits: (vscode.TextEdit | vscode.SnippetTextEdit)[], +) { + return edits.map((edit) => { + if (edit instanceof vscode.SnippetTextEdit) { + const snippetEdit: vscode.SnippetTextEdit = edit; + const firstLineEnd = snippetEdit.snippet.value.indexOf("\n"); + + if (firstLineEnd !== -1) { + // Is a multi-line snippet, remove the indentation which + // would be added back in by vscode. + const startLine = editor.document.lineAt(snippetEdit.range.start.line); + const leadingWhitespace = getLeadingWhitespace( + startLine.text, + 0, + startLine.firstNonWhitespaceCharacterIndex, + ); + + const [firstLine, rest] = splitAt(snippetEdit.snippet.value, firstLineEnd + 1); + const unindentedLines = rest + .split("\n") + .map((line) => line.replace(leadingWhitespace, "")) + .join("\n"); + + snippetEdit.snippet.value = firstLine + unindentedLines; + } + + return snippetEdit; + } else { + return edit; + } + }); +} + +// based on https://github.com/microsoft/vscode/blob/main/src/vs/base/common/strings.ts#L284 +function getLeadingWhitespace(str: string, start: number = 0, end: number = str.length): string { + for (let i = start; i < end; i++) { + const chCode = str.charCodeAt(i); + if (chCode !== " ".charCodeAt(0) && chCode !== " ".charCodeAt(0)) { + return str.substring(start, i); + } } + return str.substring(start, end); } -function parseSnippet(snip: string): [string, [number, number]] | undefined { - const m = snip.match(/\$(0|\{0:([^}]*)\})/); - if (!m) return undefined; - const placeholder = m[2] ?? ""; - if (m.index == null) return undefined; - const range: [number, number] = [m.index, placeholder.length]; - const insert = snip.replace(m[0], placeholder); - return [insert, range]; -} - -function countLines(text: string): number { - return (text.match(/\n/g) || []).length; +function splitAt(str: string, index: number): [string, string] { + return [str.substring(0, index), str.substring(index)]; } diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs index 2efafa10a828..285abb9efcb4 100644 --- a/src/tools/rust-analyzer/xtask/src/metrics.rs +++ b/src/tools/rust-analyzer/xtask/src/metrics.rs @@ -86,7 +86,11 @@ impl Metrics { fn measure_rustc_tests(&mut self, sh: &Shell) -> anyhow::Result<()> { eprintln!("\nMeasuring rustc tests"); - cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust").run()?; + cmd!( + sh, + "git clone --depth=1 --branch 1.76.0 https://github.com/rust-lang/rust.git --single-branch" + ) + .run()?; let output = cmd!(sh, "./target/release/rust-analyzer rustc-tests ./rust").read()?; for (metric, value, unit) in parse_metrics(&output) { diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs index 902b2ec69078..4e840dbfbb44 100644 --- a/src/tools/rust-installer/src/compression.rs +++ b/src/tools/rust-installer/src/compression.rs @@ -1,11 +1,12 @@ use anyhow::{Context, Error}; use flate2::{read::GzDecoder, write::GzEncoder}; use rayon::prelude::*; -use std::{convert::TryFrom, fmt, io::Read, io::Write, path::Path, str::FromStr}; +use std::{fmt, io::Read, io::Write, path::Path, str::FromStr}; use xz2::{read::XzDecoder, write::XzEncoder}; #[derive(Default, Debug, Copy, Clone)] pub enum CompressionProfile { + NoOp, Fast, #[default] Balanced, @@ -20,6 +21,7 @@ impl FromStr for CompressionProfile { "fast" => Self::Fast, "balanced" => Self::Balanced, "best" => Self::Best, + "no-op" => Self::NoOp, other => anyhow::bail!("invalid compression profile: {other}"), }) } @@ -31,6 +33,7 @@ impl fmt::Display for CompressionProfile { CompressionProfile::Fast => f.write_str("fast"), CompressionProfile::Balanced => f.write_str("balanced"), CompressionProfile::Best => f.write_str("best"), + CompressionProfile::NoOp => f.write_str("no-op"), } } } @@ -78,10 +81,16 @@ impl CompressionFormat { CompressionProfile::Fast => flate2::Compression::fast(), CompressionProfile::Balanced => flate2::Compression::new(6), CompressionProfile::Best => flate2::Compression::best(), + CompressionProfile::NoOp => panic!( + "compression profile 'no-op' should not call `CompressionFormat::encode`." + ), }, )), CompressionFormat::Xz => { let encoder = match profile { + CompressionProfile::NoOp => panic!( + "compression profile 'no-op' should not call `CompressionFormat::encode`." + ), CompressionProfile::Fast => { xz2::stream::MtStreamBuilder::new().threads(6).preset(1).encoder().unwrap() } diff --git a/src/tools/rust-installer/src/main.rs b/src/tools/rust-installer/src/main.rs index 99acecdd43c3..efb4c5bcb83f 100644 --- a/src/tools/rust-installer/src/main.rs +++ b/src/tools/rust-installer/src/main.rs @@ -1,5 +1,5 @@ use anyhow::{Context, Result}; -use clap::{self, Parser}; +use clap::Parser; #[derive(Parser)] struct CommandLine { diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index 7572dc6dcf88..e5a925b2cbf2 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -38,6 +38,10 @@ actor! { impl Tarballer { /// Generates the actual tarballs pub fn run(self) -> Result<()> { + if let CompressionProfile::NoOp = self.compression_profile { + return Ok(()); + } + let tarball_name = self.output.clone() + ".tar"; let encoder = CombinedEncoder::new( self.compression_formats diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs index 958f9b0154f7..512a8593c27c 100644 --- a/src/tools/rustfmt/src/source_file.rs +++ b/src/tools/rustfmt/src/source_file.rs @@ -66,6 +66,7 @@ where } } + #[cfg_attr(not(bootstrap), allow(non_local_definitions))] impl From<&FileName> for rustc_span::FileName { fn from(filename: &FileName) -> rustc_span::FileName { match filename { diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs index 943542288863..5b85da1d4a0c 100644 --- a/tests/codegen/array-equality.rs +++ b/tests/codegen/array-equality.rs @@ -1,7 +1,7 @@ //@ compile-flags: -O -Z merge-functions=disabled //@ only-x86_64 - #![crate_type = "lib"] +#![feature(generic_nonzero)] // CHECK-LABEL: @array_eq_value #[no_mangle] @@ -63,7 +63,7 @@ pub fn array_eq_zero_short(x: [u16; 3]) -> bool { // CHECK-LABEL: @array_eq_none_short(i40 #[no_mangle] -pub fn array_eq_none_short(x: [Option; 5]) -> bool { +pub fn array_eq_none_short(x: [Option>; 5]) -> bool { // CHECK-NEXT: start: // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0 // CHECK-NEXT: ret i1 %[[EQ]] diff --git a/tests/codegen/enum/enum-debug-niche-2.rs b/tests/codegen/enum/enum-debug-niche-2.rs index 4315741e0bdd..25871885e7ea 100644 --- a/tests/codegen/enum/enum-debug-niche-2.rs +++ b/tests/codegen/enum/enum-debug-niche-2.rs @@ -1,20 +1,17 @@ -// This tests that optimized enum debug info accurately reflects the enum layout. -// This is ignored for the fallback mode on MSVC due to problems with PDB. - -// -//@ ignore-msvc - +//! This tests that optimized enum debug info accurately reflects the enum layout. +//! This is ignored for the fallback mode on MSVC due to problems with PDB. +//! //@ compile-flags: -g -C no-prepopulate-passes - +//@ ignore-msvc +// // CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}} // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i128 4294967295{{[,)].*}} // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i128 0{{[,)].*}} - -#![feature(never_type)] +#![feature(generic_nonzero, never_type)] #[derive(Copy, Clone)] pub struct Entity { - private: std::num::NonZeroU32, + private: std::num::NonZero, } #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index 88cedcf46b69..b75c188f51a9 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -1,10 +1,10 @@ //@ compile-flags: -O -C no-prepopulate-passes - #![crate_type = "lib"] #![feature(dyn_star)] +#![feature(generic_nonzero)] use std::mem::MaybeUninit; -use std::num::NonZeroU64; +use std::num::NonZero; use std::marker::PhantomPinned; use std::ptr::NonNull; @@ -70,13 +70,13 @@ pub fn int(x: u64) -> u64 { // CHECK: noundef i64 @nonzero_int(i64 noundef %x) #[no_mangle] -pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 { +pub fn nonzero_int(x: NonZero) -> NonZero { x } // CHECK: noundef i64 @option_nonzero_int(i64 noundef %x) #[no_mangle] -pub fn option_nonzero_int(x: Option) -> Option { +pub fn option_nonzero_int(x: Option>) -> Option> { x } diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index 7c448c82e4b2..b5e0da1b2f5f 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -2,11 +2,11 @@ //@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes //@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes //@ only-64bit (so I don't need to worry about usize) - #![crate_type = "lib"] +#![feature(generic_nonzero)] use std::mem::transmute; -use std::num::NonZeroU32; +use std::num::NonZero; #[repr(u8)] pub enum SmallEnum { @@ -130,7 +130,7 @@ pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char { // CHECK-LABEL: @check_swap_pair( #[no_mangle] -pub unsafe fn check_swap_pair(x: (char, NonZeroU32)) -> (NonZeroU32, char) { +pub unsafe fn check_swap_pair(x: (char, NonZero)) -> (NonZero, char) { // OPT: %0 = icmp ule i32 %x.0, 1114111 // OPT: call void @llvm.assume(i1 %0) // OPT: %1 = icmp uge i32 %x.0, 1 diff --git a/tests/codegen/issues/issue-119422.rs b/tests/codegen/issues/issue-119422.rs index 937fdcf28f5d..19480b4dc9e1 100644 --- a/tests/codegen/issues/issue-119422.rs +++ b/tests/codegen/issues/issue-119422.rs @@ -1,13 +1,13 @@ //! This test checks that compiler don't generate useless compares to zeros -//! for NonZero integer types. - +//! for `NonZero` integer types. +//! //@ compile-flags: -O --edition=2021 -Zmerge-functions=disabled //@ only-64bit (because the LLVM type of i64 for usize shows up) - #![crate_type = "lib"] +#![feature(generic_nonzero)] -use core::num::*; use core::ptr::NonNull; +use core::num::NonZero; // CHECK-LABEL: @check_non_null #[no_mangle] @@ -18,7 +18,7 @@ pub fn check_non_null(x: NonNull) -> bool { // CHECK-LABEL: @equals_zero_is_false_u8 #[no_mangle] -pub fn equals_zero_is_false_u8(x: NonZeroU8) -> bool { +pub fn equals_zero_is_false_u8(x: NonZero) -> bool { // CHECK-NOT: br // CHECK: ret i1 false // CHECK-NOT: br @@ -27,7 +27,7 @@ pub fn equals_zero_is_false_u8(x: NonZeroU8) -> bool { // CHECK-LABEL: @not_equals_zero_is_true_u8 #[no_mangle] -pub fn not_equals_zero_is_true_u8(x: NonZeroU8) -> bool { +pub fn not_equals_zero_is_true_u8(x: NonZero) -> bool { // CHECK-NOT: br // CHECK: ret i1 true // CHECK-NOT: br @@ -36,7 +36,7 @@ pub fn not_equals_zero_is_true_u8(x: NonZeroU8) -> bool { // CHECK-LABEL: @equals_zero_is_false_i8 #[no_mangle] -pub fn equals_zero_is_false_i8(x: NonZeroI8) -> bool { +pub fn equals_zero_is_false_i8(x: NonZero) -> bool { // CHECK-NOT: br // CHECK: ret i1 false // CHECK-NOT: br @@ -45,7 +45,7 @@ pub fn equals_zero_is_false_i8(x: NonZeroI8) -> bool { // CHECK-LABEL: @not_equals_zero_is_true_i8 #[no_mangle] -pub fn not_equals_zero_is_true_i8(x: NonZeroI8) -> bool { +pub fn not_equals_zero_is_true_i8(x: NonZero) -> bool { // CHECK-NOT: br // CHECK: ret i1 true // CHECK-NOT: br @@ -54,7 +54,7 @@ pub fn not_equals_zero_is_true_i8(x: NonZeroI8) -> bool { // CHECK-LABEL: @usize_try_from_u32 #[no_mangle] -pub fn usize_try_from_u32(x: NonZeroU32) -> NonZeroUsize { +pub fn usize_try_from_u32(x: NonZero) -> NonZero { // CHECK-NOT: br // CHECK: zext i32 %{{.*}} to i64 // CHECK-NOT: br @@ -64,7 +64,7 @@ pub fn usize_try_from_u32(x: NonZeroU32) -> NonZeroUsize { // CHECK-LABEL: @isize_try_from_i32 #[no_mangle] -pub fn isize_try_from_i32(x: NonZeroI32) -> NonZeroIsize { +pub fn isize_try_from_i32(x: NonZero) -> NonZero { // CHECK-NOT: br // CHECK: sext i32 %{{.*}} to i64 // CHECK-NOT: br @@ -74,7 +74,7 @@ pub fn isize_try_from_i32(x: NonZeroI32) -> NonZeroIsize { // CHECK-LABEL: @u64_from_nonzero_is_not_zero #[no_mangle] -pub fn u64_from_nonzero_is_not_zero(x: NonZeroU64)->bool { +pub fn u64_from_nonzero_is_not_zero(x: NonZero)->bool { // CHECK-NOT: br // CHECK: ret i1 false // CHECK-NOT: br diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs index 0471d83c25a3..b86b3dd3a196 100644 --- a/tests/codegen/loads.rs +++ b/tests/codegen/loads.rs @@ -1,9 +1,9 @@ //@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 - #![crate_type = "lib"] +#![feature(generic_nonzero)] use std::mem::MaybeUninit; -use std::num::NonZeroU16; +use std::num::NonZero; pub struct Bytes { a: u8, @@ -99,14 +99,14 @@ pub fn load_int(x: &u16) -> u16 { // CHECK-LABEL: @load_nonzero_int #[no_mangle] -pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 { +pub fn load_nonzero_int(x: &NonZero) -> NonZero { // CHECK: load i16, ptr %x, align 2, !range ![[NONZEROU16_RANGE:[0-9]+]], !noundef !{{[0-9]+}} *x } // CHECK-LABEL: @load_option_nonzero_int #[no_mangle] -pub fn load_option_nonzero_int(x: &Option) -> Option { +pub fn load_option_nonzero_int(x: &Option>) -> Option> { // CHECK: load i16, ptr %x, align 2, !noundef ![[NOUNDEF]]{{$}} *x } diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index 990ec1d1f66b..14a392436078 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -1,14 +1,13 @@ //@ compile-flags: -O -Z randomize-layout=no //@ only-x86_64 //@ ignore-llvm-version: 16.0.0 -// ^ needs https://reviews.llvm.org/D146149 in 16.0.1 - +// ^-- needs https://reviews.llvm.org/D146149 in 16.0.1 #![crate_type = "lib"] -#![feature(option_as_slice)] +#![feature(generic_nonzero)] extern crate core; -use core::num::NonZeroU64; +use core::num::NonZero; use core::option::Option; // CHECK-LABEL: @u64_opt_as_slice @@ -23,7 +22,7 @@ pub fn u64_opt_as_slice(o: &Option) -> &[u64] { // CHECK-LABEL: @nonzero_u64_opt_as_slice #[no_mangle] -pub fn nonzero_u64_opt_as_slice(o: &Option) -> &[NonZeroU64] { +pub fn nonzero_u64_opt_as_slice(o: &Option>) -> &[NonZero] { // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs index f6be90a5ddeb..f637b1aef975 100644 --- a/tests/codegen/option-nonzero-eq.rs +++ b/tests/codegen/option-nonzero-eq.rs @@ -1,18 +1,18 @@ //@ compile-flags: -O -Zmerge-functions=disabled - #![crate_type = "lib"] +#![feature(generic_nonzero)] extern crate core; use core::cmp::Ordering; -use core::num::{NonZeroU32, NonZeroI64}; use core::ptr::NonNull; +use core::num::NonZero; // See also tests/assembly/option-nonzero-eq.rs, for cases with `assume`s in the // LLVM and thus don't optimize down clearly here, but do in assembly. // CHECK-lABEL: @non_zero_eq #[no_mangle] -pub fn non_zero_eq(l: Option, r: Option) -> bool { +pub fn non_zero_eq(l: Option>, r: Option>) -> bool { // CHECK: start: // CHECK-NEXT: icmp eq i32 // CHECK-NEXT: ret i1 @@ -21,7 +21,7 @@ pub fn non_zero_eq(l: Option, r: Option) -> bool { // CHECK-lABEL: @non_zero_signed_eq #[no_mangle] -pub fn non_zero_signed_eq(l: Option, r: Option) -> bool { +pub fn non_zero_signed_eq(l: Option>, r: Option>) -> bool { // CHECK: start: // CHECK-NEXT: icmp eq i64 // CHECK-NEXT: ret i1 diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs index 371e685ec6c9..85d9c34a30b5 100644 --- a/tests/codegen/slice-ref-equality.rs +++ b/tests/codegen/slice-ref-equality.rs @@ -1,8 +1,8 @@ //@ compile-flags: -O -Zmerge-functions=disabled - #![crate_type = "lib"] +#![feature(generic_nonzero)] -use std::num::{NonZeroI16, NonZeroU32}; +use std::num::NonZero; // #71602 reported a simple array comparison just generating a loop. // This was originally fixed by ensuring it generates a single bcmp, @@ -70,7 +70,7 @@ fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { // CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 // CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] -fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool { +fn eq_slice_of_nonzero(x: &[NonZero], y: &[NonZero]) -> bool { // CHECK: icmp eq [[USIZE]] %1, %3 // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr @@ -82,7 +82,7 @@ fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool { // CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 // CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] -fn eq_slice_of_option_of_nonzero(x: &[Option], y: &[Option]) -> bool { +fn eq_slice_of_option_of_nonzero(x: &[Option>], y: &[Option>]) -> bool { // CHECK: icmp eq [[USIZE]] %1, %3 // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs index 9217def76b51..1a5f53e625ae 100644 --- a/tests/codegen/transmute-optimized.rs +++ b/tests/codegen/transmute-optimized.rs @@ -1,6 +1,6 @@ //@ compile-flags: -O -Z merge-functions=disabled - #![crate_type = "lib"] +#![feature(generic_nonzero)] // This tests that LLVM can optimize based on the niches in the source or // destination types for transmutes. @@ -33,7 +33,7 @@ pub fn non_null_is_null(x: std::ptr::NonNull) -> bool { // CHECK-LABEL: i1 @non_zero_is_null( #[no_mangle] -pub fn non_zero_is_null(x: std::num::NonZeroUsize) -> bool { +pub fn non_zero_is_null(x: std::num::NonZero) -> bool { // CHECK: ret i1 false let p: *const i32 = unsafe { std::mem::transmute(x) }; p.is_null() @@ -72,7 +72,7 @@ pub fn normal_div(a: u32, b: u32) -> u32 { // CHECK-LABEL: i32 @div_transmute_nonzero(i32 #[no_mangle] -pub fn div_transmute_nonzero(a: u32, b: std::num::NonZeroI32) -> u32 { +pub fn div_transmute_nonzero(a: u32, b: std::num::NonZero) -> u32 { // CHECK-NOT: call core::panicking::panic // CHECK: %[[R:.+]] = udiv i32 %a, %b // CHECK-NEXT: ret i32 %[[R]] diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index c6dd9f7939df..cfac14a22c41 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -1,143 +1,143 @@ //@ only-cdb //@ compile-flags:-g - +// // cdb-command: g - +// // cdb-command: dx a // cdb-check:a : Some [Type: enum2$ >] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] - +// // cdb-command: dx b // cdb-check:b : None [Type: enum2$ >] - +// // cdb-command: dx c // cdb-check:c : Tag1 [Type: enum2$] - +// // cdb-command: dx d // cdb-check:d : Data [Type: enum2$] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] - +// // cdb-command: dx e // cdb-check:e : Tag2 [Type: enum2$] - +// // cdb-command: dx f // cdb-check:f : Some [Type: enum2$ > >] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] - +// // cdb-command: dx g // cdb-check:g : None [Type: enum2$ > >] - +// // cdb-command: dx h // cdb-check:h : Some [Type: enum2$ >] // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] - +// // cdb-command: dx i // cdb-check:i : None [Type: enum2$ >] - +// // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] - +// // cdb-command: dx k // cdb-check:k : Some [Type: enum2$ >] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] - +// // cdb-command: dx l // cdb-check:l : Ok [Type: enum2$ > >] // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] - +// // cdb-command: dx niche128_some // cdb-check: niche128_some : Some [Type: enum2$ > >] // 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::NonZero] - +// // cdb-command: dx niche128_none // cdb-check: niche128_none : None [Type: enum2$ > >] - +// // cdb-command: dx wrapping_niche128_untagged // cdb-check: wrapping_niche128_untagged : X [Type: enum2$] // cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] - +// // cdb-command: dx wrapping_niche128_none1 // cdb-check: wrapping_niche128_none1 : Y [Type: enum2$] // cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] - +// // cdb-command: dx wrapping_niche128_none2 // cdb-check: wrapping_niche128_none2 : Z [Type: enum2$] // cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] - +// // cdb-command: dx direct_tag_128_a,d // cdb-check: direct_tag_128_a,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 42 [Type: unsigned int] - +// // cdb-command: dx direct_tag_128_b,d // cdb-check: direct_tag_128_b,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 137 [Type: unsigned int] - +// // cdb-command: dx niche_w_fields_1_some,d // cdb-check: niche_w_fields_1_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 0x[...] : 77 [Type: unsigned char *] // cdb-check: [+0x[...]] __1 : 7 [Type: unsigned int] - +// // cdb-command: dx niche_w_fields_1_none,d // cdb-check: niche_w_fields_1_none,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 99 [Type: unsigned int] - +// // cdb-command: dx niche_w_fields_2_some,d // cdb-check: niche_w_fields_2_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZero] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] - +// // cdb-command: dx niche_w_fields_2_none,d // cdb-check: niche_w_fields_2_none,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 1000 [Type: unsigned __int64] - +// // cdb-command: dx niche_w_fields_3_some,d // cdb-check: niche_w_fields_3_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 137 [Type: unsigned char] // cdb-check: [+0x[...]] __1 : true [Type: bool] - +// // cdb-command: dx niche_w_fields_3_niche1,d // cdb-check: niche_w_fields_3_niche1,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 12 [Type: unsigned char] - +// // cdb-command: dx niche_w_fields_3_niche2,d // cdb-check: niche_w_fields_3_niche2,d : C [Type: enum2$] // cdb-check: [+0x[...]] __0 : false [Type: bool] - +// // cdb-command: dx niche_w_fields_3_niche3,d // cdb-check: niche_w_fields_3_niche3,d : D [Type: enum2$] // cdb-check: [+0x[...]] __0 : 34 [Type: unsigned char] - +// // cdb-command: dx niche_w_fields_3_niche4,d // cdb-check: niche_w_fields_3_niche4,d : E [Type: enum2$] // cdb-check: [+0x[...]] __0 : 56 [Type: unsigned char] - +// // cdb-command: dx niche_w_fields_3_niche5,d // cdb-check: niche_w_fields_3_niche5,d : F [Type: enum2$] - +// // cdb-command: dx -r3 niche_w_fields_std_result_ok,d // cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box,alloc::alloc::Global>] // cdb-check: [+0x[...]] data_ptr : [...] // cdb-check: [+0x[...]] length : 3 [...] - +// // cdb-command: dx -r3 niche_w_fields_std_result_err,d // cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64] - +// // cdb-command: dx -r2 arbitrary_discr1,d // cdb-check: arbitrary_discr1,d : Abc [Type: enum2$] // cdb-check: [+0x[...]] __0 : 1234 [Type: unsigned int] - +// // cdb-command: dx -r2 arbitrary_discr2,d // cdb-check: arbitrary_discr2,d : Def [Type: enum2$] // cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int] - +#![feature(generic_nonzero)] #![feature(rustc_attrs)] #![feature(repr128)] #![feature(arbitrary_enum_discriminant)] -use std::num::{NonZeroI128, NonZeroU32}; +use std::num::NonZero; pub enum CStyleEnum { Low = 2, @@ -160,7 +160,7 @@ enum NicheLayoutWithFields1<'a> { } enum NicheLayoutWithFields2 { - A(NonZeroU32, u64), + A(NonZero, u64), B(u64), } @@ -210,8 +210,8 @@ fn main() { let j = CStyleEnum::High; let k = Some("IAMA optional string!".to_string()); let l = Result::::Ok(42); - let niche128_some = Some(NonZeroI128::new(123456).unwrap()); - let niche128_none: Option = None; + let niche128_some = NonZero::new(123456i128); + let niche128_none: Option> = None; let wrapping_niche128_untagged = unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) }; @@ -224,7 +224,7 @@ fn main() { let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7); let niche_w_fields_1_none = NicheLayoutWithFields1::B(99); - let niche_w_fields_2_some = NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900); + let niche_w_fields_2_some = NicheLayoutWithFields2::A(NonZero::new(800).unwrap(), 900); let niche_w_fields_2_none = NicheLayoutWithFields2::B(1000); let niche_w_fields_3_some = NicheLayoutWithFields3::A(137, true); diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index e3df1fbc5201..74c9e5e1dc3f 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -237,25 +237,25 @@ // lldb-command:print nz_usize // lldb-check:[...]$11 = 122 { __0 = 122 } - +#![feature(generic_nonzero)] use std::num::*; use std::sync::atomic::*; fn main() { - let nz_i8 = NonZeroI8::new(11).unwrap(); - let nz_i16 = NonZeroI16::new(22).unwrap(); - let nz_i32 = NonZeroI32::new(33).unwrap(); - let nz_i64 = NonZeroI64::new(44).unwrap(); - let nz_i128 = NonZeroI128::new(55).unwrap(); - let nz_isize = NonZeroIsize::new(66).unwrap(); + let nz_i8 = NonZero::new(11i8).unwrap(); + let nz_i16 = NonZero::new(22i16).unwrap(); + let nz_i32 = NonZero::new(33i32).unwrap(); + let nz_i64 = NonZero::new(44i64).unwrap(); + let nz_i128 = NonZero::new(55i128).unwrap(); + let nz_isize = NonZero::new(66isize).unwrap(); - let nz_u8 = NonZeroU8::new(77).unwrap(); - let nz_u16 = NonZeroU16::new(88).unwrap(); - let nz_u32 = NonZeroU32::new(99).unwrap(); - let nz_u64 = NonZeroU64::new(100).unwrap(); - let nz_u128 = NonZeroU128::new(111).unwrap(); - let nz_usize = NonZeroUsize::new(122).unwrap(); + let nz_u8 = NonZero::new(77u8).unwrap(); + let nz_u16 = NonZero::new(88u16).unwrap(); + let nz_u32 = NonZero::new(99u32).unwrap(); + let nz_u64 = NonZero::new(100u64).unwrap(); + let nz_u128 = NonZero::new(111u128).unwrap(); + let nz_usize = NonZero::new(122usize).unwrap(); let w_i8 = Wrapping(10i8); let w_i16 = Wrapping(20i16); diff --git a/tests/mir-opt/instsimplify/combine_transmutes.rs b/tests/mir-opt/instsimplify/combine_transmutes.rs index 7f45ebf2c863..3707ee17690d 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.rs +++ b/tests/mir-opt/instsimplify/combine_transmutes.rs @@ -1,9 +1,9 @@ //@ unit-test: InstSimplify //@ compile-flags: -C panic=abort - #![crate_type = "lib"] #![feature(core_intrinsics)] #![feature(custom_mir)] +#![feature(generic_nonzero)] use std::intrinsics::mir::*; use std::mem::{MaybeUninit, ManuallyDrop, transmute}; @@ -54,7 +54,7 @@ pub unsafe fn adt_transmutes() { // CHECK: as i32 (Transmute); // CHECK: ({{_.*}}.1: std::mem::ManuallyDrop); - let _a: u8 = transmute(Some(std::num::NonZeroU8::MAX)); + let _a: u8 = transmute(Some(std::num::NonZero::::MAX)); let _a: i16 = transmute(std::num::Wrapping(0_i16)); let _a: u16 = transmute(std::num::Wrapping(0_i16)); let _a: u32 = transmute(Union32 { i32: 0 }); diff --git a/tests/rustdoc/auxiliary/issue-106421-force-unstable.rs b/tests/rustdoc/auxiliary/issue-106421-force-unstable.rs new file mode 100644 index 000000000000..589d44c1f774 --- /dev/null +++ b/tests/rustdoc/auxiliary/issue-106421-force-unstable.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Zforce-unstable-if-unmarked +#![crate_name="foo"] +pub struct FatalError; + +impl FatalError { + pub fn raise(self) -> ! { + loop {} + } +} diff --git a/tests/rustdoc/issue-106421-not-internal.rs b/tests/rustdoc/issue-106421-not-internal.rs new file mode 100644 index 000000000000..1d744fba53f8 --- /dev/null +++ b/tests/rustdoc/issue-106421-not-internal.rs @@ -0,0 +1,8 @@ +//@ aux-build:issue-106421-force-unstable.rs +//@ ignore-cross-compile +// This is the version where a non-compiler-internal crate inlines a compiler-internal one. +// In this case, the item shouldn't be documented, because regular users can't get at it. +extern crate foo; + +// @!has issue_106421_not_internal/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +pub use foo::FatalError; diff --git a/tests/rustdoc/issue-106421.rs b/tests/rustdoc/issue-106421.rs new file mode 100644 index 000000000000..d4141a4ab0c7 --- /dev/null +++ b/tests/rustdoc/issue-106421.rs @@ -0,0 +1,8 @@ +//@ aux-build:issue-106421-force-unstable.rs +//@ ignore-cross-compile +//@ compile-flags: -Zforce-unstable-if-unmarked + +extern crate foo; + +// @has issue_106421/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise' +pub use foo::FatalError; diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc/type-layout.rs index 05f8e4dc9e9e..b2ff4add63e2 100644 --- a/tests/rustdoc/type-layout.rs +++ b/tests/rustdoc/type-layout.rs @@ -81,7 +81,7 @@ pub enum Variants { // @hasraw - 'Some: 4 bytes' pub enum WithNiche { None, - Some(std::num::NonZeroU32), + Some(std::num::NonZero), } // @hasraw type_layout/enum.Uninhabited.html 'Size: ' diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 911438e0d540..fcf31aa970cd 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -64,6 +64,7 @@ [csky] needs-llvm-components: csky */ #![feature(rustc_attrs, unsized_fn_params, transparent_unions)] +#![cfg_attr(host, feature(generic_nonzero))] #![cfg_attr(not(host), feature(no_core, lang_items), no_std, no_core)] #![allow(unused, improper_ctypes_definitions, internal_features)] @@ -74,7 +75,7 @@ #[cfg(host)] use std::{ - any::Any, marker::PhantomData, mem::ManuallyDrop, num::NonZeroI32, ptr::NonNull, rc::Rc, + any::Any, marker::PhantomData, mem::ManuallyDrop, num::NonZero, ptr::NonNull, rc::Rc, sync::Arc, }; @@ -145,7 +146,7 @@ mod prelude { #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] - pub struct NonZeroI32(i32); + pub struct NonZero(T); // This just stands in for a non-trivial type. pub struct Vec { @@ -274,7 +275,7 @@ test_abi_compatible!(isize_int, isize, i64); test_abi_compatible!(zst_unit, Zst, ()); #[cfg(not(any(target_arch = "sparc64")))] test_abi_compatible!(zst_array, Zst, [u8; 0]); -test_abi_compatible!(nonzero_int, NonZeroI32, i32); +test_abi_compatible!(nonzero_int, NonZero, i32); // `DispatchFromDyn` relies on ABI compatibility. // This is interesting since these types are not `repr(transparent)`. So this is not part of our @@ -381,6 +382,6 @@ test_nonnull!(mut_unsized, &mut [i32]); test_nonnull!(fn_, fn()); test_nonnull!(nonnull, NonNull); test_nonnull!(nonnull_unsized, NonNull); -test_nonnull!(non_zero, NonZeroI32); +test_nonnull!(non_zero, NonZero); fn main() {} diff --git a/tests/ui/associated-type-bounds/implied-bounds-cycle.rs b/tests/ui/associated-type-bounds/implied-bounds-cycle.rs new file mode 100644 index 000000000000..785d47d47914 --- /dev/null +++ b/tests/ui/associated-type-bounds/implied-bounds-cycle.rs @@ -0,0 +1,10 @@ +#![feature(associated_type_bounds)] + +trait A { + type T; +} + +trait B: A {} +//~^ ERROR cycle detected when computing the implied predicates of `B` + +fn main() {} diff --git a/tests/ui/associated-type-bounds/implied-bounds-cycle.stderr b/tests/ui/associated-type-bounds/implied-bounds-cycle.stderr new file mode 100644 index 000000000000..1c1c64ea5f5e --- /dev/null +++ b/tests/ui/associated-type-bounds/implied-bounds-cycle.stderr @@ -0,0 +1,17 @@ +error[E0391]: cycle detected when computing the implied predicates of `B` + --> $DIR/implied-bounds-cycle.rs:7:15 + | +LL | trait B: A {} + | ^ + | + = note: ...which immediately requires computing the implied predicates of `B` again +note: cycle used when computing normalized predicates of `B` + --> $DIR/implied-bounds-cycle.rs:7:1 + | +LL | trait B: A {} + | ^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/async-await/async-assoc-fn-anon-lifetimes.rs b/tests/ui/async-await/async-assoc-fn-anon-lifetimes.rs index 28705bfc0c8f..1a2aae8fb23a 100644 --- a/tests/ui/async-await/async-assoc-fn-anon-lifetimes.rs +++ b/tests/ui/async-await/async-assoc-fn-anon-lifetimes.rs @@ -5,6 +5,8 @@ //@ edition:2018 +#![allow(non_local_definitions)] + struct A<'a, 'b>(&'a &'b i32); struct B<'a>(&'a i32); diff --git a/tests/ui/cfg/cfg-target-abi.rs b/tests/ui/cfg/cfg-target-abi.rs index 5d13337c1c30..306ae077325b 100644 --- a/tests/ui/cfg/cfg-target-abi.rs +++ b/tests/ui/cfg/cfg-target-abi.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(cfg_target_abi)] #[cfg(target_abi = "eabihf")] pub fn main() { diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs index 0c55e35a993f..859a36c604c6 100644 --- a/tests/ui/check-cfg/well-known-values.rs +++ b/tests/ui/check-cfg/well-known-values.rs @@ -10,7 +10,6 @@ #![feature(cfg_overflow_checks)] #![feature(cfg_relocation_model)] #![feature(cfg_sanitize)] -#![feature(cfg_target_abi)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_target_thread_local)] diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 6535cd9a1a1f..5f52421fef5b 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:26:5 + --> $DIR/well-known-values.rs:25:5 | LL | clippy = "_UNEXPECTED_VALUE", | ^^^^^^---------------------- @@ -11,7 +11,7 @@ LL | clippy = "_UNEXPECTED_VALUE", = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:28:5 + --> $DIR/well-known-values.rs:27:5 | LL | debug_assertions = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^---------------------- @@ -22,7 +22,7 @@ LL | debug_assertions = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:30:5 + --> $DIR/well-known-values.rs:29:5 | LL | doc = "_UNEXPECTED_VALUE", | ^^^---------------------- @@ -33,7 +33,7 @@ LL | doc = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:32:5 + --> $DIR/well-known-values.rs:31:5 | LL | doctest = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -44,7 +44,7 @@ LL | doctest = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:34:5 + --> $DIR/well-known-values.rs:33:5 | LL | miri = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -55,7 +55,7 @@ LL | miri = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:36:5 + --> $DIR/well-known-values.rs:35:5 | LL | overflow_checks = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^---------------------- @@ -66,7 +66,7 @@ LL | overflow_checks = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:38:5 + --> $DIR/well-known-values.rs:37:5 | LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | panic = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:40:5 + --> $DIR/well-known-values.rs:39:5 | LL | proc_macro = "_UNEXPECTED_VALUE", | ^^^^^^^^^^---------------------- @@ -86,7 +86,7 @@ LL | proc_macro = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:42:5 + --> $DIR/well-known-values.rs:41:5 | LL | relocation_model = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | relocation_model = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:44:5 + --> $DIR/well-known-values.rs:43:5 | LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | sanitize = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:46:5 + --> $DIR/well-known-values.rs:45:5 | LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | target_abi = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:48:5 + --> $DIR/well-known-values.rs:47:5 | LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | target_arch = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:50:5 + --> $DIR/well-known-values.rs:49:5 | LL | target_endian = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,16 +131,16 @@ LL | target_endian = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:52:5 + --> $DIR/well-known-values.rs:51:5 | LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `eabihf`, `gnu`, `gnueabihf`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:54:5 + --> $DIR/well-known-values.rs:53:5 | LL | target_family = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | target_family = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:56:5 + --> $DIR/well-known-values.rs:55:5 | LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL | target_feature = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:58:5 + --> $DIR/well-known-values.rs:57:5 | LL | target_has_atomic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | target_has_atomic = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:60:5 + --> $DIR/well-known-values.rs:59:5 | LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:62:5 + --> $DIR/well-known-values.rs:61:5 | LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:64:5 + --> $DIR/well-known-values.rs:63:5 | LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | target_os = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:66:5 + --> $DIR/well-known-values.rs:65:5 | LL | target_pointer_width = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | target_pointer_width = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:68:5 + --> $DIR/well-known-values.rs:67:5 | LL | target_thread_local = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^---------------------- @@ -214,7 +214,7 @@ LL | target_thread_local = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:70:5 + --> $DIR/well-known-values.rs:69:5 | LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | target_vendor = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:72:5 + --> $DIR/well-known-values.rs:71:5 | LL | test = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -234,7 +234,7 @@ LL | test = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:74:5 + --> $DIR/well-known-values.rs:73:5 | LL | unix = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -245,7 +245,7 @@ LL | unix = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:76:5 + --> $DIR/well-known-values.rs:75:5 | LL | windows = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -256,7 +256,7 @@ LL | windows = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `linuz` - --> $DIR/well-known-values.rs:82:7 + --> $DIR/well-known-values.rs:81:7 | LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | ^^^^^^^^^^^^------- diff --git a/tests/ui/const-generics/min_const_generics/macro.rs b/tests/ui/const-generics/min_const_generics/macro.rs index b7e8083a8619..52f47628f8f1 100644 --- a/tests/ui/const-generics/min_const_generics/macro.rs +++ b/tests/ui/const-generics/min_const_generics/macro.rs @@ -1,4 +1,6 @@ //@ run-pass +#![allow(non_local_definitions)] + struct Example; macro_rules! external_macro { diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 57815e6af65c..c06c30741164 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:22:1 + --> $DIR/raw-bytes.rs:21:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:30:1 + --> $DIR/raw-bytes.rs:29:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:44:1 + --> $DIR/raw-bytes.rs:43:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:46:1 + --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:52:1 + --> $DIR/raw-bytes.rs:51:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:57:1 + --> $DIR/raw-bytes.rs:56:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,10 +65,10 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:60:1 + --> $DIR/raw-bytes.rs:59:1 | -LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -76,10 +76,10 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:62:1 + --> $DIR/raw-bytes.rs:61:1 | -LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:68:1 + --> $DIR/raw-bytes.rs:67:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:74:1 + --> $DIR/raw-bytes.rs:73:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:77:1 + --> $DIR/raw-bytes.rs:76:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:85:1 + --> $DIR/raw-bytes.rs:84:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:89:1 + --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:93:1 + --> $DIR/raw-bytes.rs:92:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:96:1 + --> $DIR/raw-bytes.rs:95:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:99:1 + --> $DIR/raw-bytes.rs:98:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:102:1 + --> $DIR/raw-bytes.rs:101:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:105:1 + --> $DIR/raw-bytes.rs:104:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:107:1 + --> $DIR/raw-bytes.rs:106:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:109:1 + --> $DIR/raw-bytes.rs:108:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:115:1 + --> $DIR/raw-bytes.rs:114:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:140:1 + --> $DIR/raw-bytes.rs:139:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:142:1 + --> $DIR/raw-bytes.rs:141:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:144:1 + --> $DIR/raw-bytes.rs:143:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:147:1 + --> $DIR/raw-bytes.rs:146:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:149:1 + --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:151:1 + --> $DIR/raw-bytes.rs:150:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:155:1 + --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:157:1 + --> $DIR/raw-bytes.rs:156:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:160:1 + --> $DIR/raw-bytes.rs:159:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:163:1 + --> $DIR/raw-bytes.rs:162:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:163:40 + --> $DIR/raw-bytes.rs:162:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:169:1 + --> $DIR/raw-bytes.rs:168:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:169:42 + --> $DIR/raw-bytes.rs:168:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:173:1 + --> $DIR/raw-bytes.rs:172:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:173:42 + --> $DIR/raw-bytes.rs:172:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:178:1 + --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:182:1 + --> $DIR/raw-bytes.rs:181:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:186:1 + --> $DIR/raw-bytes.rs:185:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:189:1 + --> $DIR/raw-bytes.rs:188:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:193:1 + --> $DIR/raw-bytes.rs:192:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:197:1 + --> $DIR/raw-bytes.rs:196:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:199:1 + --> $DIR/raw-bytes.rs:198:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer @@ -459,7 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:203:1 + --> $DIR/raw-bytes.rs:202:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -470,7 +470,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:204:1 + --> $DIR/raw-bytes.rs:203:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -481,7 +481,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:205:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -492,7 +492,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:209:1 + --> $DIR/raw-bytes.rs:208:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -503,7 +503,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 + --> $DIR/raw-bytes.rs:211:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -516,7 +516,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 + --> $DIR/raw-bytes.rs:214:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean @@ -527,7 +527,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:219:1 + --> $DIR/raw-bytes.rs:218:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer @@ -538,7 +538,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:226:1 + --> $DIR/raw-bytes.rs:225:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -549,7 +549,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:231:1 + --> $DIR/raw-bytes.rs:230:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -562,7 +562,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:236:1 + --> $DIR/raw-bytes.rs:235:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index c875d91ccb87..0589280524ca 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:22:1 + --> $DIR/raw-bytes.rs:21:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:30:1 + --> $DIR/raw-bytes.rs:29:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:44:1 + --> $DIR/raw-bytes.rs:43:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:46:1 + --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:52:1 + --> $DIR/raw-bytes.rs:51:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:57:1 + --> $DIR/raw-bytes.rs:56:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,10 +65,10 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:60:1 + --> $DIR/raw-bytes.rs:59:1 | -LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -76,10 +76,10 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:62:1 + --> $DIR/raw-bytes.rs:61:1 | -LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:68:1 + --> $DIR/raw-bytes.rs:67:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:74:1 + --> $DIR/raw-bytes.rs:73:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:77:1 + --> $DIR/raw-bytes.rs:76:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:85:1 + --> $DIR/raw-bytes.rs:84:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:89:1 + --> $DIR/raw-bytes.rs:88:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:93:1 + --> $DIR/raw-bytes.rs:92:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:96:1 + --> $DIR/raw-bytes.rs:95:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:99:1 + --> $DIR/raw-bytes.rs:98:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:102:1 + --> $DIR/raw-bytes.rs:101:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:105:1 + --> $DIR/raw-bytes.rs:104:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:107:1 + --> $DIR/raw-bytes.rs:106:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:109:1 + --> $DIR/raw-bytes.rs:108:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:115:1 + --> $DIR/raw-bytes.rs:114:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:140:1 + --> $DIR/raw-bytes.rs:139:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:142:1 + --> $DIR/raw-bytes.rs:141:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:144:1 + --> $DIR/raw-bytes.rs:143:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:147:1 + --> $DIR/raw-bytes.rs:146:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:149:1 + --> $DIR/raw-bytes.rs:148:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:151:1 + --> $DIR/raw-bytes.rs:150:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:155:1 + --> $DIR/raw-bytes.rs:154:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:157:1 + --> $DIR/raw-bytes.rs:156:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:160:1 + --> $DIR/raw-bytes.rs:159:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:163:1 + --> $DIR/raw-bytes.rs:162:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:163:40 + --> $DIR/raw-bytes.rs:162:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:169:1 + --> $DIR/raw-bytes.rs:168:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:169:42 + --> $DIR/raw-bytes.rs:168:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:173:1 + --> $DIR/raw-bytes.rs:172:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:173:42 + --> $DIR/raw-bytes.rs:172:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:178:1 + --> $DIR/raw-bytes.rs:177:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:182:1 + --> $DIR/raw-bytes.rs:181:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:186:1 + --> $DIR/raw-bytes.rs:185:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:189:1 + --> $DIR/raw-bytes.rs:188:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:193:1 + --> $DIR/raw-bytes.rs:192:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:197:1 + --> $DIR/raw-bytes.rs:196:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:199:1 + --> $DIR/raw-bytes.rs:198:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer @@ -459,7 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:203:1 + --> $DIR/raw-bytes.rs:202:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -470,7 +470,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:204:1 + --> $DIR/raw-bytes.rs:203:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -481,7 +481,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:205:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -492,7 +492,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:209:1 + --> $DIR/raw-bytes.rs:208:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -503,7 +503,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 + --> $DIR/raw-bytes.rs:211:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -516,7 +516,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 + --> $DIR/raw-bytes.rs:214:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean @@ -527,7 +527,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:219:1 + --> $DIR/raw-bytes.rs:218:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer @@ -538,7 +538,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:226:1 + --> $DIR/raw-bytes.rs:225:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -549,7 +549,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:231:1 + --> $DIR/raw-bytes.rs:230:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -562,7 +562,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:236:1 + --> $DIR/raw-bytes.rs:235:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 96903b322e45..e5dfd5ca2939 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -2,14 +2,13 @@ //@ ignore-endian-big // ignore-tidy-linelength //@ normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼" -> "╾ALLOC_ID$1╼" - -#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] #![allow(invalid_value)] +#![feature(generic_nonzero, never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] use std::mem; use std::alloc::Layout; use std::ptr::NonNull; -use std::num::{NonZeroU8, NonZeroUsize}; +use std::num::NonZero; use std::slice::{from_ptr_range, from_raw_parts}; // # Bad enums and chars @@ -57,9 +56,9 @@ const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value -const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; +const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; //~^ ERROR it is undefined behavior to use this value -const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; +const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value #[rustc_layout_scalar_valid_range_start(10)] diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index 229ce9a7df38..76bd5248ffd8 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -1,12 +1,12 @@ // Strip out raw byte dumps to make comparison platform-independent: //@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(rustc_attrs, ptr_metadata)] #![allow(invalid_value)] // make sure we cannot allow away the errors tested here +#![feature(generic_nonzero, rustc_attrs, ptr_metadata)] use std::mem; use std::ptr::NonNull; -use std::num::{NonZeroU8, NonZeroUsize}; +use std::num::NonZero; const NON_NULL: NonNull = unsafe { mem::transmute(1usize) }; const NON_NULL_PTR: NonNull = unsafe { mem::transmute(&1) }; @@ -21,9 +21,9 @@ const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { mem::transmute(out_of_bounds_ptr) } }; -const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; +const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; //~^ ERROR it is undefined behavior to use this value -const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; +const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value #[repr(C)] @@ -31,7 +31,7 @@ union MaybeUninit { uninit: (), init: T, } -const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; +const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR evaluation of constant value failed //~| uninitialized diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 7822306b654c..70b961fe1cd4 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -18,8 +18,8 @@ LL | let out_of_bounds_ptr = &ptr[255]; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 | -LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -29,8 +29,8 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:26:1 | -LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 +LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -38,10 +38,10 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: evaluation of constant value failed - --> $DIR/ub-nonnull.rs:34:36 + --> $DIR/ub-nonnull.rs:34:38 | -LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:43:1 diff --git a/tests/ui/consts/const-eval/valid-const.rs b/tests/ui/consts/const-eval/valid-const.rs index 1c8c048ae28c..15d3e8834565 100644 --- a/tests/ui/consts/const-eval/valid-const.rs +++ b/tests/ui/consts/const-eval/valid-const.rs @@ -1,16 +1,17 @@ //@ check-pass - +// // Some constants that *are* valid +#![feature(generic_nonzero)] use std::mem; use std::ptr::NonNull; -use std::num::{NonZeroU8, NonZeroUsize}; +use std::num::NonZero; const NON_NULL_PTR1: NonNull = unsafe { mem::transmute(1usize) }; const NON_NULL_PTR2: NonNull = unsafe { mem::transmute(&0) }; -const NON_NULL_U8: NonZeroU8 = unsafe { mem::transmute(1u8) }; -const NON_NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(1usize) }; +const NON_NULL_U8: NonZero = unsafe { mem::transmute(1u8) }; +const NON_NULL_USIZE: NonZero = unsafe { mem::transmute(1usize) }; const UNIT: () = (); diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs index 09142c561574..31d3b6e73312 100644 --- a/tests/ui/consts/const_in_pattern/accept_structural.rs +++ b/tests/ui/consts/const_in_pattern/accept_structural.rs @@ -1,5 +1,6 @@ //@ run-pass +#![allow(non_local_definitions)] #![warn(indirect_structural_match)] // This test is checking our logic for structural match checking by enumerating diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs index 048fca762d5a..62efce648761 100644 --- a/tests/ui/consts/const_in_pattern/issue-65466.rs +++ b/tests/ui/consts/const_in_pattern/issue-65466.rs @@ -1,7 +1,3 @@ -#![deny(indirect_structural_match)] - -//@ check-pass - #[derive(PartialEq, Eq)] enum O { Some(*const T), // Can also use PhantomData @@ -15,8 +11,7 @@ const C: &[O] = &[O::None]; fn main() { let x = O::None; match &[x][..] { - C => (), //~WARN: the type must implement `PartialEq` - //~| previously accepted + C => (), //~ERROR: the type must implement `PartialEq` _ => (), } } diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr index 9c80cb3a849c..7d5e5b5b0c64 100644 --- a/tests/ui/consts/const_in_pattern/issue-65466.stderr +++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr @@ -1,23 +1,8 @@ -warning: to use a constant of type `&[O]` in a pattern, the type must implement `PartialEq` - --> $DIR/issue-65466.rs:18:9 +error: to use a constant of type `&[O]` in a pattern, the type must implement `PartialEq` + --> $DIR/issue-65466.rs:14:9 | LL | C => (), | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116122 - = note: `#[warn(const_patterns_without_partial_eq)]` on by default -warning: 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -warning: to use a constant of type `&[O]` in a pattern, the type must implement `PartialEq` - --> $DIR/issue-65466.rs:18:9 - | -LL | C => (), - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116122 - = note: `#[warn(const_patterns_without_partial_eq)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/consts/ice-48279.rs b/tests/ui/consts/ice-48279.rs index 5316974b80ad..a4f687a3e9ce 100644 --- a/tests/ui/consts/ice-48279.rs +++ b/tests/ui/consts/ice-48279.rs @@ -15,7 +15,7 @@ impl NonZeroU32 { } } -//pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(7) }; +// pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(7) }; pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32 { value: 7 } }; fn main() { diff --git a/tests/ui/consts/tuple-struct-constructors.rs b/tests/ui/consts/tuple-struct-constructors.rs index 8472a09844bb..d2f25aeec9b1 100644 --- a/tests/ui/consts/tuple-struct-constructors.rs +++ b/tests/ui/consts/tuple-struct-constructors.rs @@ -1,10 +1,11 @@ //@ run-pass - +// // https://github.com/rust-lang/rust/issues/41898 +#![feature(generic_nonzero)] -use std::num::NonZeroU64; +use std::num::NonZero; fn main() { - const FOO: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(2) }; + const FOO: NonZero = unsafe { NonZero::new_unchecked(2) }; if let FOO = FOO {} } diff --git a/tests/ui/drop/dropck-eyepatch-reorder.rs b/tests/ui/drop/dropck-eyepatch-reorder.rs index 6b394414baec..b985beee9ec9 100644 --- a/tests/ui/drop/dropck-eyepatch-reorder.rs +++ b/tests/ui/drop/dropck-eyepatch-reorder.rs @@ -1,5 +1,6 @@ //@ run-pass #![feature(dropck_eyepatch)] +#![allow(non_local_definitions)] // The point of this test is to test uses of `#[may_dangle]` attribute // where the formal declaration order (in the impl generics) does not diff --git a/tests/ui/drop/dropck-eyepatch.rs b/tests/ui/drop/dropck-eyepatch.rs index 2f27b72da5a6..2dffe6aba176 100644 --- a/tests/ui/drop/dropck-eyepatch.rs +++ b/tests/ui/drop/dropck-eyepatch.rs @@ -1,5 +1,6 @@ //@ run-pass #![feature(dropck_eyepatch)] +#![allow(non_local_definitions)] // The point of this test is to illustrate that the `#[may_dangle]` // attribute specifically allows, in the context of a type diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs b/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs deleted file mode 100644 index d005dc3ad456..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg(target_abi = "x")] //~ ERROR `cfg(target_abi)` is experimental -struct Foo(u64, u64); - -#[cfg_attr(target_abi = "x", x)] //~ ERROR `cfg(target_abi)` is experimental -struct Bar(u64, u64); - -#[cfg(not(any(all(target_abi = "x"))))] //~ ERROR `cfg(target_abi)` is experimental -fn foo() {} - -fn main() { - cfg!(target_abi = "x"); - //~^ ERROR `cfg(target_abi)` is experimental and subject to change -} diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr b/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr deleted file mode 100644 index 4829f8572cc5..000000000000 --- a/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: `cfg(target_abi)` is experimental and subject to change - --> $DIR/feature-gate-cfg-target-abi.rs:1:7 - | -LL | #[cfg(target_abi = "x")] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #80970 for more information - = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(target_abi)` is experimental and subject to change - --> $DIR/feature-gate-cfg-target-abi.rs:4:12 - | -LL | #[cfg_attr(target_abi = "x", x)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #80970 for more information - = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(target_abi)` is experimental and subject to change - --> $DIR/feature-gate-cfg-target-abi.rs:7:19 - | -LL | #[cfg(not(any(all(target_abi = "x"))))] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #80970 for more information - = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(target_abi)` is experimental and subject to change - --> $DIR/feature-gate-cfg-target-abi.rs:11:10 - | -LL | cfg!(target_abi = "x"); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #80970 for more information - = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/imports/local-modularized-tricky-pass-2.rs b/tests/ui/imports/local-modularized-tricky-pass-2.rs index 581bab467f56..1cf97c5aa06e 100644 --- a/tests/ui/imports/local-modularized-tricky-pass-2.rs +++ b/tests/ui/imports/local-modularized-tricky-pass-2.rs @@ -4,6 +4,7 @@ // into the root module soon enough to act as usual items and shadow globs and preludes. #![feature(decl_macro)] +#![allow(non_local_definitions)] // `macro_export` shadows globs use inner1::*; diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs index 2420aec50588..fb3b0652ddbf 100644 --- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -4,11 +4,11 @@ // ignore-tidy-linelength //@ ignore-emscripten spawning processes is not supported //@ ignore-sgx no processes - +// // This test checks panic emitted from `mem::{uninitialized,zeroed}`. - -#![feature(never_type)] #![allow(deprecated, invalid_value)] +#![feature(generic_nonzero)] +#![feature(never_type)] use std::{ mem::{self, MaybeUninit, ManuallyDrop}, @@ -29,7 +29,7 @@ enum OneVariant { Variant(i32) } #[allow(dead_code, non_camel_case_types)] enum OneVariant_NonZero { - Variant(i32, i32, num::NonZeroI32), + Variant(i32, i32, num::NonZero), DeadVariant(Bar), } @@ -55,8 +55,8 @@ enum LR { } #[allow(dead_code, non_camel_case_types)] enum LR_NonZero { - Left(num::NonZeroI64), - Right(num::NonZeroI64), + Left(num::NonZero), + Right(num::NonZero), } struct ZeroSized; diff --git a/tests/ui/issues/issue-31776.rs b/tests/ui/issues/issue-31776.rs index 632defbcf273..4b342a0e3b2d 100644 --- a/tests/ui/issues/issue-31776.rs +++ b/tests/ui/issues/issue-31776.rs @@ -1,6 +1,7 @@ //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] +#![allow(non_local_definitions)] // Various scenarios in which `pub` is required in blocks struct S; diff --git a/tests/ui/issues/issue-41053.rs b/tests/ui/issues/issue-41053.rs index f46bf6b4aa16..18f9e209c33b 100644 --- a/tests/ui/issues/issue-41053.rs +++ b/tests/ui/issues/issue-41053.rs @@ -1,6 +1,8 @@ //@ run-pass //@ aux-build:issue-41053.rs +#![allow(non_local_definitions)] + pub trait Trait { fn foo(&self) {} } pub struct Foo; diff --git a/tests/ui/issues/issue-64593.rs b/tests/ui/issues/issue-64593.rs index e55353810067..091c3a2f316d 100644 --- a/tests/ui/issues/issue-64593.rs +++ b/tests/ui/issues/issue-64593.rs @@ -1,7 +1,8 @@ //@ check-pass #![deny(improper_ctypes)] +#![feature(generic_nonzero)] -pub struct Error(std::num::NonZeroU32); +pub struct Error(std::num::NonZero); extern "Rust" { fn foo(dest: &mut [u8]) -> Result<(), Error>; diff --git a/tests/ui/layout/unsafe-cell-hides-niche.rs b/tests/ui/layout/unsafe-cell-hides-niche.rs index b3158839de0d..568eb819be2e 100644 --- a/tests/ui/layout/unsafe-cell-hides-niche.rs +++ b/tests/ui/layout/unsafe-cell-hides-niche.rs @@ -1,17 +1,17 @@ // For rust-lang/rust#68303: the contents of `UnsafeCell` cannot // participate in the niche-optimization for enum discriminants. This -// test checks that an `Option>` has the same +// test checks that an `Option>>` has the same // size in memory as an `Option>` (namely, 8 bytes). - +// //@ check-pass //@ compile-flags: --crate-type=lib //@ only-x86 - +#![feature(generic_nonzero)] #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; -use std::num::NonZeroU32 as N32; +use std::num::NonZero; use std::sync::{Mutex, RwLock}; struct Wrapper(#[allow(dead_code)] T); @@ -54,15 +54,17 @@ macro_rules! check_sizes { const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -check_sizes!(Wrapper: 4 => 8); -check_sizes!(Wrapper: 4 => 4); // (✓ niche opt) -check_sizes!(Transparent: 4 => 8); -check_sizes!(Transparent: 4 => 4); // (✓ niche opt) -check_sizes!(NoNiche: 4 => 8); -check_sizes!(NoNiche: 4 => 8); +check_sizes!(Wrapper: 4 => 8); +check_sizes!(Wrapper>: 4 => 4); // (✓ niche opt) -check_sizes!(UnsafeCell: 4 => 8); -check_sizes!(UnsafeCell: 4 => 8); +check_sizes!(Transparent: 4 => 8); +check_sizes!(Transparent>: 4 => 4); // (✓ niche opt) + +check_sizes!(NoNiche: 4 => 8); +check_sizes!(NoNiche>: 4 => 8); + +check_sizes!(UnsafeCell: 4 => 8); +check_sizes!(UnsafeCell>: 4 => 8); check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); @@ -79,4 +81,4 @@ check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -check_sizes!(UnsafeCell>: 16 => 32); +check_sizes!(UnsafeCell>>: 16 => 32); diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs index 095afc4337a5..058f59234878 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.rs +++ b/tests/ui/layout/zero-sized-array-enum-niche.rs @@ -1,6 +1,7 @@ //@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" -#![feature(rustc_attrs)] #![crate_type = "lib"] +#![feature(generic_nonzero)] +#![feature(rustc_attrs)] // Various tests around the behavior of zero-sized arrays and // enum niches, especially that they have coherent size and alignment. @@ -34,7 +35,7 @@ enum MultipleAlignments { //~ ERROR: layout_of struct Packed(T); #[rustc_layout(debug)] -type NicheLosesToTagged = Result<[u32; 0], Packed>; //~ ERROR: layout_of +type NicheLosesToTagged = Result<[u32; 0], Packed>>; //~ ERROR: layout_of // Should get tag_encoding: Direct, size == align == 4. #[repr(u16)] diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 0ed743818c57..af049125de46 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -98,7 +98,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:13:1 + --> $DIR/zero-sized-array-enum-niche.rs:14:1 | LL | type AlignedResult = Result<[u32; 0], bool>; | ^^^^^^^^^^^^^^^^^^ @@ -227,7 +227,7 @@ error: layout_of(MultipleAlignments) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:21:1 + --> $DIR/zero-sized-array-enum-niche.rs:22:1 | LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -332,9 +332,9 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:37:1 + --> $DIR/zero-sized-array-enum-niche.rs:38:1 | -LL | type NicheLosesToTagged = Result<[u32; 0], Packed>; +LL | type NicheLosesToTagged = Result<[u32; 0], Packed>>; | ^^^^^^^^^^^^^^^^^^^^^^^ error: layout_of(Result<[u32; 0], Packed>) = Layout { @@ -441,7 +441,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } - --> $DIR/zero-sized-array-enum-niche.rs:44:1 + --> $DIR/zero-sized-array-enum-niche.rs:45:1 | LL | type NicheWinsOverTagged = Result<[u32; 0], Packed>; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/auxiliary/non_local_macro.rs b/tests/ui/lint/auxiliary/non_local_macro.rs new file mode 100644 index 000000000000..8c0ff8adda1b --- /dev/null +++ b/tests/ui/lint/auxiliary/non_local_macro.rs @@ -0,0 +1,26 @@ +#[macro_export] +macro_rules! non_local_impl { + ($a:ident) => { + const _IMPL_DEBUG: () = { + impl ::std::fmt::Debug for $a { + fn fmt(&self, _: &mut ::std::fmt::Formatter<'_>) + -> ::std::result::Result<(), ::std::fmt::Error> + { + todo!() + } + } + }; + } +} + +#[macro_export] +macro_rules! non_local_macro_rules { + ($a:ident) => { + const _MACRO_EXPORT: () = { + #[macro_export] + macro_rules! $a { + () => {} + } + }; + } +} diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index ce027c825545..cb63af0ea422 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -2,6 +2,7 @@ //@ aux-build:external_extern_fn.rs #![crate_type = "lib"] #![warn(clashing_extern_declarations)] +#![feature(generic_nonzero)] mod redeclared_different_signature { mod a { @@ -265,7 +266,7 @@ mod missing_return_type { mod non_zero_and_non_null { mod a { extern "C" { - fn non_zero_usize() -> core::num::NonZeroUsize; + fn non_zero_usize() -> core::num::NonZero; fn non_null_ptr() -> core::ptr::NonNull; } } @@ -285,36 +286,33 @@ mod non_zero_and_non_null { // See #75739 mod non_zero_transparent { mod a1 { - use std::num::NonZeroUsize; extern "C" { - fn f1() -> NonZeroUsize; + fn f1() -> std::num::NonZero; } } mod b1 { #[repr(transparent)] - struct X(NonZeroUsize); - use std::num::NonZeroUsize; + struct X(std::num::NonZero); + extern "C" { fn f1() -> X; } } mod a2 { - use std::num::NonZeroUsize; extern "C" { - fn f2() -> NonZeroUsize; + fn f2() -> std::num::NonZero; } } mod b2 { #[repr(transparent)] - struct X1(NonZeroUsize); + struct X1(std::num::NonZero); #[repr(transparent)] struct X(X1); - use std::num::NonZeroUsize; extern "C" { // Same case as above, but with two layers of newtyping. fn f2() -> X; @@ -325,7 +323,6 @@ mod non_zero_transparent { #[repr(transparent)] struct X(core::ptr::NonNull); - use std::num::NonZeroUsize; extern "C" { fn f3() -> X; } @@ -340,7 +337,7 @@ mod non_zero_transparent { mod a4 { #[repr(transparent)] enum E { - X(std::num::NonZeroUsize), + X(std::num::NonZero), } extern "C" { fn f4() -> E; @@ -349,7 +346,7 @@ mod non_zero_transparent { mod b4 { extern "C" { - fn f4() -> std::num::NonZeroUsize; + fn f4() -> std::num::NonZero; } } } @@ -369,8 +366,8 @@ mod null_optimised_enums { extern "C" { // This should be allowed, because these conversions are guaranteed to be FFI-safe (see // #60300) - fn option_non_zero_usize() -> Option; - fn option_non_zero_isize() -> Option; + fn option_non_zero_usize() -> Option>; + fn option_non_zero_isize() -> Option>; fn option_non_null_ptr() -> Option>; // However, these should be incorrect (note isize instead of usize) @@ -415,16 +412,16 @@ mod hidden_niche { } mod b { use std::cell::UnsafeCell; - use std::num::NonZeroUsize; + use std::num::NonZero; #[repr(transparent)] struct Transparent { - x: NonZeroUsize, + x: NonZero, } #[repr(transparent)] struct TransparentNoNiche { - y: UnsafeCell, + y: UnsafeCell>, } extern "C" { @@ -434,7 +431,7 @@ mod hidden_niche { //~^ WARN redeclared with a different signature //~| WARN block uses type `Option`, which is not FFI-safe - fn hidden_niche_unsafe_cell() -> Option>; + fn hidden_niche_unsafe_cell() -> Option>>; //~^ WARN redeclared with a different signature //~| WARN block uses type `Option>>`, which is not FFI-safe } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 5b9244b69931..86ee789aeb22 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:433:55 + --> $DIR/clashing-extern-fn.rs:430:55 | LL | fn hidden_niche_transparent_no_niche() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -9,16 +9,16 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:437:46 + --> $DIR/clashing-extern-fn.rs:434:46 | -LL | fn hidden_niche_unsafe_cell() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn hidden_niche_unsafe_cell() -> Option>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint warning: `clash` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:14:13 + --> $DIR/clashing-extern-fn.rs:15:13 | LL | fn clash(x: u8); | --------------- `clash` previously declared here @@ -35,7 +35,7 @@ LL | #![warn(clashing_extern_declarations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:52:9 + --> $DIR/clashing-extern-fn.rs:53:9 | LL | #[link_name = "extern_link_name"] | --------------------------------- `extern_link_name` previously declared here @@ -47,7 +47,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:55:9 + --> $DIR/clashing-extern-fn.rs:56:9 | LL | fn some_other_new_name(x: i16); | ------------------------------ `some_other_new_name` previously declared here @@ -59,7 +59,7 @@ LL | #[link_name = "some_other_new_name"] found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:59:9 + --> $DIR/clashing-extern-fn.rs:60:9 | LL | #[link_name = "link_name_same"] | ------------------------------- `link_name_same` previously declared here @@ -71,7 +71,7 @@ LL | #[link_name = "link_name_same"] found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:72:9 + --> $DIR/clashing-extern-fn.rs:73:9 | LL | fn different_mod(x: u8); | ----------------------- `different_mod` previously declared here @@ -83,7 +83,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:82:9 + --> $DIR/clashing-extern-fn.rs:83:9 | LL | fn variadic_decl(x: u8, ...); | ---------------------------- `variadic_decl` previously declared here @@ -95,7 +95,7 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:142:13 + --> $DIR/clashing-extern-fn.rs:143:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | -------------------------------------------- `weigh_banana` previously declared here @@ -107,7 +107,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64; found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:171:13 + --> $DIR/clashing-extern-fn.rs:172:13 | LL | fn draw_point(p: Point); | ----------------------- `draw_point` previously declared here @@ -119,7 +119,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:197:13 + --> $DIR/clashing-extern-fn.rs:198:13 | LL | fn origin() -> Point3; | --------------------- `origin` previously declared here @@ -131,7 +131,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:220:13 + --> $DIR/clashing-extern-fn.rs:221:13 | LL | fn transparent_incorrect() -> T; | ------------------------------- `transparent_incorrect` previously declared here @@ -143,7 +143,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:259:13 + --> $DIR/clashing-extern-fn.rs:260:13 | LL | fn missing_return_type() -> usize; | --------------------------------- `missing_return_type` previously declared here @@ -155,10 +155,10 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:277:13 + --> $DIR/clashing-extern-fn.rs:278:13 | -LL | fn non_zero_usize() -> core::num::NonZeroUsize; - | ---------------------------------------------- `non_zero_usize` previously declared here +LL | fn non_zero_usize() -> core::num::NonZero; + | ------------------------------------------------ `non_zero_usize` previously declared here ... LL | fn non_zero_usize() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration @@ -167,7 +167,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:279:13 + --> $DIR/clashing-extern-fn.rs:280:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ---------------------------------------------- `non_null_ptr` previously declared here @@ -179,7 +179,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:377:13 + --> $DIR/clashing-extern-fn.rs:374:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -191,7 +191,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:379:13 + --> $DIR/clashing-extern-fn.rs:376:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -203,7 +203,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:433:13 + --> $DIR/clashing-extern-fn.rs:430:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here @@ -215,13 +215,13 @@ LL | fn hidden_niche_transparent_no_niche() -> Option Option` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:437:13 + --> $DIR/clashing-extern-fn.rs:434:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | -------------------------------------- `hidden_niche_unsafe_cell` previously declared here ... -LL | fn hidden_niche_unsafe_cell() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn hidden_niche_unsafe_cell() -> Option>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn() -> Option>>` diff --git a/tests/ui/lint/ice-array-into-iter-lint-issue-121532.rs b/tests/ui/lint/ice-array-into-iter-lint-issue-121532.rs new file mode 100644 index 000000000000..92cab01fe48c --- /dev/null +++ b/tests/ui/lint/ice-array-into-iter-lint-issue-121532.rs @@ -0,0 +1,11 @@ +// Regression test for #121532 +// Checks the we don't ICE in ArrayIntoIter +// lint when typeck has failed + + // Typeck fails for the arg type as + // `Self` makes no sense here +fn func(a: Self::ItemsIterator) { //~ ERROR failed to resolve: `Self` is only available in impls, traits, and type definitions + a.into_iter(); +} + +fn main() {} diff --git a/tests/ui/lint/ice-array-into-iter-lint-issue-121532.stderr b/tests/ui/lint/ice-array-into-iter-lint-issue-121532.stderr new file mode 100644 index 000000000000..73ceddae940b --- /dev/null +++ b/tests/ui/lint/ice-array-into-iter-lint-issue-121532.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions + --> $DIR/ice-array-into-iter-lint-issue-121532.rs:7:12 + | +LL | fn func(a: Self::ItemsIterator) { + | ^^^^ `Self` is only available in impls, traits, and type definitions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/lint/ice-unions-known-panics-lint-issue-121534.rs b/tests/ui/lint/ice-unions-known-panics-lint-issue-121534.rs new file mode 100644 index 000000000000..9fadb828b3d2 --- /dev/null +++ b/tests/ui/lint/ice-unions-known-panics-lint-issue-121534.rs @@ -0,0 +1,21 @@ +// Regression test for #121534 +// Tests that no ICE occurs in KnownPanicsLint when it +// evaluates an operation whose operands have different +// layout types even though they have the same type. +// This situation can be contrived through the use of +// unions as in this test + +//@ build-pass +union Union { + u32_field: u32, + i32_field: i32, +} + +pub fn main() { + let u32_variant = Union { u32_field: 2 }; + let i32_variant = Union { i32_field: 3 }; + let a = unsafe { u32_variant.u32_field }; + let b = unsafe { i32_variant.u32_field }; + + let _diff = a - b; +} diff --git a/tests/ui/lint/invalid_value.rs b/tests/ui/lint/invalid_value.rs index 57d8cbe7c934..1d2f23aaaf6f 100644 --- a/tests/ui/lint/invalid_value.rs +++ b/tests/ui/lint/invalid_value.rs @@ -1,13 +1,12 @@ // This test checks that calling `mem::{uninitialized,zeroed}` with certain types results // in a lint. - -#![feature(never_type, rustc_attrs)] #![allow(deprecated)] #![deny(invalid_value)] +#![feature(generic_nonzero, never_type, rustc_attrs)] use std::mem::{self, MaybeUninit}; use std::ptr::NonNull; -use std::num::NonZeroU32; +use std::num::NonZero; enum Void {} @@ -36,7 +35,7 @@ enum OneFruit { enum OneFruitNonZero { Apple(!), - Banana(NonZeroU32), + Banana(NonZero), } enum TwoUninhabited { @@ -92,8 +91,8 @@ fn main() { let _val: NonNull = mem::zeroed(); //~ ERROR: does not permit zero-initialization let _val: NonNull = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - let _val: (NonZeroU32, i32) = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: (NonZeroU32, i32) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + let _val: (NonZero, i32) = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: (NonZero, i32) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized @@ -151,7 +150,7 @@ fn main() { // Transmute-from-0 let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization - let _val: NonZeroU32 = mem::transmute(0); //~ ERROR: does not permit zero-initialization + let _val: NonZero = mem::transmute(0); //~ ERROR: does not permit zero-initialization // `MaybeUninit` cases let _val: NonNull = MaybeUninit::zeroed().assume_init(); //~ ERROR: does not permit zero-initialization diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index bdf47343114c..955d01bd5d90 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -1,5 +1,5 @@ error: the type `&T` does not permit zero-initialization - --> $DIR/invalid_value.rs:54:32 + --> $DIR/invalid_value.rs:53:32 | LL | let _val: &'static T = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -9,13 +9,13 @@ LL | let _val: &'static T = mem::zeroed(); | = note: references must be non-null note: the lint level is defined here - --> $DIR/invalid_value.rs:6:9 + --> $DIR/invalid_value.rs:4:9 | LL | #![deny(invalid_value)] | ^^^^^^^^^^^^^ error: the type `&T` does not permit being left uninitialized - --> $DIR/invalid_value.rs:55:32 + --> $DIR/invalid_value.rs:54:32 | LL | let _val: &'static T = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let _val: &'static T = mem::uninitialized(); = note: references must be non-null error: the type `Wrap<&T>` does not permit zero-initialization - --> $DIR/invalid_value.rs:57:38 + --> $DIR/invalid_value.rs:56:38 | LL | let _val: Wrap<&'static T> = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -36,13 +36,13 @@ LL | let _val: Wrap<&'static T> = mem::zeroed(); | = note: `Wrap<&T>` must be non-null note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `Wrap<&T>` does not permit being left uninitialized - --> $DIR/invalid_value.rs:58:38 + --> $DIR/invalid_value.rs:57:38 | LL | let _val: Wrap<&'static T> = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ LL | let _val: Wrap<&'static T> = mem::uninitialized(); | = note: `Wrap<&T>` must be non-null note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `!` does not permit zero-initialization - --> $DIR/invalid_value.rs:65:23 + --> $DIR/invalid_value.rs:64:23 | LL | let _val: ! = mem::zeroed(); | ^^^^^^^^^^^^^ this code causes undefined behavior when executed @@ -66,7 +66,7 @@ LL | let _val: ! = mem::zeroed(); = note: the `!` type has no valid value error: the type `!` does not permit being left uninitialized - --> $DIR/invalid_value.rs:66:23 + --> $DIR/invalid_value.rs:65:23 | LL | let _val: ! = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed @@ -74,7 +74,7 @@ LL | let _val: ! = mem::uninitialized(); = note: the `!` type has no valid value error: the type `(i32, !)` does not permit zero-initialization - --> $DIR/invalid_value.rs:68:30 + --> $DIR/invalid_value.rs:67:30 | LL | let _val: (i32, !) = mem::zeroed(); | ^^^^^^^^^^^^^ this code causes undefined behavior when executed @@ -82,7 +82,7 @@ LL | let _val: (i32, !) = mem::zeroed(); = note: the `!` type has no valid value error: the type `(i32, !)` does not permit being left uninitialized - --> $DIR/invalid_value.rs:69:30 + --> $DIR/invalid_value.rs:68:30 | LL | let _val: (i32, !) = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed @@ -90,31 +90,31 @@ LL | let _val: (i32, !) = mem::uninitialized(); = note: integers must be initialized error: the type `Void` does not permit zero-initialization - --> $DIR/invalid_value.rs:71:26 + --> $DIR/invalid_value.rs:70:26 | LL | let _val: Void = mem::zeroed(); | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | note: enums with no inhabited variants have no valid value - --> $DIR/invalid_value.rs:12:1 + --> $DIR/invalid_value.rs:11:1 | LL | enum Void {} | ^^^^^^^^^ error: the type `Void` does not permit being left uninitialized - --> $DIR/invalid_value.rs:72:26 + --> $DIR/invalid_value.rs:71:26 | LL | let _val: Void = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | note: enums with no inhabited variants have no valid value - --> $DIR/invalid_value.rs:12:1 + --> $DIR/invalid_value.rs:11:1 | LL | enum Void {} | ^^^^^^^^^ error: the type `&i32` does not permit zero-initialization - --> $DIR/invalid_value.rs:74:34 + --> $DIR/invalid_value.rs:73:34 | LL | let _val: &'static i32 = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL | let _val: &'static i32 = mem::zeroed(); = note: references must be non-null error: the type `&i32` does not permit being left uninitialized - --> $DIR/invalid_value.rs:75:34 + --> $DIR/invalid_value.rs:74:34 | LL | let _val: &'static i32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | let _val: &'static i32 = mem::uninitialized(); = note: references must be non-null error: the type `Ref` does not permit zero-initialization - --> $DIR/invalid_value.rs:77:25 + --> $DIR/invalid_value.rs:76:25 | LL | let _val: Ref = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -146,13 +146,13 @@ LL | let _val: Ref = mem::zeroed(); | = note: `Ref` must be non-null note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:14:12 + --> $DIR/invalid_value.rs:13:12 | LL | struct Ref(&'static i32); | ^^^^^^^^^^^^ error: the type `Ref` does not permit being left uninitialized - --> $DIR/invalid_value.rs:78:25 + --> $DIR/invalid_value.rs:77:25 | LL | let _val: Ref = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -162,13 +162,13 @@ LL | let _val: Ref = mem::uninitialized(); | = note: `Ref` must be non-null note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:14:12 + --> $DIR/invalid_value.rs:13:12 | LL | struct Ref(&'static i32); | ^^^^^^^^^^^^ error: the type `fn()` does not permit zero-initialization - --> $DIR/invalid_value.rs:80:26 + --> $DIR/invalid_value.rs:79:26 | LL | let _val: fn() = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | let _val: fn() = mem::zeroed(); = note: function pointers must be non-null error: the type `fn()` does not permit being left uninitialized - --> $DIR/invalid_value.rs:81:26 + --> $DIR/invalid_value.rs:80:26 | LL | let _val: fn() = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ LL | let _val: fn() = mem::uninitialized(); = note: function pointers must be non-null error: the type `Wrap` does not permit zero-initialization - --> $DIR/invalid_value.rs:83:32 + --> $DIR/invalid_value.rs:82:32 | LL | let _val: Wrap = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -200,13 +200,13 @@ LL | let _val: Wrap = mem::zeroed(); | = note: `Wrap` must be non-null note: because function pointers must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `Wrap` does not permit being left uninitialized - --> $DIR/invalid_value.rs:84:32 + --> $DIR/invalid_value.rs:83:32 | LL | let _val: Wrap = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -216,13 +216,13 @@ LL | let _val: Wrap = mem::uninitialized(); | = note: `Wrap` must be non-null note: because function pointers must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `WrapEnum` does not permit zero-initialization - --> $DIR/invalid_value.rs:86:36 + --> $DIR/invalid_value.rs:85:36 | LL | let _val: WrapEnum = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -232,13 +232,13 @@ LL | let _val: WrapEnum = mem::zeroed(); | = note: `WrapEnum` must be non-null note: because function pointers must be non-null (in this field of the only potentially inhabited enum variant) - --> $DIR/invalid_value.rs:18:28 + --> $DIR/invalid_value.rs:17:28 | LL | enum WrapEnum { Wrapped(T) } | ^ error: the type `WrapEnum` does not permit being left uninitialized - --> $DIR/invalid_value.rs:87:36 + --> $DIR/invalid_value.rs:86:36 | LL | let _val: WrapEnum = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -248,13 +248,13 @@ LL | let _val: WrapEnum = mem::uninitialized(); | = note: `WrapEnum` must be non-null note: because function pointers must be non-null (in this field of the only potentially inhabited enum variant) - --> $DIR/invalid_value.rs:18:28 + --> $DIR/invalid_value.rs:17:28 | LL | enum WrapEnum { Wrapped(T) } | ^ error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization - --> $DIR/invalid_value.rs:89:42 + --> $DIR/invalid_value.rs:88:42 | LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -263,18 +263,18 @@ LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: `RefPair` must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:15:16 + --> $DIR/invalid_value.rs:14:16 | LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized - --> $DIR/invalid_value.rs:90:42 + --> $DIR/invalid_value.rs:89:42 | LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -283,18 +283,18 @@ LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: `RefPair` must be non-null (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ note: because references must be non-null (in this struct field) - --> $DIR/invalid_value.rs:15:16 + --> $DIR/invalid_value.rs:14:16 | LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ error: the type `NonNull` does not permit zero-initialization - --> $DIR/invalid_value.rs:92:34 + --> $DIR/invalid_value.rs:91:34 | LL | let _val: NonNull = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -305,7 +305,7 @@ LL | let _val: NonNull = mem::zeroed(); = note: `std::ptr::NonNull` must be non-null error: the type `NonNull` does not permit being left uninitialized - --> $DIR/invalid_value.rs:93:34 + --> $DIR/invalid_value.rs:92:34 | LL | let _val: NonNull = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -317,30 +317,30 @@ LL | let _val: NonNull = mem::uninitialized(); = note: raw pointers must be initialized error: the type `(NonZero, i32)` does not permit zero-initialization - --> $DIR/invalid_value.rs:95:39 + --> $DIR/invalid_value.rs:94:41 | -LL | let _val: (NonZeroU32, i32) = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done +LL | let _val: (NonZero, i32) = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `std::num::NonZero` must be non-null error: the type `(NonZero, i32)` does not permit being left uninitialized - --> $DIR/invalid_value.rs:96:39 + --> $DIR/invalid_value.rs:95:41 | -LL | let _val: (NonZeroU32, i32) = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done +LL | let _val: (NonZero, i32) = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `std::num::NonZero` must be non-null = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization - --> $DIR/invalid_value.rs:98:37 + --> $DIR/invalid_value.rs:97:37 | LL | let _val: *const dyn Send = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL | let _val: *const dyn Send = mem::zeroed(); = note: the vtable of a wide raw pointer must be non-null error: the type `*const dyn Send` does not permit being left uninitialized - --> $DIR/invalid_value.rs:99:37 + --> $DIR/invalid_value.rs:98:37 | LL | let _val: *const dyn Send = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -362,7 +362,7 @@ LL | let _val: *const dyn Send = mem::uninitialized(); = note: the vtable of a wide raw pointer must be non-null error: the type `[fn(); 2]` does not permit zero-initialization - --> $DIR/invalid_value.rs:101:31 + --> $DIR/invalid_value.rs:100:31 | LL | let _val: [fn(); 2] = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL | let _val: [fn(); 2] = mem::zeroed(); = note: function pointers must be non-null error: the type `[fn(); 2]` does not permit being left uninitialized - --> $DIR/invalid_value.rs:102:31 + --> $DIR/invalid_value.rs:101:31 | LL | let _val: [fn(); 2] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -384,31 +384,31 @@ LL | let _val: [fn(); 2] = mem::uninitialized(); = note: function pointers must be non-null error: the type `TwoUninhabited` does not permit zero-initialization - --> $DIR/invalid_value.rs:104:36 + --> $DIR/invalid_value.rs:103:36 | LL | let _val: TwoUninhabited = mem::zeroed(); | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | note: enums with no inhabited variants have no valid value - --> $DIR/invalid_value.rs:42:1 + --> $DIR/invalid_value.rs:41:1 | LL | enum TwoUninhabited { | ^^^^^^^^^^^^^^^^^^^ error: the type `TwoUninhabited` does not permit being left uninitialized - --> $DIR/invalid_value.rs:105:36 + --> $DIR/invalid_value.rs:104:36 | LL | let _val: TwoUninhabited = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | note: enums with no inhabited variants have no valid value - --> $DIR/invalid_value.rs:42:1 + --> $DIR/invalid_value.rs:41:1 | LL | enum TwoUninhabited { | ^^^^^^^^^^^^^^^^^^^ error: the type `OneFruitNonZero` does not permit zero-initialization - --> $DIR/invalid_value.rs:107:37 + --> $DIR/invalid_value.rs:106:37 | LL | let _val: OneFruitNonZero = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -418,13 +418,13 @@ LL | let _val: OneFruitNonZero = mem::zeroed(); | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) - --> $DIR/invalid_value.rs:39:12 + --> $DIR/invalid_value.rs:38:12 | -LL | Banana(NonZeroU32), - | ^^^^^^^^^^ +LL | Banana(NonZero), + | ^^^^^^^^^^^^ error: the type `OneFruitNonZero` does not permit being left uninitialized - --> $DIR/invalid_value.rs:108:37 + --> $DIR/invalid_value.rs:107:37 | LL | let _val: OneFruitNonZero = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -434,14 +434,14 @@ LL | let _val: OneFruitNonZero = mem::uninitialized(); | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) - --> $DIR/invalid_value.rs:39:12 + --> $DIR/invalid_value.rs:38:12 | -LL | Banana(NonZeroU32), - | ^^^^^^^^^^ +LL | Banana(NonZero), + | ^^^^^^^^^^^^ = note: integers must be initialized error: the type `bool` does not permit being left uninitialized - --> $DIR/invalid_value.rs:112:26 + --> $DIR/invalid_value.rs:111:26 | LL | let _val: bool = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -452,7 +452,7 @@ LL | let _val: bool = mem::uninitialized(); = note: booleans must be either `true` or `false` error: the type `Wrap` does not permit being left uninitialized - --> $DIR/invalid_value.rs:115:32 + --> $DIR/invalid_value.rs:114:32 | LL | let _val: Wrap = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -462,13 +462,13 @@ LL | let _val: Wrap = mem::uninitialized(); | = note: `Wrap` must be initialized inside its custom valid range note: characters must be a valid Unicode codepoint (in this struct field) - --> $DIR/invalid_value.rs:17:18 + --> $DIR/invalid_value.rs:16:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `NonBig` does not permit being left uninitialized - --> $DIR/invalid_value.rs:118:28 + --> $DIR/invalid_value.rs:117:28 | LL | let _val: NonBig = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -478,13 +478,13 @@ LL | let _val: NonBig = mem::uninitialized(); | = note: `NonBig` must be initialized inside its custom valid range note: integers must be initialized (in this struct field) - --> $DIR/invalid_value.rs:23:26 + --> $DIR/invalid_value.rs:22:26 | LL | pub(crate) struct NonBig(u64); | ^^^ error: the type `Fruit` does not permit being left uninitialized - --> $DIR/invalid_value.rs:121:27 + --> $DIR/invalid_value.rs:120:27 | LL | let _val: Fruit = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -493,13 +493,13 @@ LL | let _val: Fruit = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: enums with multiple inhabited variants have to be initialized to a variant - --> $DIR/invalid_value.rs:26:1 + --> $DIR/invalid_value.rs:25:1 | LL | enum Fruit { | ^^^^^^^^^^ error: the type `[bool; 2]` does not permit being left uninitialized - --> $DIR/invalid_value.rs:124:31 + --> $DIR/invalid_value.rs:123:31 | LL | let _val: [bool; 2] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ LL | let _val: [bool; 2] = mem::uninitialized(); = note: booleans must be either `true` or `false` error: the type `i32` does not permit being left uninitialized - --> $DIR/invalid_value.rs:127:25 + --> $DIR/invalid_value.rs:126:25 | LL | let _val: i32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -521,7 +521,7 @@ LL | let _val: i32 = mem::uninitialized(); = note: integers must be initialized error: the type `f32` does not permit being left uninitialized - --> $DIR/invalid_value.rs:130:25 + --> $DIR/invalid_value.rs:129:25 | LL | let _val: f32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +532,7 @@ LL | let _val: f32 = mem::uninitialized(); = note: floats must be initialized error: the type `*const ()` does not permit being left uninitialized - --> $DIR/invalid_value.rs:133:31 + --> $DIR/invalid_value.rs:132:31 | LL | let _val: *const () = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -543,7 +543,7 @@ LL | let _val: *const () = mem::uninitialized(); = note: raw pointers must be initialized error: the type `*const [()]` does not permit being left uninitialized - --> $DIR/invalid_value.rs:136:33 + --> $DIR/invalid_value.rs:135:33 | LL | let _val: *const [()] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -554,7 +554,7 @@ LL | let _val: *const [()] = mem::uninitialized(); = note: raw pointers must be initialized error: the type `WrapAroundRange` does not permit being left uninitialized - --> $DIR/invalid_value.rs:139:37 + --> $DIR/invalid_value.rs:138:37 | LL | let _val: WrapAroundRange = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -564,13 +564,13 @@ LL | let _val: WrapAroundRange = mem::uninitialized(); | = note: `WrapAroundRange` must be initialized inside its custom valid range note: integers must be initialized (in this struct field) - --> $DIR/invalid_value.rs:49:35 + --> $DIR/invalid_value.rs:48:35 | LL | pub(crate) struct WrapAroundRange(u8); | ^^ error: the type `Result` does not permit being left uninitialized - --> $DIR/invalid_value.rs:144:38 + --> $DIR/invalid_value.rs:143:38 | LL | let _val: Result = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -582,7 +582,7 @@ note: enums with multiple inhabited variants have to be initialized to a variant --> $SRC_DIR/core/src/result.rs:LL:COL error: the type `&i32` does not permit zero-initialization - --> $DIR/invalid_value.rs:152:34 + --> $DIR/invalid_value.rs:151:34 | LL | let _val: &'static i32 = mem::transmute(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -593,7 +593,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize); = note: references must be non-null error: the type `&[i32]` does not permit zero-initialization - --> $DIR/invalid_value.rs:153:36 + --> $DIR/invalid_value.rs:152:36 | LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -604,18 +604,18 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); = note: references must be non-null error: the type `NonZero` does not permit zero-initialization - --> $DIR/invalid_value.rs:154:32 + --> $DIR/invalid_value.rs:153:34 | -LL | let _val: NonZeroU32 = mem::transmute(0); - | ^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done +LL | let _val: NonZero = mem::transmute(0); + | ^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `std::num::NonZero` must be non-null error: the type `NonNull` does not permit zero-initialization - --> $DIR/invalid_value.rs:157:34 + --> $DIR/invalid_value.rs:156:34 | LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -626,7 +626,7 @@ LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); = note: `std::ptr::NonNull` must be non-null error: the type `NonNull` does not permit being left uninitialized - --> $DIR/invalid_value.rs:158:34 + --> $DIR/invalid_value.rs:157:34 | LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -638,7 +638,7 @@ LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); = note: raw pointers must be initialized error: the type `bool` does not permit being left uninitialized - --> $DIR/invalid_value.rs:159:26 + --> $DIR/invalid_value.rs:158:26 | LL | let _val: bool = MaybeUninit::uninit().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 7c2060805939..3157b6e240ae 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -1,7 +1,8 @@ -#![feature(transparent_unions)] -#![feature(ptr_internals)] -#![deny(improper_ctypes)] #![allow(dead_code)] +#![deny(improper_ctypes)] +#![feature(generic_nonzero)] +#![feature(ptr_internals)] +#![feature(transparent_unions)] use std::num; @@ -67,26 +68,26 @@ extern "C" { fn option_fn(x: Option); fn nonnull(x: Option>); fn unique(x: Option>); - fn nonzero_u8(x: Option); - fn nonzero_u16(x: Option); - fn nonzero_u32(x: Option); - fn nonzero_u64(x: Option); - fn nonzero_u128(x: Option); + fn nonzero_u8(x: Option>); + fn nonzero_u16(x: Option>); + fn nonzero_u32(x: Option>); + fn nonzero_u64(x: Option>); + fn nonzero_u128(x: Option>); //~^ ERROR `extern` block uses type `u128` - fn nonzero_usize(x: Option); - fn nonzero_i8(x: Option); - fn nonzero_i16(x: Option); - fn nonzero_i32(x: Option); - fn nonzero_i64(x: Option); - fn nonzero_i128(x: Option); + fn nonzero_usize(x: Option>); + fn nonzero_i8(x: Option>); + fn nonzero_i16(x: Option>); + fn nonzero_i32(x: Option>); + fn nonzero_i64(x: Option>); + fn nonzero_i128(x: Option>); //~^ ERROR `extern` block uses type `i128` - fn nonzero_isize(x: Option); - fn transparent_struct(x: Option>); - fn transparent_enum(x: Option>); - fn transparent_union(x: Option>); + fn nonzero_isize(x: Option>); + fn transparent_struct(x: Option>>); + fn transparent_enum(x: Option>>); + fn transparent_union(x: Option>>); //~^ ERROR `extern` block uses type - fn repr_rust(x: Option>); //~ ERROR `extern` block uses type - fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR `extern` block uses type + fn repr_rust(x: Option>>); //~ ERROR `extern` block uses type + fn no_result(x: Result<(), num::NonZero>); //~ ERROR `extern` block uses type } pub fn main() {} diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 64beefbb7579..48be3eb5a563 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `U`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:60:13 + --> $DIR/lint-ctypes-enum.rs:61:13 | LL | fn uf(x: U); | ^ not FFI-safe @@ -7,18 +7,18 @@ LL | fn uf(x: U); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:9:1 + --> $DIR/lint-ctypes-enum.rs:10:1 | LL | enum U { | ^^^^^^ note: the lint level is defined here - --> $DIR/lint-ctypes-enum.rs:3:9 + --> $DIR/lint-ctypes-enum.rs:2:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `B`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:61:13 + --> $DIR/lint-ctypes-enum.rs:62:13 | LL | fn bf(x: B); | ^ not FFI-safe @@ -26,13 +26,13 @@ LL | fn bf(x: B); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:12:1 + --> $DIR/lint-ctypes-enum.rs:13:1 | LL | enum B { | ^^^^^^ error: `extern` block uses type `T`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:62:13 + --> $DIR/lint-ctypes-enum.rs:63:13 | LL | fn tf(x: T); | ^ not FFI-safe @@ -40,50 +40,50 @@ LL | fn tf(x: T); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:16:1 + --> $DIR/lint-ctypes-enum.rs:17:1 | LL | enum T { | ^^^^^^ error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:74:23 + --> $DIR/lint-ctypes-enum.rs:75:23 | -LL | fn nonzero_u128(x: Option); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn nonzero_u128(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:81:23 + --> $DIR/lint-ctypes-enum.rs:82:23 | -LL | fn nonzero_i128(x: Option); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn nonzero_i128(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:86:28 + --> $DIR/lint-ctypes-enum.rs:87:28 | -LL | fn transparent_union(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn transparent_union(x: Option>>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = 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>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:88:20 + --> $DIR/lint-ctypes-enum.rs:89:20 | -LL | fn repr_rust(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn repr_rust(x: Option>>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = 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<(), NonZero>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:89:20 + --> $DIR/lint-ctypes-enum.rs:90:20 | -LL | fn no_result(x: Result<(), num::NonZeroI32>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn no_result(x: Result<(), num::NonZero>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs new file mode 100644 index 000000000000..c9aaa0493463 --- /dev/null +++ b/tests/ui/lint/non_local_definitions.rs @@ -0,0 +1,385 @@ +//@ check-pass +//@ edition:2021 +//@ aux-build:non_local_macro.rs +//@ rustc-env:CARGO=/usr/bin/cargo + +#![feature(inline_const)] + +extern crate non_local_macro; + +use std::fmt::{Debug, Display}; + +struct Test; + +impl Debug for Test { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +mod do_not_lint_mod { + pub trait Tait {} + + impl super::Test { + fn hugo() {} + } + + impl Tait for super::Test {} +} + +trait Uto {} +const Z: () = { + trait Uto1 {} + + impl Uto1 for Test {} // the trait is local, don't lint + + impl Uto for &Test {} + //~^ WARN non-local `impl` definition +}; + +trait Ano {} +const _: () = { + impl Ano for &Test {} // ignored since the parent is an anon-const +}; + +type A = [u32; { + impl Uto for *mut Test {} + //~^ WARN non-local `impl` definition + + 1 +}]; + +enum Enum { + Discr = { + impl Uto for Test {} + //~^ WARN non-local `impl` definition + + 1 + } +} + +trait Uto2 {} +static A: u32 = { + impl Uto2 for Test {} + //~^ WARN non-local `impl` definition + + 1 +}; + +trait Uto3 {} +const B: u32 = { + impl Uto3 for Test {} + //~^ WARN non-local `impl` definition + + #[macro_export] + macro_rules! m0 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + trait Uto4 {} + impl Uto4 for Test {} + + 1 +}; + +trait Uto5 {} +fn main() { + #[macro_export] + macro_rules! m { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + impl Test { + //~^ WARN non-local `impl` definition + fn foo() {} + } + + let _array = [0i32; { + impl Test { + //~^ WARN non-local `impl` definition + fn bar() {} + } + + 1 + }]; + + const { + impl Test { + //~^ WARN non-local `impl` definition + fn hoo() {} + } + + 1 + }; + + const _: u32 = { + impl Test { + //~^ WARN non-local `impl` definition + fn foo2() {} + } + + 1 + }; + + impl Display for Test { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl dyn Uto5 {} + //~^ WARN non-local `impl` definition + + impl Uto5 for Vec { } + //~^ WARN non-local `impl` definition + + impl Uto5 for &dyn Uto5 {} + //~^ WARN non-local `impl` definition + + impl Uto5 for *mut Test {} + //~^ WARN non-local `impl` definition + + impl Uto5 for *mut [Test] {} + //~^ WARN non-local `impl` definition + + impl Uto5 for [Test; 8] {} + //~^ WARN non-local `impl` definition + + impl Uto5 for (Test,) {} + //~^ WARN non-local `impl` definition + + impl Uto5 for fn(Test) -> () {} + //~^ WARN non-local `impl` definition + + impl Uto5 for fn() -> Test {} + //~^ WARN non-local `impl` definition + + let _a = || { + impl Uto5 for Test {} + //~^ WARN non-local `impl` definition + + 1 + }; + + type A = [u32; { + impl Uto5 for &Test {} + //~^ WARN non-local `impl` definition + + 1 + }]; + + fn a(_: [u32; { + impl Uto5 for &(Test,) {} + //~^ WARN non-local `impl` definition + + 1 + }]) {} + + fn b() -> [u32; { + impl Uto5 for &(Test,Test) {} + //~^ WARN non-local `impl` definition + + 1 + }] { todo!() } + + struct InsideMain; + + impl Uto5 for *mut InsideMain {} + //~^ WARN non-local `impl` definition + impl Uto5 for *mut [InsideMain] {} + //~^ WARN non-local `impl` definition + impl Uto5 for [InsideMain; 8] {} + //~^ WARN non-local `impl` definition + impl Uto5 for (InsideMain,) {} + //~^ WARN non-local `impl` definition + impl Uto5 for fn(InsideMain) -> () {} + //~^ WARN non-local `impl` definition + impl Uto5 for fn() -> InsideMain {} + //~^ WARN non-local `impl` definition + + impl Debug for InsideMain { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl InsideMain { + fn foo() {} + } + + fn inside_inside() { + impl Display for InsideMain { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl InsideMain { + //~^ WARN non-local `impl` definition + fn bar() { + #[macro_export] + macro_rules! m2 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + } + } + } + + trait Uto6 {} + impl dyn Uto6 {} + impl Uto5 for dyn Uto6 {} + + impl Uto3 for Vec { } + //~^ WARN non-local `impl` definition +} + +trait Uto7 {} +trait Uto8 {} + +fn bad() { + struct Local; + impl Uto7 for Test where Local: std::any::Any {} + //~^ WARN non-local `impl` definition + + impl Uto8 for T {} + //~^ WARN non-local `impl` definition +} + +struct UwU(T); + +fn fun() { + #[derive(Debug)] + struct OwO; + impl Default for UwU { + //~^ WARN non-local `impl` definition + fn default() -> Self { + UwU(OwO) + } + } +} + +struct Cat; + +fn meow() { + impl From for () { + //~^ WARN non-local `impl` definition + fn from(_: Cat) -> () { + todo!() + } + } + + #[derive(Debug)] + struct Cat; + impl AsRef for () { + //~^ WARN non-local `impl` definition + fn as_ref(&self) -> &Cat { &Cat } + } +} + +struct G; + +fn fun2() { + #[derive(Debug, Default)] + struct B; + impl PartialEq for G { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &B) -> bool { + true + } + } +} + +fn side_effects() { + dbg!(().as_ref()); // prints `Cat` + dbg!(UwU::default().0); + let _ = G::eq(&G, dbg!(&<_>::default())); +} + +struct Dog; + +fn woof() { + impl PartialEq for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + impl PartialEq<()> for Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq<()> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq for () { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + struct Test; + impl PartialEq for Test { + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } +} + +struct Wrap(T); + +impl Wrap>> {} + +fn rawr() { + struct Lion; + + impl From>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap>) -> Self { + todo!() + } + } + + impl From<()> for Wrap { + //~^ WARN non-local `impl` definition + fn from(_: ()) -> Self { + todo!() + } + } +} + +macro_rules! m { + () => { + trait MacroTrait {} + struct OutsideStruct; + fn my_func() { + impl MacroTrait for OutsideStruct {} + //~^ WARN non-local `impl` definition + } + } +} + +m!(); + +struct CargoUpdate; + +non_local_macro::non_local_impl!(CargoUpdate); +//~^ WARN non-local `impl` definition + +non_local_macro::non_local_macro_rules!(my_macro); +//~^ WARN non-local `macro_rules!` definition + +fn bitflags() { + struct Flags; + + const _: () = { + impl Flags {} + }; +} diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr new file mode 100644 index 000000000000..f9f29ec63a80 --- /dev/null +++ b/tests/ui/lint/non_local_definitions.stderr @@ -0,0 +1,640 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:36:5 + | +LL | const Z: () = { + | - help: use a const-anon item to suppress this lint: `_` +... +LL | impl Uto for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `Z` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:46:5 + | +LL | impl Uto for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:54:9 + | +LL | impl Uto for Test {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:63:5 + | +LL | impl Uto2 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current static `A` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:71:5 + | +LL | impl Uto3 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `B` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:75:5 + | +LL | macro_rules! m0 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:87:5 + | +LL | macro_rules! m { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:90:5 + | +LL | / impl Test { +LL | | +LL | | fn foo() {} +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:96:9 + | +LL | / impl Test { +LL | | +LL | | fn bar() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:105:9 + | +LL | / impl Test { +LL | | +LL | | fn hoo() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current inline constant `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:114:9 + | +LL | / impl Test { +LL | | +LL | | fn foo2() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant `_` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:122:5 + | +LL | / impl Display for Test { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:129:5 + | +LL | impl dyn Uto5 {} + | ^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:132:5 + | +LL | impl Uto5 for Vec { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:135:5 + | +LL | impl Uto5 for &dyn Uto5 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:138:5 + | +LL | impl Uto5 for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:141:5 + | +LL | impl Uto5 for *mut [Test] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:144:5 + | +LL | impl Uto5 for [Test; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:147:5 + | +LL | impl Uto5 for (Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:150:5 + | +LL | impl Uto5 for fn(Test) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:153:5 + | +LL | impl Uto5 for fn() -> Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:157:9 + | +LL | impl Uto5 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current closure `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:164:9 + | +LL | impl Uto5 for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:171:9 + | +LL | impl Uto5 for &(Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:178:9 + | +LL | impl Uto5 for &(Test,Test) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:186:5 + | +LL | impl Uto5 for *mut InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:188:5 + | +LL | impl Uto5 for *mut [InsideMain] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:190:5 + | +LL | impl Uto5 for [InsideMain; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:192:5 + | +LL | impl Uto5 for (InsideMain,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:194:5 + | +LL | impl Uto5 for fn(InsideMain) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:196:5 + | +LL | impl Uto5 for fn() -> InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:210:9 + | +LL | / impl Display for InsideMain { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:217:9 + | +LL | / impl InsideMain { +LL | | +LL | | fn bar() { +LL | | #[macro_export] +... | +LL | | } +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:221:17 + | +LL | macro_rules! m2 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 3 bodies + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:231:5 + | +LL | impl Uto3 for Vec { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:240:5 + | +LL | impl Uto7 for Test where Local: std::any::Any {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:243:5 + | +LL | impl Uto8 for T {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:252:5 + | +LL | / impl Default for UwU { +LL | | +LL | | fn default() -> Self { +LL | | UwU(OwO) +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:263:5 + | +LL | / impl From for () { +LL | | +LL | | fn from(_: Cat) -> () { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `meow` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:272:5 + | +LL | / impl AsRef for () { +LL | | +LL | | fn as_ref(&self) -> &Cat { &Cat } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `meow` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:283:5 + | +LL | / impl PartialEq for G { +LL | | +LL | | fn eq(&self, _: &B) -> bool { +LL | | true +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun2` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:300:5 + | +LL | / impl PartialEq for &Dog { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `woof` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:307:5 + | +LL | / impl PartialEq<()> for Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `woof` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:314:5 + | +LL | / impl PartialEq<()> for &Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `woof` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:321:5 + | +LL | / impl PartialEq for () { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `woof` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:343:5 + | +LL | / impl From>> for () { +LL | | +LL | | fn from(_: Wrap>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:350:5 + | +LL | / impl From<()> for Wrap { +LL | | +LL | | fn from(_: ()) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:363:13 + | +LL | impl MacroTrait for OutsideStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: move this `impl` block outside the of the current function `my_func` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:373:1 + | +LL | non_local_macro::non_local_impl!(CargoUpdate); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` + = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:376:1 + | +LL | non_local_macro::non_local_macro_rules!(my_macro); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 50 warnings emitted + diff --git a/tests/ui/macros/type-macros-simple.rs b/tests/ui/macros/type-macros-simple.rs index 4d1001baf59f..d189b881f7dd 100644 --- a/tests/ui/macros/type-macros-simple.rs +++ b/tests/ui/macros/type-macros-simple.rs @@ -1,6 +1,8 @@ //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] +#![allow(non_local_definitions)] + macro_rules! Tuple { { $A:ty,$B:ty } => { ($A, $B) } } diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.rs b/tests/ui/match/issue-72896-non-partial-eq-const.rs index d49727146084..f15eae83896d 100644 --- a/tests/ui/match/issue-72896-non-partial-eq-const.rs +++ b/tests/ui/match/issue-72896-non-partial-eq-const.rs @@ -1,4 +1,3 @@ -//@ run-pass trait EnumSetType { type Repr; } @@ -17,8 +16,7 @@ const CONST_SET: EnumSet = EnumSet { __enumset_underlying: 3 }; fn main() { match CONST_SET { - CONST_SET => { /* ok */ } //~WARN: must implement `PartialEq` - //~| previously accepted + CONST_SET => { /* ok */ } //~ERROR: must implement `PartialEq` _ => panic!("match fell through?"), } } diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr index a7fc0cfc0545..4155586c1606 100644 --- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr +++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr @@ -1,23 +1,8 @@ -warning: to use a constant of type `EnumSet` in a pattern, the type must implement `PartialEq` - --> $DIR/issue-72896-non-partial-eq-const.rs:20:9 +error: to use a constant of type `EnumSet` in a pattern, the type must implement `PartialEq` + --> $DIR/issue-72896-non-partial-eq-const.rs:19:9 | LL | CONST_SET => { /* ok */ } | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116122 - = note: `#[warn(const_patterns_without_partial_eq)]` on by default -warning: 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -warning: to use a constant of type `EnumSet` in a pattern, the type must implement `PartialEq` - --> $DIR/issue-72896-non-partial-eq-const.rs:20:9 - | -LL | CONST_SET => { /* ok */ } - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #116122 - = note: `#[warn(const_patterns_without_partial_eq)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs index dc3b6c280f34..bda5cef979ec 100644 --- a/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs +++ b/tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs @@ -2,11 +2,11 @@ //@ error-pattern:attempt to negate with overflow //@ ignore-emscripten no processes //@ compile-flags: -C debug-assertions - #![allow(arithmetic_overflow)] +#![feature(generic_nonzero)] -use std::num::NonZeroI8; +use std::num::NonZero; fn main() { - let _x = -NonZeroI8::new(i8::MIN).unwrap(); + let _x = -NonZero::new(i8::MIN).unwrap(); } diff --git a/tests/ui/packed/issue-46152.rs b/tests/ui/packed/issue-46152.rs index e38b445107ba..5b2e4bbfdf24 100644 --- a/tests/ui/packed/issue-46152.rs +++ b/tests/ui/packed/issue-46152.rs @@ -1,6 +1,7 @@ //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] +#![allow(non_local_definitions)] #![feature(unsize, coerce_unsized)] #[repr(packed)] diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index da11f0c01217..07da1cff27a7 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -1,24 +1,24 @@ +//! This file illustrates how niche-filling enums are handled, +//! modelled after cases like `Option<&u32>`, `Option` and such. +//! +//! It uses `NonZero` rather than `&_` or `Unique<_>`, because +//! the test is not set up to deal with target-dependent pointer width. +//! +//! It avoids using `u64`/`i64` because on some targets that is only 4-byte +//! aligned (while on most it is 8-byte aligned) and so the resulting +//! padding and overall computed sizes can be quite different. +//! //@ compile-flags: -Z print-type-sizes --crate-type lib //@ ignore-debug: debug assertions will print more types //@ build-pass //@ ignore-pass -// ^-- needed because `--pass check` does not emit the output needed. -// FIXME: consider using an attribute instead of side-effects. - -// This file illustrates how niche-filling enums are handled, -// modelled after cases like `Option<&u32>`, `Option` and such. -// -// It uses NonZeroU32 rather than `&_` or `Unique<_>`, because -// the test is not set up to deal with target-dependent pointer width. -// -// It avoids using u64/i64 because on some targets that is only 4-byte -// aligned (while on most it is 8-byte aligned) and so the resulting -// padding and overall computed sizes can be quite different. - -#![feature(rustc_attrs)] +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. #![allow(dead_code)] +#![feature(generic_nonzero)] +#![feature(rustc_attrs)] -use std::num::NonZeroU32; +use std::num::NonZero; pub enum MyOption { None, Some(T) } @@ -34,7 +34,7 @@ impl Default for MyOption { pub enum EmbeddedDiscr { None, - Record { pre: u8, val: NonZeroU32, post: u16 }, + Record { pre: u8, val: NonZero, post: u16 }, } impl Default for EmbeddedDiscr { @@ -50,13 +50,13 @@ pub struct IndirectNonZero { pub struct NestedNonZero { pre: u8, - val: NonZeroU32, + val: NonZero, post: u16, } impl Default for NestedNonZero { fn default() -> Self { - NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 } + NestedNonZero { pre: 0, val: unsafe { NonZero::new_unchecked(1) }, post: 0 } } } @@ -77,7 +77,7 @@ pub union Union2 { } pub fn test() { - let _x: MyOption = Default::default(); + let _x: MyOption> = Default::default(); let _y: EmbeddedDiscr = Default::default(); let _z: MyOption = Default::default(); let _a: MyOption = Default::default(); @@ -90,9 +90,9 @@ pub fn test() { let _h: MyOption = Default::default(); // Unions do not currently participate in niche filling. - let _i: MyOption> = Default::default(); + let _i: MyOption, u32>> = Default::default(); // ...even when theoretically possible. - let _j: MyOption> = Default::default(); - let _k: MyOption> = Default::default(); + let _j: MyOption>> = Default::default(); + let _k: MyOption, NonZero>> = Default::default(); } diff --git a/tests/ui/privacy/associated-item-privacy-trait.rs b/tests/ui/privacy/associated-item-privacy-trait.rs index f038ae9e261d..655d892e2441 100644 --- a/tests/ui/privacy/associated-item-privacy-trait.rs +++ b/tests/ui/privacy/associated-item-privacy-trait.rs @@ -1,5 +1,5 @@ #![feature(decl_macro, associated_type_defaults)] -#![allow(private_interfaces, private_bounds)] +#![allow(private_interfaces, private_bounds, non_local_definitions)] mod priv_trait { trait PrivTr { diff --git a/tests/ui/privacy/private-in-public-non-principal.rs b/tests/ui/privacy/private-in-public-non-principal.rs index e348a181651c..8dc90919bc9e 100644 --- a/tests/ui/privacy/private-in-public-non-principal.rs +++ b/tests/ui/privacy/private-in-public-non-principal.rs @@ -1,5 +1,6 @@ #![feature(auto_traits)] #![feature(negative_impls)] +#![allow(non_local_definitions)] pub trait PubPrincipal {} auto trait PrivNonPrincipal {} diff --git a/tests/ui/privacy/private-in-public-non-principal.stderr b/tests/ui/privacy/private-in-public-non-principal.stderr index 73f2249bc6c0..5aa08d3f0717 100644 --- a/tests/ui/privacy/private-in-public-non-principal.stderr +++ b/tests/ui/privacy/private-in-public-non-principal.stderr @@ -1,24 +1,24 @@ warning: trait `PrivNonPrincipal` is more private than the item `leak_dyn_nonprincipal` - --> $DIR/private-in-public-non-principal.rs:7:1 + --> $DIR/private-in-public-non-principal.rs:8:1 | LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function `leak_dyn_nonprincipal` is reachable at visibility `pub` | note: but trait `PrivNonPrincipal` is only usable at visibility `pub(crate)` - --> $DIR/private-in-public-non-principal.rs:5:1 + --> $DIR/private-in-public-non-principal.rs:6:1 | LL | auto trait PrivNonPrincipal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(private_interfaces)]` on by default error: missing documentation for an associated function - --> $DIR/private-in-public-non-principal.rs:13:9 + --> $DIR/private-in-public-non-principal.rs:14:9 | LL | pub fn check_doc_lint() {} | ^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/private-in-public-non-principal.rs:10:8 + --> $DIR/private-in-public-non-principal.rs:11:8 | LL | #[deny(missing_docs)] | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/nested-macro-rules.rs b/tests/ui/proc-macro/nested-macro-rules.rs index bb25b97df506..0dce3c408c20 100644 --- a/tests/ui/proc-macro/nested-macro-rules.rs +++ b/tests/ui/proc-macro/nested-macro-rules.rs @@ -19,5 +19,6 @@ fn main() { nested_macro_rules::inner_macro!(print_bang, print_attr); nested_macro_rules::outer_macro!(SecondStruct, SecondAttrStruct); + //~^ WARN non-local `macro_rules!` definition inner_macro!(print_bang, print_attr); } diff --git a/tests/ui/proc-macro/nested-macro-rules.stderr b/tests/ui/proc-macro/nested-macro-rules.stderr new file mode 100644 index 000000000000..111be8827714 --- /dev/null +++ b/tests/ui/proc-macro/nested-macro-rules.stderr @@ -0,0 +1,27 @@ +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/auxiliary/nested-macro-rules.rs:7:9 + | +LL | macro_rules! outer_macro { + | ------------------------ in this expansion of `nested_macro_rules::outer_macro!` +... +LL | / macro_rules! inner_macro { +LL | | ($bang_macro:ident, $attr_macro:ident) => { +LL | | $bang_macro!($name); +LL | | #[$attr_macro] struct $attr_struct_name {} +LL | | } +LL | | } + | |_________^ + | + ::: $DIR/nested-macro-rules.rs:21:5 + | +LL | nested_macro_rules::outer_macro!(SecondStruct, SecondAttrStruct); + | ---------------------------------------------------------------- in this macro invocation + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `#[warn(non_local_definitions)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rust-2018/uniform-paths/issue-55779.rs b/tests/ui/rust-2018/uniform-paths/issue-55779.rs index 350ab324682b..246b8dd82c5e 100644 --- a/tests/ui/rust-2018/uniform-paths/issue-55779.rs +++ b/tests/ui/rust-2018/uniform-paths/issue-55779.rs @@ -2,6 +2,8 @@ //@ edition:2018 //@ aux-crate:issue_55779_extern_trait=issue-55779-extern-trait.rs +#![allow(non_local_definitions)] + use issue_55779_extern_trait::Trait; struct Local; diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.rs b/tests/ui/structs-enums/enum-null-pointer-opt.rs index 6f8c81689682..a8418943ba4f 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.rs +++ b/tests/ui/structs-enums/enum-null-pointer-opt.rs @@ -1,8 +1,9 @@ //@ run-pass +#![feature(generic_nonzero)] #![feature(transparent_unions)] use std::mem::size_of; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; @@ -57,7 +58,7 @@ fn main() { assert_eq!(size_of::<[Box; 1]>(), size_of::; 1]>>()); // Should apply to NonZero - assert_eq!(size_of::(), size_of::>()); + assert_eq!(size_of::>(), size_of::>>()); assert_eq!(size_of::>(), size_of::>>()); // Should apply to types that use NonZero internally diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr index 64e93ffaffd6..fca62bd1c801 100644 --- a/tests/ui/structs-enums/enum-null-pointer-opt.stderr +++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr @@ -1,5 +1,5 @@ warning: method `dummy` is never used - --> $DIR/enum-null-pointer-opt.rs:10:18 + --> $DIR/enum-null-pointer-opt.rs:11:18 | LL | trait Trait { fn dummy(&self) { } } | ----- ^^^^^ diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 92060e3cade3..66f663ce0776 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -2,12 +2,13 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] +#![feature(generic_nonzero)] #![feature(never_type)] #![feature(pointer_is_aligned)] #![feature(strict_provenance)] use std::mem::size_of; -use std::num::{NonZeroU8, NonZeroU16}; +use std::num::NonZero; use std::ptr; use std::ptr::NonNull; use std::borrow::Cow; @@ -110,14 +111,14 @@ enum Option2 { // Two layouts are considered for `CanBeNicheFilledButShouldnt`: // Niche-filling: -// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) } +// { u32 (4 bytes), NonZero + tag in niche (1 byte), padding (3 bytes) } // Tagged: -// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) } +// { tag (1 byte), NonZero (1 byte), padding (2 bytes), u32 (4 bytes) } // Both are the same size (due to padding), // but the tagged layout is better as the tag creates a niche with 254 invalid values, // allowing types like `Option>` to fit into 8 bytes. pub enum CanBeNicheFilledButShouldnt { - A(NonZeroU8, u32), + A(NonZero, u32), B } pub enum AlwaysTaggedBecauseItHasNoNiche { @@ -135,7 +136,7 @@ pub enum NicheFilledMultipleFields { G, } -struct BoolInTheMiddle(std::num::NonZeroU16, bool, u8); +struct BoolInTheMiddle(NonZero, bool, u8); enum NicheWithData { A, @@ -275,7 +276,7 @@ pub fn main() { assert_eq!(size_of::>(), 2); assert_eq!(size_of::>>(), 2); - struct S1{ a: u16, b: std::num::NonZeroU16, c: u16, d: u8, e: u32, f: u64, g:[u8;2] } + struct S1{ a: u16, b: NonZero, c: u16, d: u8, e: u32, f: u64, g:[u8;2] } assert_eq!(size_of::(), 24); assert_eq!(size_of::>(), 24); @@ -287,14 +288,14 @@ pub fn main() { size_of::<(&(), NicheWithData)>() ); - pub enum FillPadding { A(std::num::NonZeroU8, u32), B } + pub enum FillPadding { A(NonZero, u32), B } assert_eq!(size_of::(), 8); assert_eq!(size_of::>(), 8); assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>(), 4); - assert_eq!(size_of::>>(), 4); - assert_eq!(size_of::>(), 4); + assert_eq!(size_of::, u8, u8), u16>>(), 4); + assert_eq!(size_of::, u8, u8), u16>>>(), 4); + assert_eq!(size_of::, u8, u8, u8), u16>>(), 4); assert_eq!(size_of::>(), 6); assert_eq!(size_of::>(), 4); @@ -314,10 +315,10 @@ pub fn main() { assert_eq!(ptr::from_ref(&v), ptr::from_ref(&v.r.ptr).cast(), "sort niches to the front where possible"); - // Ideal layouts: (bool, u8, NonZeroU16) or (NonZeroU16, u8, bool) + // Ideal layouts: (bool, u8, NonZero) or (NonZero, u8, bool) // Currently the layout algorithm will choose the latter because it doesn't attempt // to aggregate multiple smaller fields to move a niche before a higher-alignment one. - let b = BoolInTheMiddle( NonZeroU16::new(1).unwrap(), true, 0); + let b = BoolInTheMiddle(NonZero::new(1).unwrap(), true, 0); assert!(ptr::from_ref(&b.1).addr() > ptr::from_ref(&b.2).addr()); assert_eq!(size_of::>(), size_of::()); diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.rs b/tests/ui/suggestions/core-std-import-order-issue-83564.rs index 2cf1983858a6..62b9b246cc81 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.rs +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.rs @@ -1,10 +1,11 @@ //@ edition:2018 - +// // This is a regression test for #83564. // For some reason, Rust 2018 or higher is required to reproduce the bug. +#![feature(generic_nonzero)] fn main() { //~^ HELP consider importing one of these items - let _x = NonZeroU32::new(5).unwrap(); - //~^ ERROR failed to resolve: use of undeclared type `NonZeroU32` + let _x = NonZero::new(5u32).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZero` } diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr index c2634e3070ea..56e10b9340c0 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type `NonZeroU32` - --> $DIR/core-std-import-order-issue-83564.rs:8:14 +error[E0433]: failed to resolve: use of undeclared type `NonZero` + --> $DIR/core-std-import-order-issue-83564.rs:9:14 | -LL | let _x = NonZeroU32::new(5).unwrap(); - | ^^^^^^^^^^ use of undeclared type `NonZeroU32` +LL | let _x = NonZero::new(5u32).unwrap(); + | ^^^^^^^ use of undeclared type `NonZero` | help: consider importing one of these items | -LL + use core::num::NonZeroU32; +LL + use core::num::NonZero; | -LL + use std::num::NonZeroU32; +LL + use std::num::NonZero; | error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index 41c903220113..17c55fb4d49d 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver //~^ ERROR cannot normalize `::Id: '_` - +#![feature(generic_nonzero)] #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete @@ -23,8 +23,9 @@ fn transmute, U: Copy>(t: T) -> U { *t.intu() } -use std::num::NonZeroU8; +use std::num::NonZero; + fn main() { - let s = transmute::>(0); //~ ERROR cannot satisfy + let s = transmute::>>(0); //~ ERROR cannot satisfy assert_eq!(s, None); } diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index c87612d6a26e..65e337003252 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -23,10 +23,10 @@ LL | self | ^^^^ cannot satisfy `T <: ::Id` error[E0284]: type annotations needed: cannot satisfy `::Id == Option>` - --> $DIR/specialization-transmute.rs:28:13 + --> $DIR/specialization-transmute.rs:29:13 | -LL | let s = transmute::>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == Option>` +LL | let s = transmute::>>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == Option>` | note: required by a bound in `transmute` --> $DIR/specialization-transmute.rs:22:25