diff options
324 files changed, 4670 insertions, 2581 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d23682596fd..663ace48e9e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -20,3 +20,6 @@ f97fddab91fbf290ea5b691fe355d6f915220b6e cc907f80b95c6ec530c5ee1b05b044a468f07eca # format let-chains b2d2184edea578109a48ec3d8decbee5948e8f35 +# test directives migration +6e48b96692d63a79a14563f27fe5185f122434f8 +ec2cc761bc7067712ecc7734502f703fe3b024c8 diff --git a/Cargo.lock b/Cargo.lock index 5b19c4a721e..8518bb2a91f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3308,13 +3308,14 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544" +checksum = "a26170e1d79ea32f7ccec3188dd13cfc1f18c82764a9cbc1071667c0f865a4ea" dependencies = [ "anyhow", "rustc_version", "tempfile", + "walkdir", ] [[package]] diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 50fe37dcdb6..5ccc7d51066 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<Lit> { 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<bool> for IdentIsRaw { + fn from(b: bool) -> Self { + if b { Self::Yes } else { Self::No } + } +} + +impl From<IdentIsRaw> 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<ast::Pat>), NtExpr(P<ast::Expr>), NtTy(P<ast::Ty>), - NtIdent(Ident, /* is_raw */ bool), + NtIdent(Ident, IdentIsRaw), NtLifetime(Ident), NtLiteral(P<ast::Expr>), /// Stuff inside brackets for attributes diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 298c01a4567..adc3056cc29 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 7ea0078ea3b..6e1974f48b2 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<Target = pp::Printer> + 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<Target = pp::Printer> + 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 c5a73c31995..263081ea19e 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 d244897f8a5..01821ee833f 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 97d6b82de98..bf4693cd541 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 d5a42566e19..0bd2d423a29 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 6eeb028728c..3ee4fded749 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<P<Expr>>, } +#[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<Span>, bool /*is tuple*/), + Unnamed(Vec<Span>, 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 b66f7111ff0..3366378d38d 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_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 67bc86e4c90..b6bbc81732e 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -313,7 +313,7 @@ fn get_llvm_object_symbols( llvm::LLVMRustGetSymbols( buf.as_ptr(), buf.len(), - &mut *state as *mut &mut _ as *mut c_void, + std::ptr::addr_of_mut!(*state) as *mut c_void, callback, error_callback, ) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 23e6f054a7c..58c0765d814 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1079,7 +1079,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .map(|(arg_idx, val)| { let idx = val.unwrap_leaf().try_to_i32().unwrap(); if idx >= i32::try_from(total_len).unwrap() { - bx.sess().dcx().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds { + bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { span, name, arg_idx: arg_idx as u64, @@ -1138,24 +1138,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let val = bx.const_get_elt(vector, i as u64); match bx.const_to_opt_u128(val, true) { None => { - bx.sess().dcx().emit_err( - InvalidMonomorphization::ShuffleIndexNotConstant { - span, - name, - arg_idx, - }, - ); - None + bug!("typeck should have already ensured that these are const") } Some(idx) if idx >= total_len => { - bx.sess().dcx().emit_err( - InvalidMonomorphization::ShuffleIndexOutOfBounds { - span, - name, - arg_idx, - total_len, - }, - ); + bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx, + total_len, + }); None } Some(idx) => Some(bx.const_i32(idx as i32)), @@ -1184,10 +1175,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>( out_ty: arg_tys[2] } ); + let idx = bx + .const_to_opt_u128(args[1].immediate(), false) + .expect("typeck should have ensure that this is a const"); + if idx >= in_len.into() { + bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: 1, + total_len: in_len.into(), + }); + return Ok(bx.const_null(llret_ty)); + } return Ok(bx.insert_element( args[0].immediate(), args[2].immediate(), - args[1].immediate(), + bx.const_i32(idx as i32), )); } if name == sym::simd_extract { @@ -1195,7 +1198,19 @@ fn generic_simd_intrinsic<'ll, 'tcx>( ret_ty == in_elem, InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty } ); - return Ok(bx.extract_element(args[0].immediate(), args[1].immediate())); + let idx = bx + .const_to_opt_u128(args[1].immediate(), false) + .expect("typeck should have ensure that this is a const"); + if idx >= in_len.into() { + bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { + span, + name, + arg_idx: 1, + total_len: in_len.into(), + }); + return Ok(bx.const_null(llret_ty)); + } + return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32))); } if name == sym::simd_select { @@ -2091,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, } @@ -2101,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()), @@ -2113,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()), @@ -2125,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_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 35210b0b2e8..c84461e53eb 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -169,7 +169,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_pass_timings(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintPassTimings(&mut size as *mut usize); + let cstr = llvm::LLVMRustPrintPassTimings(std::ptr::addr_of_mut!(size)); if cstr.is_null() { println!("failed to get pass timings"); } else { @@ -182,7 +182,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_statistics(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintStatistics(&mut size as *mut usize); + let cstr = llvm::LLVMRustPrintStatistics(std::ptr::addr_of_mut!(size)); if cstr.is_null() { println!("failed to get pass stats"); } else { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 54e8ed85e32..1b2beac56a2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -435,7 +435,7 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess &tm, cpu_cstring.as_ptr(), callback, - &mut out as *mut &mut dyn PrintBackendInfo as *mut c_void, + std::ptr::addr_of_mut!(out) as *mut c_void, ); } } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index fa7719d8971..5ba66d1be43 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -106,14 +106,12 @@ codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of ` codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} -codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant - -codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len}) - codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}` codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}` +codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: SIMD index #{$arg_idx} is out of bounds (limit {$total_len}) + codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}` codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e42a8bd9ed9..a7ac502b248 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -797,16 +797,8 @@ pub enum InvalidMonomorphization<'tcx> { out_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = E0511)] - ShuffleIndexNotConstant { - #[primary_span] - span: Span, - name: Symbol, - arg_idx: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = E0511)] - ShuffleIndexOutOfBounds { + #[diag(codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds, code = E0511)] + SimdIndexOutOfBounds { #[primary_span] span: Span, name: Symbol, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 00007110938..9c7aadb81f8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -319,7 +319,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { targets: &SwitchTargets, ) { let discr = self.codegen_operand(bx, discr); + let discr_value = discr.immediate(); let switch_ty = discr.layout.ty; + // If our discriminant is a constant we can branch directly + if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) { + let target = targets.target_for_value(const_discr); + bx.br(helper.llbb_with_cleanup(self, target)); + return; + }; + let mut target_iter = targets.iter(); if target_iter.len() == 1 { // If there are two targets (one conditional, one fallback), emit `br` instead of @@ -330,14 +338,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if switch_ty == bx.tcx().types.bool { // Don't generate trivial icmps when switching on bool. match test_value { - 0 => bx.cond_br(discr.immediate(), llfalse, lltrue), - 1 => bx.cond_br(discr.immediate(), lltrue, llfalse), + 0 => bx.cond_br(discr_value, llfalse, lltrue), + 1 => bx.cond_br(discr_value, lltrue, llfalse), _ => bug!(), } } else { let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); let llval = bx.const_uint_big(switch_llty, test_value); - let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); + let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); bx.cond_br(cmp, lltrue, llfalse); } } else if self.cx.sess().opts.optimize == OptLevel::No @@ -362,11 +370,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ll2 = helper.llbb_with_cleanup(self, target2); let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); let llval = bx.const_uint_big(switch_llty, test_value1); - let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); + let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); bx.cond_br(cmp, ll1, ll2); } else { bx.switch( - discr.immediate(), + discr_value, helper.llbb_with_cleanup(self, targets.otherwise()), target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))), ); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f020616f6d8..1cb991b38f7 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -379,10 +379,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (input, input_len) = self.operand_to_simd(&args[0])?; let (dest, dest_len) = self.place_to_simd(dest)?; assert_eq!(input_len, dest_len, "Return vector length must match input length"); - assert!( - index < dest_len, - "Index `{index}` must be in bounds of vector with length {dest_len}" - ); + // Bounds are not checked by typeck so we have to do it ourselves. + if index >= input_len { + throw_ub_format!( + "`simd_insert` index {index} is out-of-bounds of vector with length {input_len}" + ); + } for i in 0..dest_len { let place = self.project_index(&dest, i)?; @@ -397,10 +399,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::simd_extract => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let (input, input_len) = self.operand_to_simd(&args[0])?; - assert!( - index < input_len, - "index `{index}` must be in bounds of vector with length {input_len}" - ); + // Bounds are not checked by typeck so we have to do it ourselves. + if index >= input_len { + throw_ub_format!( + "`simd_extract` index {index} is out-of-bounds of vector with length {input_len}" + ); + } self.copy_op(&self.project_index(&input, index)?, dest)?; } sym::likely | sym::unlikely | sym::black_box => { diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index adcb6ceaebf..32202ac3ede 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -429,7 +429,7 @@ impl<T> RwLock<T> { #[inline(always)] pub fn leak(&self) -> &T { let guard = self.read(); - let ret = unsafe { &*(&*guard as *const T) }; + let ret = unsafe { &*std::ptr::addr_of!(*guard) }; std::mem::forget(guard); ret } diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index e66cfbe6fb6..ffc8f782fd3 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 c82609503c1..bf99e9e6d5c 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 3ca0787ce8e..84f7dc4771a 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 0fdfa563138..ec1dd807d1a 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 7a888250ca1..0e07b41b43c 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::<Vec<_>>(); @@ -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 62d0deb2d3a..87ea8690ffe 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<TokenTree<TokenStre Question => 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<TokenTree<TokenStre escaped.extend(ch.escape_debug()); } let stream = [ - Ident(sym::doc, false), + Ident(sym::doc, IdentIsRaw::No), Eq, TokenKind::lit(token::Str, Symbol::intern(&escaped), None), ] @@ -259,7 +262,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => { 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<SmallVec<[tokenstream::TokenTree; 2]>> } 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 91c4dd732e3..78795e86fd5 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 18f6ae35054..1b2993dabdb 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 99875ec5405..6cb41be7c94 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, @@ -792,6 +791,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_intrinsic, Normal, template!(Word), ErrorFollowing, "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", ), + rustc_attr!( + rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, + "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93c183a65ef..8eea4b7d8a8 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/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 07bbaa1926e..b46a67d08eb 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<A>` in `impl<A, B> for C<B> in D<A>` 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_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e245dee4daf..7715f2ef43a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2437,6 +2437,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let suggestion = if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") }; suggs.push((sp, suggestion)) + } else if let GenericKind::Alias(ref p) = bound_kind + && let ty::Projection = p.kind(self.tcx) + && let DefKind::AssocTy = self.tcx.def_kind(p.def_id) + && let Some(ty::ImplTraitInTraitData::Trait { .. }) = + self.tcx.opt_rpitit_info(p.def_id) + { + // The lifetime found in the `impl` is longer than the one on the RPITIT. + // Do not suggest `<Type as Trait>::{opaque}: 'static`. } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) { let pred = format!("{bound_kind}: {lt_name}"); let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 92f7497362e..9f73d2e6812 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 d8e12c04f75..844f87c3f50 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -527,6 +527,11 @@ fn register_builtins(store: &mut LintStore) { "no longer needed, see #93367 \ <https://github.com/rust-lang/rust/issues/93367> for more information", ); + store.register_removed( + "const_patterns_without_partial_eq", + "converted into hard error, see RFC #3535 \ + <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 84a050a242a..1cddb45428c 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, @@ -2343,57 +2342,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<T: EnumSetType> { - /// __enumset_underlying: T::Repr, - /// } - /// - /// const CONST_SET: EnumSet<Enum8> = 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 <https://github.com/rust-lang/rust/issues/116122>", - }; -} - -declare_lint! { /// The `ambiguous_associated_items` lint detects ambiguity between /// [associated items] and [enum variants]. /// diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index f4dfbe059eb..9c7c46f2ad2 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -233,7 +233,7 @@ impl<'sess> OnDiskCache<'sess> { for (index, file) in files.iter().enumerate() { let index = SourceFileIndex(index as u32); - let file_ptr: *const SourceFile = &**file as *const _; + let file_ptr: *const SourceFile = std::ptr::addr_of!(**file); file_to_file_index.insert(file_ptr, index); let source_file_id = EncodedSourceFileId::new(tcx, file); file_index_to_stable_id.insert(index, source_file_id); @@ -835,7 +835,7 @@ pub struct CacheEncoder<'a, 'tcx> { impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { #[inline] fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex { - self.file_to_file_index[&(&*source_file as *const SourceFile)] + self.file_to_file_index[&std::ptr::addr_of!(*source_file)] } /// Encode something with additional information that allows to do some diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 4f9c9d85763..336c2dce114 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -61,7 +61,7 @@ impl<T> List<T> { // length) that is 64-byte aligned, thus featuring the necessary // trailing padding for elements with up to 64-byte alignment. static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign); - unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) } + unsafe { &*(std::ptr::addr_of!(EMPTY_SLICE) as *const List<T>) } } pub fn len(&self) -> usize { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f9a8795f5d6..641a278c1d3 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1150,39 +1150,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// the value, we will set and generate a branch to the appropriate /// pre-binding block. /// - /// If we find that *NONE* of the candidates apply, we branch to the - /// `otherwise_block`, setting it to `Some` if required. In principle, this - /// means that the input list was not exhaustive, though at present we - /// sometimes are not smart enough to recognize all exhaustive inputs. + /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`. /// /// It might be surprising that the input can be non-exhaustive. /// Indeed, initially, it is not, because all matches are /// exhaustive in Rust. But during processing we sometimes divide /// up the list of candidates and recurse with a non-exhaustive - /// list. This is important to keep the size of the generated code - /// under control. See [`Builder::test_candidates`] for more details. + /// list. This is how our lowering approach (called "backtracking + /// automaton" in the literature) works. + /// See [`Builder::test_candidates`] for more details. /// /// If `fake_borrows` is `Some`, then places which need fake borrows /// will be added to it. /// - /// For an example of a case where we set `otherwise_block`, even for an - /// exhaustive match, consider: - /// + /// For an example of how we use `otherwise_block`, consider: /// ``` - /// # fn foo(x: (bool, bool)) { - /// match x { - /// (true, true) => (), - /// (_, false) => (), - /// (false, true) => (), + /// # fn foo((x, y): (bool, bool)) -> u32 { + /// match (x, y) { + /// (true, true) => 1, + /// (_, false) => 2, + /// (false, true) => 3, /// } /// # } /// ``` + /// For this match, we generate something like: + /// ``` + /// # fn foo((x, y): (bool, bool)) -> u32 { + /// if x { + /// if y { + /// return 1 + /// } else { + /// // continue + /// } + /// } else { + /// // continue + /// } + /// if y { + /// if x { + /// // This is actually unreachable because the `(true, true)` case was handled above. + /// // continue + /// } else { + /// return 3 + /// } + /// } else { + /// return 2 + /// } + /// // this is the final `otherwise_block`, which is unreachable because the match was exhaustive. + /// unreachable!() + /// # } + /// ``` + /// + /// Every `continue` is an instance of branching to some `otherwise_block` somewhere deep within + /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`]. /// - /// For this match, we check if `x.0` matches `true` (for the first - /// arm). If it doesn't match, we check `x.1`. If `x.1` is `true` we check - /// if `x.0` matches `false` (for the third arm). In the (impossible at - /// runtime) case when `x.0` is now `true`, we branch to - /// `otherwise_block`. + /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller + /// code size at the expense of non-optimal code paths. #[instrument(skip(self, fake_borrows), level = "debug")] fn match_candidates<'pat>( &mut self, @@ -1557,18 +1579,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// This is the most subtle part of the matching algorithm. At - /// this point, the input candidates have been fully simplified, - /// and so we know that all remaining match-pairs require some - /// sort of test. To decide what test to perform, we take the highest - /// priority candidate (the first one in the list, as of January 2021) - /// and extract the first match-pair from the list. From this we decide - /// what kind of test is needed using [`Builder::test`], defined in the - /// [`test` module](mod@test). + /// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at + /// least one match pair. We currently simply pick the test corresponding to the first match + /// pair of the first candidate in the list. /// - /// *Note:* taking the first match pair is somewhat arbitrary, and - /// we might do better here by choosing more carefully what to - /// test. + /// *Note:* taking the first match pair is somewhat arbitrary, and we might do better here by + /// choosing more carefully what to test. /// /// For example, consider the following possible match-pairs: /// @@ -1580,121 +1596,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// [`Switch`]: TestKind::Switch /// [`SwitchInt`]: TestKind::SwitchInt /// [`Range`]: TestKind::Range - /// - /// Once we know what sort of test we are going to perform, this - /// test may also help us winnow down our candidates. So we walk over - /// the candidates (from high to low priority) and check. This - /// gives us, for each outcome of the test, a transformed list of - /// candidates. For example, if we are testing `x.0`'s variant, - /// and we have a candidate `(x.0 @ Some(v), x.1 @ 22)`, - /// then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)`. - /// Note that the first match-pair is now simpler (and, in fact, irrefutable). - /// - /// But there may also be candidates that the test just doesn't - /// apply to. The classical example involves wildcards: - /// - /// ``` - /// # let (x, y, z) = (true, true, true); - /// match (x, y, z) { - /// (true , _ , true ) => true, // (0) - /// (_ , true , _ ) => true, // (1) - /// (false, false, _ ) => false, // (2) - /// (true , _ , false) => false, // (3) - /// } - /// # ; - /// ``` - /// - /// In that case, after we test on `x`, there are 2 overlapping candidate - /// sets: - /// - /// - If the outcome is that `x` is true, candidates 0, 1, and 3 - /// - If the outcome is that `x` is false, candidates 1 and 2 - /// - /// Here, the traditional "decision tree" method would generate 2 - /// separate code-paths for the 2 separate cases. - /// - /// In some cases, this duplication can create an exponential amount of - /// code. This is most easily seen by noticing that this method terminates - /// with precisely the reachable arms being reachable - but that problem - /// is trivially NP-complete: - /// - /// ```ignore (illustrative) - /// match (var0, var1, var2, var3, ...) { - /// (true , _ , _ , false, true, ...) => false, - /// (_ , true, true , false, _ , ...) => false, - /// (false, _ , false, false, _ , ...) => false, - /// ... - /// _ => true - /// } - /// ``` - /// - /// Here the last arm is reachable only if there is an assignment to - /// the variables that does not match any of the literals. Therefore, - /// compilation would take an exponential amount of time in some cases. - /// - /// That kind of exponential worst-case might not occur in practice, but - /// our simplistic treatment of constants and guards would make it occur - /// in very common situations - for example [#29740]: - /// - /// ```ignore (illustrative) - /// match x { - /// "foo" if foo_guard => ..., - /// "bar" if bar_guard => ..., - /// "baz" if baz_guard => ..., - /// ... - /// } - /// ``` - /// - /// [#29740]: https://github.com/rust-lang/rust/issues/29740 - /// - /// Here we first test the match-pair `x @ "foo"`, which is an [`Eq` test]. - /// - /// [`Eq` test]: TestKind::Eq - /// - /// It might seem that we would end up with 2 disjoint candidate - /// sets, consisting of the first candidate or the other two, but our - /// algorithm doesn't reason about `"foo"` being distinct from the other - /// constants; it considers the latter arms to potentially match after - /// both outcomes, which obviously leads to an exponential number - /// of tests. - /// - /// To avoid these kinds of problems, our algorithm tries to ensure - /// the amount of generated tests is linear. When we do a k-way test, - /// we return an additional "unmatched" set alongside the obvious `k` - /// sets. When we encounter a candidate that would be present in more - /// than one of the sets, we put it and all candidates below it into the - /// "unmatched" set. This ensures these `k+1` sets are disjoint. - /// - /// After we perform our test, we branch into the appropriate candidate - /// set and recurse with `match_candidates`. These sub-matches are - /// obviously non-exhaustive - as we discarded our otherwise set - so - /// we set their continuation to do `match_candidates` on the - /// "unmatched" set (which is again non-exhaustive). - /// - /// If you apply this to the above test, you basically wind up - /// with an if-else-if chain, testing each candidate in turn, - /// which is precisely what we want. - /// - /// In addition to avoiding exponential-time blowups, this algorithm - /// also has the nice property that each guard and arm is only generated - /// once. - fn test_candidates<'pat, 'b, 'c>( + fn pick_test( &mut self, - span: Span, - scrutinee_span: Span, - mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], - start_block: BasicBlock, - otherwise_block: BasicBlock, + candidates: &mut [&mut Candidate<'_, 'tcx>], fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, - ) { - // extract the match-pair from the highest priority candidate + ) -> (PlaceBuilder<'tcx>, Test<'tcx>) { + // Extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; let mut test = self.test(match_pair); let match_place = match_pair.place.clone(); - // most of the time, the test to perform is simply a function - // of the main candidate; but for a test like SwitchInt, we - // may want to add cases based on the candidates that are + debug!(?test, ?match_pair); + // Most of the time, the test to perform is simply a function of the main candidate; but for + // a test like SwitchInt, we may want to add cases based on the candidates that are // available match test.kind { TestKind::SwitchInt { switch_ty: _, ref mut options } => { @@ -1721,20 +1635,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fb.insert(resolved_place); } - // perform the test, branching to one of N blocks. For each of - // those N possible outcomes, create a (initially empty) - // vector of candidates. Those are the candidates that still - // apply if the test has that particular outcome. - debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair); + (match_place, test) + } + + /// Given a test, we sort the input candidates into several buckets. If a candidate only matches + /// in one of the branches of `test`, we move it there. If it could match in more than one of + /// the branches of `test`, we stop sorting candidates. + /// + /// This returns a pair of + /// - the candidates that weren't sorted; + /// - for each possible outcome of the test, the candidates that match in that outcome. + /// + /// Moreover, we transform the branched candidates to reflect the fact that we know which + /// outcome of `test` occurred. + /// + /// For example: + /// ``` + /// # let (x, y, z) = (true, true, true); + /// match (x, y, z) { + /// (true , _ , true ) => true, // (0) + /// (false, false, _ ) => false, // (1) + /// (_ , true , _ ) => true, // (2) + /// (true , _ , false) => false, // (3) + /// } + /// # ; + /// ``` + /// + /// Assume we are testing on `x`. There are 2 overlapping candidate sets: + /// - If the outcome is that `x` is true, candidates 0, 2, and 3 + /// - If the outcome is that `x` is false, candidates 1 and 2 + /// + /// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes + /// into outcome `x == false`, and candidate 2 and 3 remain unsorted. + /// + /// The sorted candidates are transformed: + /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`; + /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. + fn sort_candidates<'b, 'c, 'pat>( + &mut self, + match_place: &PlaceBuilder<'tcx>, + test: &Test<'tcx>, + mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], + ) -> (&'b mut [&'c mut Candidate<'pat, 'tcx>], Vec<Vec<&'b mut Candidate<'pat, 'tcx>>>) { + // For each of the N possible outcomes, create a (initially empty) vector of candidates. + // Those are the candidates that apply if the test has that particular outcome. let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![]; target_candidates.resize_with(test.targets(), Default::default); let total_candidate_count = candidates.len(); - // Sort the candidates into the appropriate vector in - // `target_candidates`. Note that at some point we may - // encounter a candidate where the test is not relevant; at - // that point, we stop sorting. + // Sort the candidates into the appropriate vector in `target_candidates`. Note that at some + // point we may encounter a candidate where the test is not relevant; at that point, we stop + // sorting. while let Some(candidate) = candidates.first_mut() { let Some(idx) = self.sort_candidate(&match_place, &test, candidate) else { break; @@ -1743,7 +1695,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target_candidates[idx].push(candidate); candidates = rest; } - // at least the first candidate ought to be tested + + // At least the first candidate ought to be tested assert!( total_candidate_count > candidates.len(), "{total_candidate_count}, {candidates:#?}" @@ -1751,16 +1704,130 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("tested_candidates: {}", total_candidate_count - candidates.len()); debug!("untested_candidates: {}", candidates.len()); + (candidates, target_candidates) + } + + /// This is the most subtle part of the match lowering algorithm. At this point, the input + /// candidates have been fully simplified, so all remaining match-pairs require some sort of + /// test. + /// + /// Once we pick what sort of test we are going to perform, this test will help us winnow down + /// our candidates. So we walk over the candidates (from high to low priority) and check. We + /// compute, for each outcome of the test, a transformed list of candidates. If a candidate + /// matches in a single branch of our test, we add it to the corresponding outcome. We also + /// transform it to record the fact that we know which outcome occurred. + /// + /// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1 + /// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the + /// branch corresponding to `Some`. To ensure we make progress, we always pick a test that + /// results in simplifying the first candidate. + /// + /// But there may also be candidates that the test doesn't + /// apply to. The classical example is wildcards: + /// + /// ``` + /// # let (x, y, z) = (true, true, true); + /// match (x, y, z) { + /// (true , _ , true ) => true, // (0) + /// (false, false, _ ) => false, // (1) + /// (_ , true , _ ) => true, // (2) + /// (true , _ , false) => false, // (3) + /// } + /// # ; + /// ``` + /// + /// Here, the traditional "decision tree" method would generate 2 separate code-paths for the 2 + /// possible values of `x`. This would however duplicate some candidates, which would need to be + /// lowered several times. + /// + /// In some cases, this duplication can create an exponential amount of + /// code. This is most easily seen by noticing that this method terminates + /// with precisely the reachable arms being reachable - but that problem + /// is trivially NP-complete: + /// + /// ```ignore (illustrative) + /// match (var0, var1, var2, var3, ...) { + /// (true , _ , _ , false, true, ...) => false, + /// (_ , true, true , false, _ , ...) => false, + /// (false, _ , false, false, _ , ...) => false, + /// ... + /// _ => true + /// } + /// ``` + /// + /// Here the last arm is reachable only if there is an assignment to + /// the variables that does not match any of the literals. Therefore, + /// compilation would take an exponential amount of time in some cases. + /// + /// In rustc, we opt instead for the "backtracking automaton" approach. This guarantees we never + /// duplicate a candidate (except in the presence of or-patterns). In fact this guarantee is + /// ensured by the fact that we carry around `&mut Candidate`s which can't be duplicated. + /// + /// To make this work, whenever we decide to perform a test, if we encounter a candidate that + /// could match in more than one branch of the test, we stop. We generate code for the test and + /// for the candidates in its branches; the remaining candidates will be tested if the + /// candidates in the branches fail to match. + /// + /// For example, if we test on `x` in the following: + /// ``` + /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 { + /// match (x, y, z) { + /// (true , _ , true ) => 0, + /// (false, false, _ ) => 1, + /// (_ , true , _ ) => 2, + /// (true , _ , false) => 3, + /// } + /// # } + /// ``` + /// this function generates code that looks more of less like: + /// ``` + /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 { + /// if x { + /// match (y, z) { + /// (_, true) => return 0, + /// _ => {} // continue matching + /// } + /// } else { + /// match (y, z) { + /// (false, _) => return 1, + /// _ => {} // continue matching + /// } + /// } + /// // the block here is `remainder_start` + /// match (x, y, z) { + /// (_ , true , _ ) => 2, + /// (true , _ , false) => 3, + /// _ => unreachable!(), + /// } + /// # } + /// ``` + fn test_candidates<'pat, 'b, 'c>( + &mut self, + span: Span, + scrutinee_span: Span, + candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], + start_block: BasicBlock, + otherwise_block: BasicBlock, + fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, + ) { + // Extract the match-pair from the highest priority candidate and build a test from it. + let (match_place, test) = self.pick_test(candidates, fake_borrows); + + // For each of the N possible test outcomes, build the vector of candidates that applies if + // the test has that particular outcome. + let (remaining_candidates, target_candidates) = + self.sort_candidates(&match_place, &test, candidates); + // The block that we should branch to if none of the // `target_candidates` match. - let remainder_start = if !candidates.is_empty() { + let remainder_start = if !remaining_candidates.is_empty() { let remainder_start = self.cfg.start_new_block(); self.match_candidates( span, scrutinee_span, remainder_start, otherwise_block, - candidates, + remaining_candidates, fake_borrows, ); remainder_start diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 48b93ce0ac5..101f1cb9f2f 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -768,6 +768,14 @@ pub struct TypeNotStructural<'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> { #[primary_span] @@ -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 c77c80d9f4b..09727f9b71b 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/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 2009539d4d0..36546a03cdf 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -421,6 +421,10 @@ impl<'tcx> Inliner<'tcx> { callee_attrs: &CodegenFnAttrs, cross_crate_inlinable: bool, ) -> Result<(), &'static str> { + if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) { + return Err("#[rustc_no_mir_inline]"); + } + if let InlineAttr::Never = callee_attrs.inline { return Err("never inline hint"); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 577b8f2080f..2e11da4d585 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -482,17 +482,40 @@ impl<'tcx> Validator<'_, 'tcx> { match op { BinOp::Div | BinOp::Rem => { if lhs_ty.is_integral() { + let sz = lhs_ty.primitive_size(self.tcx); // Integer division: the RHS must be a non-zero const. - let const_val = match rhs { + let rhs_val = match rhs { Operand::Constant(c) => { - c.const_.try_eval_bits(self.tcx, self.param_env) + c.const_.try_eval_scalar_int(self.tcx, self.param_env) } _ => None, }; - match const_val { + match rhs_val.map(|x| x.try_to_uint(sz).unwrap()) { + // for the zero test, int vs uint does not matter Some(x) if x != 0 => {} // okay _ => return Err(Unpromotable), // value not known or 0 -- not okay } + // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`. + if lhs_ty.is_signed() { + match rhs_val.map(|x| x.try_to_int(sz).unwrap()) { + Some(-1) | None => { + // The RHS is -1 or unknown, so we have to be careful. + // But is the LHS int::MIN? + let lhs_val = match lhs { + Operand::Constant(c) => c + .const_ + .try_eval_scalar_int(self.tcx, self.param_env), + _ => None, + }; + let lhs_min = sz.signed_int_min(); + match lhs_val.map(|x| x.try_to_int(sz).unwrap()) { + Some(x) if x != lhs_min => {} // okay + _ => return Err(Unpromotable), // value not known or int::MIN -- not okay + } + } + _ => {} + } + } } } // The remaining operations can never fail. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index c768ea93b5f..dc9f5bad765 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 a136abaa28b..3b4e05332fa 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<token::TokenKind>)] = &[ (" ", "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 0cc2170714c..517e3d82787 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<AssocOp>, - ) -> 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::<i32>().is_err() @@ -1294,7 +1296,7 @@ impl<'a> Parser<'a> { { // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish // suggestion being the only one to apply is high. - return false; + return Recovered::No; } return match (op.node, &outer_op.node) { // `x == y == z` @@ -1313,7 +1315,7 @@ impl<'a> 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 8826c06bebd..1ad637451b1 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<Expr>, lo: Span) -> PResult<'a, P<Expr>> { 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<ExprField> { 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 77381ef4626..2e049ca908f 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<T>;` } 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<FieldDef>, /* recovered */ bool)> { + ) -> PResult<'a, (ThinVec<FieldDef>, 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<Param>> { // 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 dea2b9e6ca7..29dd2eeb56a 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<Recovered> 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<T>, bool /* trailing */, bool /* recovered */)> { + ) -> PResult<'a, (ThinVec<T>, 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<T>, bool /* trailing */, bool /* recovered */)> { + ) -> PResult<'a, (ThinVec<T>, 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<T>, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec<T>, 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<T>, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec<T>, 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<T>, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec<T>, Trailing)> { self.parse_unspanned_seq( &token::OpenDelim(delim), &token::CloseDelim(delim), @@ -1034,7 +1054,7 @@ impl<'a> Parser<'a> { fn parse_paren_comma_seq<T>( &mut self, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> { + ) -> PResult<'a, (ThinVec<T>, 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 071d6b72f3b..f1572a18a8b 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 75fc013d3e6..2ede19b11e0 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 681039999a6..6e7bbe7e06d 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 1bae5b32240..ee02b69c614 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 23a92e6dd3d..e3fe535bd5f 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_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d64a3b43aad..222dd69dbc4 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 4583f991cab..7e7424be303 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<LocalDefId>; +#[derive(Copy, Clone)] +pub enum UsePrelude { + No, + Yes, +} + +impl From<UsePrelude> 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<T>, + mut visitor: impl FnMut(&mut Self, Scope<'a>, UsePrelude, SyntaxContext) -> Option<T>, ) -> Option<T> { // 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_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46472a131ff..609ab054da2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1441,6 +1441,7 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_never_returns_null_ptr, + rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, rustc_object_lifetime_default, diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index f13058ebc82..097039d6c73 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -14,7 +14,7 @@ fn simulator_targets_set_abi() { aarch64_apple_watchos_sim::target(), ]; - for target in all_sim_targets { + for target in &all_sim_targets { assert_eq!(target.abi, "sim") } } 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 22f6ee81055..70e40f60f22 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 84d9ceac04d..ca0db5e5640 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 9f4a432c6fa..61b6d7a63e3 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 e5518c6daec..7afdb87b62e 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 3619d02438d..e82171de378 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -320,22 +320,25 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let mut errors = fulfill_cx.select_where_possible(infcx); errors.pop().map(|err| err.obligation) } else { - obligations.iter().cloned().find(|obligation| { - // We use `evaluate_root_obligation` to correctly track intercrate - // ambiguity clauses. We cannot use this in the new solver. - let evaluation_result = selcx.evaluate_root_obligation(obligation); - - match evaluation_result { - Ok(result) => !result.may_apply(), - // If overflow occurs, we need to conservatively treat the goal as possibly holding, - // since there can be instantiations of this goal that don't overflow and result in - // success. This isn't much of a problem in the old solver, since we treat overflow - // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>), - // but in the new solver, this is very important for correctness, since overflow - // *must* be treated as ambiguity for completeness. - Err(_overflow) => false, - } - }) + obligations + .iter() + .find(|obligation| { + // We use `evaluate_root_obligation` to correctly track intercrate + // ambiguity clauses. We cannot use this in the new solver. + let evaluation_result = selcx.evaluate_root_obligation(obligation); + + match evaluation_result { + Ok(result) => !result.may_apply(), + // If overflow occurs, we need to conservatively treat the goal as possibly holding, + // since there can be instantiations of this goal that don't overflow and result in + // success. This isn't much of a problem in the old solver, since we treat overflow + // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>), + // but in the new solver, this is very important for correctness, since overflow + // *must* be treated as ambiguity for completeness. + Err(_overflow) => false, + } + }) + .cloned() } } @@ -598,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<bool> 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<Ty<'tcx>>), } @@ -751,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> @@ -769,7 +787,7 @@ where } fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> { - 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 9eec60ea06c..32447aca390 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/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 6272f793f40..0f7d8d7e083 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -208,7 +208,7 @@ where if TLV.is_set() { Err(Error::from("StableMIR already running")) } else { - let ptr: *const () = &context as *const &_ as _; + let ptr: *const () = std::ptr::addr_of!(context) as _; TLV.set(&Cell::new(ptr), || Ok(f())) } } diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 3b29c144a89..0421a12b3a9 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -176,7 +176,7 @@ impl<T: ?Sized> ThinBox<T> { fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> { // SAFETY: both types are transparent to `NonNull<u8>` - unsafe { &*((&self.ptr) as *const WithOpaqueHeader as *const WithHeader<_>) } + unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b84273848ee..45e93feb6c5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,6 +92,7 @@ #![warn(multiple_supertrait_upcastable)] #![allow(internal_features)] #![allow(rustdoc::redundant_explicit_links)] +#![deny(ffi_unwind_calls)] // // Library features: // tidy-alphabetical-start diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c3d0019be39..084157b97ab 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1969,7 +1969,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { // Copy value as bytes ptr::copy_nonoverlapping( - &*src as *const T as *const u8, + core::ptr::addr_of!(*src) as *const u8, ptr::addr_of_mut!((*ptr).value) as *mut u8, value_size, ); @@ -2440,7 +2440,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Rc<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized, A: Allocator> fmt::Pointer for Rc<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&**self as *const T), f) + fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 524aa35e045..00f47f5c6e0 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1914,7 +1914,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { // Copy value as bytes ptr::copy_nonoverlapping( - &*src as *const T as *const u8, + core::ptr::addr_of!(*src) as *const u8, ptr::addr_of_mut!((*ptr).data) as *mut u8, value_size, ); @@ -3265,7 +3265,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Arc<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized, A: Allocator> fmt::Pointer for Arc<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&**self as *const T), f) + fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) } } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 248943cf022..20186a2de0f 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -4,6 +4,7 @@ use crate::ffi::c_char; use crate::fmt; use crate::intrinsics; use crate::ops; +use crate::ptr::addr_of; use crate::slice; use crate::slice::memchr; use crate::str; @@ -603,7 +604,7 @@ impl CStr { pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. - unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } + unsafe { &*(addr_of!(self.inner) as *const [u8]) } } /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8. diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index e42b2315ea5..f9d89795a99 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2706,13 +2706,25 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) macro_rules! assert_unsafe_precondition { ($message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => { { + // #[cfg(bootstrap)] (this comment) // When the standard library is compiled with debug assertions, we want the check to inline for better performance. // This is important when working on the compiler, which is compiled with debug assertions locally. // When not compiled with debug assertions (so the precompiled std) we outline the check to minimize the compile // time impact when debug assertions are disabled. - // It is not clear whether that is the best solution, see #120848. - #[cfg_attr(debug_assertions, inline(always))] - #[cfg_attr(not(debug_assertions), inline(never))] + // The proper solution to this is the `#[rustc_no_mir_inline]` below, but we still want decent performance for cfg(bootstrap). + #[cfg_attr(all(debug_assertions, bootstrap), inline(always))] + #[cfg_attr(all(not(debug_assertions), bootstrap), inline(never))] + + // This check is inlineable, but not by the MIR inliner. + // The reason for this is that the MIR inliner is in an exceptionally bad position + // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`, + // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and + // would be bad for compile times. + // + // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without + // inlining the check. If it's `true`, it can inline it and get significantly better performance. + #[cfg_attr(not(bootstrap), rustc_no_mir_inline)] + #[cfg_attr(not(bootstrap), inline)] #[rustc_nounwind] fn precondition_check($($name:$ty),*) { if !$e { diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 64bd5b3e2b6..1a5f9e62654 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -2,6 +2,7 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedF use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::num::NonZero; use crate::ops::{ControlFlow, Try}; +use crate::ptr::addr_of; use crate::{array, fmt}; /// An iterator that uses `f` to both filter and map elements from `iter`. @@ -98,9 +99,8 @@ where // SAFETY: Loop conditions ensure the index is in bounds. unsafe { - let opt_payload_at: *const MaybeUninit<B> = (&val as *const Option<B>) - .byte_add(core::mem::offset_of!(Option<B>, Some.0)) - .cast(); + let opt_payload_at: *const MaybeUninit<B> = + addr_of!(val).byte_add(core::mem::offset_of!(Option<B>, Some.0)).cast(); let dst = guard.array.as_mut_ptr().add(idx); crate::ptr::copy_nonoverlapping(opt_payload_at, dst, 1); crate::mem::forget(val); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 456d88122af..49cead680e3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -106,6 +106,7 @@ #![allow(incomplete_features)] #![warn(multiple_supertrait_upcastable)] #![allow(internal_features)] +#![deny(ffi_unwind_calls)] // Do not check link redundancy on bootstraping phase #![allow(rustdoc::redundant_explicit_links)] // diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 90b3341f0ad..fc5b08c9801 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1553,7 +1553,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::<T>()); + copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::<T>()); // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 031666fb012..1ad81fcfcfe 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -146,6 +146,9 @@ impl<T> [T] { /// ``` /// let a = [1, 2, 3]; /// assert!(!a.is_empty()); + /// + /// let b: &[i32] = &[]; + /// assert!(b.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] @@ -185,6 +188,9 @@ impl<T> [T] { /// *first = 5; /// } /// assert_eq!(x, &[5, 1, 2]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.first_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] @@ -297,7 +303,7 @@ impl<T> [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns a mutable reference to the last item in the slice. + /// Returns a mutable reference to the last item in the slice, or `None` if it is empty. /// /// # Examples /// @@ -308,6 +314,9 @@ impl<T> [T] { /// *last = 10; /// } /// assert_eq!(x, &[0, 1, 10]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.last_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index d05458a6944..610966625b5 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -36,6 +36,7 @@ #![feature(strict_provenance)] #![recursion_limit = "256"] #![allow(internal_features)] +#![deny(ffi_unwind_calls)] #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 6c99e8c3620..9757653e02c 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -21,7 +21,7 @@ mod libc { fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { // Work with an actual instance of the type since using a null pointer is UB let base = (addr as *const libc::sockaddr_un).addr(); - let path = (&addr.sun_path as *const libc::c_char).addr(); + let path = core::ptr::addr_of!(addr.sun_path).addr(); path - base } @@ -98,7 +98,7 @@ impl SocketAddr { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?; SocketAddr::from_parts(addr, len) } } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 218536689fd..1d279d6adbc 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg: libc::msghdr = zeroed(); - msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); msg.msg_iovlen = bufs.len() as _; @@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to( if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg: libc::msghdr = zeroed(); - msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_iovlen = bufs.len() as _; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 3b7b610fdf9..0b4d955294c 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -91,7 +91,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?; Ok(socket) } @@ -124,7 +124,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; cvt(libc::bind( socket.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, + core::ptr::addr_of!(socket_addr.addr) as *const _, socket_addr.len as _, ))?; Ok(socket) @@ -206,7 +206,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; } Ok(()) } @@ -238,7 +238,7 @@ impl UnixDatagram { unsafe { cvt(libc::connect( self.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, + core::ptr::addr_of!(socket_addr.addr) as *const _, socket_addr.len, ))?; } @@ -505,7 +505,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - &addr as *const _ as *const _, + core::ptr::addr_of!(addr) as *const _, len, ))?; Ok(count as usize) @@ -540,7 +540,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - &socket_addr.addr as *const _ as *const _, + core::ptr::addr_of!(socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(count as usize) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index d64a43bc20b..31286a906ea 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -99,7 +99,11 @@ impl UnixListener { )))] const backlog: libc::c_int = libc::SOMAXCONN; - cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind( + inner.as_inner().as_raw_fd(), + core::ptr::addr_of!(addr) as *const _, + len as _, + ))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) @@ -139,7 +143,7 @@ impl UnixListener { const backlog: libc::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, + core::ptr::addr_of!(socket_addr.addr) as *const _, socket_addr.len as _, ))?; cvt(libc::listen(inner.as_raw_fd(), backlog))?; @@ -174,7 +178,7 @@ impl UnixListener { pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; let addr = SocketAddr::from_parts(storage, len)?; Ok((UnixStream(sock), addr)) } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index e117f616caf..b1cd504e219 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -96,7 +96,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; Ok(UnixStream(inner)) } } @@ -130,7 +130,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, + core::ptr::addr_of!(socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(UnixStream(inner)) diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index 6a0cc2d2c48..6efa74182cc 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -62,7 +62,7 @@ pub mod impl_linux { socket.as_raw_fd(), SOL_SOCKET, SO_PEERCRED, - &mut ucred as *mut ucred as *mut c_void, + core::ptr::addr_of_mut!(ucred) as *mut c_void, &mut ucred_size, ); @@ -122,7 +122,7 @@ pub mod impl_mac { socket.as_raw_fd(), SOL_LOCAL, LOCAL_PEERPID, - &mut pid as *mut pid_t as *mut c_void, + core::ptr::addr_of_mut!(pid) as *mut c_void, &mut pid_size, ); diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 66b4ec37c8e..ef701d3867a 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -502,7 +502,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let data_ptr = &mut data as *mut _ as *mut u8; + let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8; // SAFETY: // // Access to the union's fields: this is `std` and we know that the `r#try` diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index f6a7c0a9f75..ca62179e95b 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -165,6 +165,8 @@ pub use core::sync::Exclusive; pub use self::barrier::{Barrier, BarrierWaitResult}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::condvar::{Condvar, WaitTimeoutResult}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::mutex::MappedMutexGuard; #[stable(feature = "rust1", since = "1.0.0")] pub use self::mutex::{Mutex, MutexGuard}; #[stable(feature = "rust1", since = "1.0.0")] @@ -172,6 +174,8 @@ pub use self::mutex::{Mutex, MutexGuard}; pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 33f768dcbe9..1b82713edc7 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -182,7 +182,11 @@ impl<T> Channel<T> { // Prepare for blocking until a receiver wakes us up. let oper = Operation::hook(token); let mut packet = Packet::<T>::message_on_stack(msg); - inner.senders.register_with_packet(oper, &mut packet as *mut Packet<T> as *mut (), cx); + inner.senders.register_with_packet( + oper, + core::ptr::addr_of_mut!(packet) as *mut (), + cx, + ); inner.receivers.notify(); drop(inner); @@ -251,7 +255,7 @@ impl<T> Channel<T> { let mut packet = Packet::<T>::empty_on_stack(); inner.receivers.register_with_packet( oper, - &mut packet as *mut Packet<T> as *mut (), + core::ptr::addr_of_mut!(packet) as *mut (), cx, ); inner.senders.notify(); diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 920143b7ac7..fa91f9d907a 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -3,7 +3,10 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; +use crate::ptr::NonNull; use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys::locks as sys; @@ -213,6 +216,47 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {} #[stable(feature = "mutexguard", since = "1.19.0")] unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} +/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a +/// subfield of the protected data. When this structure is dropped (falls out +/// of scope), the lock will be unlocked. +/// +/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the +/// former cannot be used with [`Condvar`], since that +/// could introduce soundness issues if the locked object is modified by another +/// thread while the `Mutex` is unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// [`Deref`] and [`DerefMut`] implementations. +/// +/// This structure is created by the [`map`] and [`try_map`] methods on +/// [`MutexGuard`]. +/// +/// [`map`]: MutexGuard::map +/// [`try_map`]: MutexGuard::try_map +/// [`Condvar`]: crate::sync::Condvar +#[must_use = "if unused the Mutex will immediately unlock"] +#[must_not_suspend = "holding a MappedMutexGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +#[clippy::has_significant_drop] +pub struct MappedMutexGuard<'a, T: ?Sized + 'a> { + // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a + // `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops. + // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field + // below for the correct variance over `T` (invariance). + data: NonNull<T>, + inner: &'a sys::Mutex, + poison_flag: &'a poison::Flag, + poison: poison::Guard, + _variance: PhantomData<&'a mut T>, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {} +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {} + impl<T> Mutex<T> { /// Creates a new mutex in an unlocked state ready for use. /// @@ -550,3 +594,178 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.lock.poison } + +impl<'a, T: ?Sized> MutexGuard<'a, T> { + /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `Mutex` is already locked, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MutexGuard::map(...)`. A method would interfere with methods of the + /// same name on the contents of the `MutexGuard` used through `Deref`. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); + let orig = ManuallyDrop::new(orig); + MappedMutexGuard { + data, + inner: &orig.lock.inner, + poison_flag: &orig.lock.poison, + poison: orig.poison.clone(), + _variance: PhantomData, + } + } + + /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `Mutex` is already locked, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MutexGuard::try_map(...)`. A method would interfere with methods of the + /// same name on the contents of the `MutexGuard` used through `Deref`. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { &mut *orig.lock.data.get() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedMutexGuard { + data, + inner: &orig.lock.inner, + poison_flag: &orig.lock.poison, + poison: orig.poison.clone(), + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { self.data.as_mut() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> { + #[inline] + fn drop(&mut self) { + unsafe { + self.poison_flag.done(&self.poison); + self.inner.unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl<'a, T: ?Sized> MappedMutexGuard<'a, T> { + /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `Mutex` is already locked, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedMutexGuard::map(...)`. A method would interfere with methods of the + /// same name on the contents of the `MutexGuard` used through `Deref`. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_mut() })); + let orig = ManuallyDrop::new(orig); + MappedMutexGuard { + data, + inner: orig.inner, + poison_flag: orig.poison_flag, + poison: orig.poison.clone(), + _variance: PhantomData, + } + } + + /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `Mutex` is already locked, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedMutexGuard::try_map(...)`. A method would interfere with methods of the + /// same name on the contents of the `MutexGuard` used through `Deref`. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_mut() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedMutexGuard { + data, + inner: orig.inner, + poison_flag: orig.poison_flag, + poison: orig.poison.clone(), + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs index 1786a3c09ff..19ec096c593 100644 --- a/library/std/src/sync/mutex/tests.rs +++ b/library/std/src/sync/mutex/tests.rs @@ -1,6 +1,6 @@ use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::mpsc::channel; -use crate::sync::{Arc, Condvar, Mutex}; +use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError}; use crate::thread; struct Packet<T>(Arc<(Mutex<T>, Condvar)>); @@ -189,6 +189,21 @@ fn test_mutex_arc_poison() { } #[test] +fn test_mutex_arc_poison_mapped() { + let arc = Arc::new(Mutex::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _ = thread::spawn(move || { + let lock = arc2.lock().unwrap(); + let lock = MutexGuard::map(lock, |val| val); + assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex + }) + .join(); + assert!(arc.lock().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] fn test_mutex_arc_nested() { // Tests nested mutexes and access // to underlying data. @@ -236,3 +251,77 @@ fn test_mutex_unsized() { let comp: &[i32] = &[4, 2, 5]; assert_eq!(&*mutex.lock().unwrap(), comp); } + +#[test] +fn test_mapping_mapped_guard() { + let arr = [0; 4]; + let mut lock = Mutex::new(arr); + let guard = lock.lock().unwrap(); + let guard = MutexGuard::map(guard, |arr| &mut arr[..2]); + let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]); + assert_eq!(guard.len(), 1); + guard[0] = 42; + drop(guard); + assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); +} + +#[test] +fn panic_while_mapping_unlocked_poison() { + let lock = Mutex::new(()); + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.lock().unwrap(); + let _guard = MutexGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_lock() { + Ok(_) => panic!("panicking in a MutexGuard::map closure should poison the Mutex"), + Err(TryLockError::WouldBlock) => { + panic!("panicking in a MutexGuard::map closure should unlock the mutex") + } + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.lock().unwrap(); + let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_lock() { + Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"), + Err(TryLockError::WouldBlock) => { + panic!("panicking in a MutexGuard::try_map closure should unlock the mutex") + } + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.lock().unwrap(); + let guard = MutexGuard::map::<(), _>(guard, |val| val); + let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_lock() { + Ok(_) => panic!("panicking in a MappedMutexGuard::map closure should poison the Mutex"), + Err(TryLockError::WouldBlock) => { + panic!("panicking in a MappedMutexGuard::map closure should unlock the mutex") + } + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.lock().unwrap(); + let guard = MutexGuard::map::<(), _>(guard, |val| val); + let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_lock() { + Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"), + Err(TryLockError::WouldBlock) => { + panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex") + } + Err(TryLockError::Poisoned(_)) => {} + } + + drop(lock); +} diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 1e978bec4b4..3c51389fa34 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -78,6 +78,7 @@ impl Flag { } } +#[derive(Clone)] pub struct Guard { #[cfg(panic = "unwind")] panicking: bool, diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index c5d846b85aa..0b3d25c3298 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -3,6 +3,8 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; @@ -105,7 +107,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a - // `Ref` argument doesn't hold immutability for its whole scope, only until it drops. + // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` // is preferable over `const* T` to allow for niche optimization. data: NonNull<T>, @@ -144,6 +146,67 @@ impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {} #[stable(feature = "rwlock_guard_sync", since = "1.23.0")] unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} +/// RAII structure used to release the shared read access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`try_map`] methods +/// on [`RwLockReadGuard`]. +/// +/// [`map`]: RwLockReadGuard::map +/// [`try_map`]: RwLockReadGuard::try_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +#[clippy::has_significant_drop] +pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> { + // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a + // `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. + // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` + // is preferable over `const* T` to allow for niche optimization. + data: NonNull<T>, + inner_lock: &'a sys::RwLock, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`try_map`] methods +/// on [`RwLockWriteGuard`]. +/// +/// [`map`]: RwLockWriteGuard::map +/// [`try_map`]: RwLockWriteGuard::try_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +#[clippy::has_significant_drop] +pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> { + // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a + // `MappedRwLockWriteGuard` argument doesn't hold uniqueness for its whole scope, only until it drops. + // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field + // below for the correct variance over `T` (invariance). + data: NonNull<T>, + inner_lock: &'a sys::RwLock, + poison_flag: &'a poison::Flag, + poison: poison::Guard, + _variance: PhantomData<&'a mut T>, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {} + impl<T> RwLock<T> { /// Creates a new instance of an `RwLock<T>` which is unlocked. /// @@ -557,12 +620,40 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { } } +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockGuard::new` were satisfied when created. + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. unsafe { self.data.as_ref() } } } @@ -585,6 +676,37 @@ impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { } } +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + unsafe { self.data.as_mut() } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { fn drop(&mut self) { @@ -605,3 +727,310 @@ impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { } } } + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { + fn drop(&mut self) { + self.poison_flag.done(&self.poison); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + unsafe { + self.inner_lock.write_unlock(); + } + } +} + +impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::try_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { + data, + inner_lock: &orig.lock.inner, + poison_flag: &orig.lock.poison, + poison: orig.poison.clone(), + _variance: PhantomData, + } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { &mut *orig.lock.data.get() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: &orig.lock.inner, + poison_flag: &orig.lock.poison, + poison: orig.poison.clone(), + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_mut() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { + data, + inner_lock: orig.inner_lock, + poison_flag: orig.poison_flag, + poison: orig.poison.clone(), + _variance: PhantomData, + } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. + #[doc(alias = "filter_map")] + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `try_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the reference + // passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_mut() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: orig.inner_lock, + poison_flag: orig.poison_flag, + poison: orig.poison.clone(), + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 1a9d3d3f12f..9cc5e7a3a60 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -1,6 +1,9 @@ use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::mpsc::channel; -use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError}; +use crate::sync::{ + Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, + TryLockError, +}; use crate::thread; use rand::Rng; @@ -56,6 +59,19 @@ fn test_rw_arc_poison_wr() { } #[test] +fn test_rw_arc_poison_mapped_w_r() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.write().unwrap(); + let _lock = RwLockWriteGuard::map(lock, |val| val); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); +} + +#[test] fn test_rw_arc_poison_ww() { let arc = Arc::new(RwLock::new(1)); assert!(!arc.is_poisoned()); @@ -70,6 +86,20 @@ fn test_rw_arc_poison_ww() { } #[test] +fn test_rw_arc_poison_mapped_w_w() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.write().unwrap(); + let _lock = RwLockWriteGuard::map(lock, |val| val); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] fn test_rw_arc_no_poison_rr() { let arc = Arc::new(RwLock::new(1)); let arc2 = arc.clone(); @@ -81,6 +111,21 @@ fn test_rw_arc_no_poison_rr() { let lock = arc.read().unwrap(); assert_eq!(*lock, 1); } + +#[test] +fn test_rw_arc_no_poison_mapped_r_r() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.read().unwrap(); + let _lock = RwLockReadGuard::map(lock, |val| val); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} + #[test] fn test_rw_arc_no_poison_rw() { let arc = Arc::new(RwLock::new(1)); @@ -95,6 +140,20 @@ fn test_rw_arc_no_poison_rw() { } #[test] +fn test_rw_arc_no_poison_mapped_r_w() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.read().unwrap(); + let _lock = RwLockReadGuard::map(lock, |val| val); + panic!(); + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] fn test_rw_arc() { let arc = Arc::new(RwLock::new(0)); let arc2 = arc.clone(); @@ -179,6 +238,16 @@ fn test_rwlock_try_write() { } drop(read_guard); + let mapped_read_guard = RwLockReadGuard::map(lock.read().unwrap(), |_| &()); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while mapped_read_guard is in scope"), + Err(_) => assert!(false, "unexpected error"), + } + + drop(mapped_read_guard); } #[test] @@ -257,3 +326,173 @@ fn test_read_guard_covariance() { } drop(lock); } + +#[test] +fn test_mapped_read_guard_covariance() { + fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {} + let j: i32 = 5; + let lock = RwLock::new((&j, &j)); + { + let i = 6; + let guard = lock.read().unwrap(); + let guard = RwLockReadGuard::map(guard, |(val, _val)| val); + do_stuff(guard, &i); + } + drop(lock); +} + +#[test] +fn test_mapping_mapped_guard() { + let arr = [0; 4]; + let mut lock = RwLock::new(arr); + let guard = lock.write().unwrap(); + let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]); + let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]); + assert_eq!(guard.len(), 1); + guard[0] = 42; + drop(guard); + assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); + + let guard = lock.read().unwrap(); + let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]); + let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]); + assert_eq!(*guard, [42]); + drop(guard); + assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); +} + +#[test] +fn panic_while_mapping_read_unlocked_no_poison() { + let lock = RwLock::new(()); + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.read().unwrap(); + let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => {} + Err(TryLockError::WouldBlock) => { + panic!("panicking in a RwLockReadGuard::map closure should release the read lock") + } + Err(TryLockError::Poisoned(_)) => { + panic!("panicking in a RwLockReadGuard::map closure should not poison the RwLock") + } + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.read().unwrap(); + let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => {} + Err(TryLockError::WouldBlock) => { + panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock") + } + Err(TryLockError::Poisoned(_)) => { + panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock") + } + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.read().unwrap(); + let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); + let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => {} + Err(TryLockError::WouldBlock) => { + panic!("panicking in a MappedRwLockReadGuard::map closure should release the read lock") + } + Err(TryLockError::Poisoned(_)) => { + panic!("panicking in a MappedRwLockReadGuard::map closure should not poison the RwLock") + } + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.read().unwrap(); + let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); + let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => {} + Err(TryLockError::WouldBlock) => panic!( + "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock" + ), + Err(TryLockError::Poisoned(_)) => panic!( + "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock" + ), + } + + drop(lock); +} + +#[test] +fn panic_while_mapping_write_unlocked_poison() { + let lock = RwLock::new(()); + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.write().unwrap(); + let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => panic!("panicking in a RwLockWriteGuard::map closure should poison the RwLock"), + Err(TryLockError::WouldBlock) => { + panic!("panicking in a RwLockWriteGuard::map closure should release the write lock") + } + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.write().unwrap(); + let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => { + panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock") + } + Err(TryLockError::WouldBlock) => { + panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock") + } + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.write().unwrap(); + let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); + let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => { + panic!("panicking in a MappedRwLockWriteGuard::map closure should poison the RwLock") + } + Err(TryLockError::WouldBlock) => panic!( + "panicking in a MappedRwLockWriteGuard::map closure should release the write lock" + ), + Err(TryLockError::Poisoned(_)) => {} + } + + let _ = crate::panic::catch_unwind(|| { + let guard = lock.write().unwrap(); + let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); + let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + }); + + match lock.try_write() { + Ok(_) => panic!( + "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock" + ), + Err(TryLockError::WouldBlock) => panic!( + "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock" + ), + Err(TryLockError::Poisoned(_)) => {} + } + + drop(lock); +} diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 871a2ccdfa4..1c53796f5d4 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -207,7 +207,7 @@ impl Socket { buf.as_mut_ptr(), buf.len(), flags, - &mut storage as *mut _ as *mut _, + core::ptr::addr_of_mut!(storage) as *mut _, &mut addrlen, ) })?; @@ -323,7 +323,7 @@ impl Socket { netc::ioctl( self.as_raw_fd(), netc::FIONBIO, - &mut nonblocking as *mut _ as *mut core::ffi::c_void, + core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void, ) }) .map(drop) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index b0e9634d229..f289dafd8bc 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -100,7 +100,7 @@ pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { let mut time: Timespec = Timespec::zero(); - let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) }; + let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) }; Instant(time) } @@ -197,7 +197,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); - let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) }; + let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; SystemTime(time) } diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs index 6762a43b483..8a9ea4ac00d 100644 --- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs @@ -95,7 +95,7 @@ impl Tls { #[allow(unused)] pub unsafe fn activate_persistent(self: Box<Self>) { // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. - unsafe { set_tls_ptr((&*self) as *const Tls as _) }; + unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) }; mem::forget(self); } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index c75323ef775..086cdfe6e94 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1344,7 +1344,7 @@ impl File { } cvt(unsafe { libc::fsetattrlist( self.as_raw_fd(), - (&attrlist as *const libc::attrlist).cast::<libc::c_void>().cast_mut(), + core::ptr::addr_of!(attrlist).cast::<libc::c_void>().cast_mut(), buf.as_ptr().cast::<libc::c_void>().cast_mut(), num_times * mem::size_of::<libc::timespec>(), 0 @@ -1744,7 +1744,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> #[cfg(target_os = "espidf")] fn open_to_and_set_permissions( to: &Path, - reader_metadata: crate::fs::Metadata, + _reader_metadata: crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; let writer = OpenOptions::new().open(to)?; @@ -1918,7 +1918,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { copyfile_state_get( state.0, COPYFILE_STATE_COPIED, - &mut bytes_copied as *mut libc::off_t as *mut libc::c_void, + core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, ) })?; Ok(bytes_copied as u64) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 04b8c5ca916..23287258f2f 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -38,7 +38,7 @@ pub mod thread_parking; pub mod time; #[cfg(target_os = "espidf")] -pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {} +pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 1b6a6bb2c5c..f4ae7d21781 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -316,7 +316,7 @@ impl Socket { buf.as_mut_ptr() as *mut c_void, buf.len(), flags, - &mut storage as *mut _ as *mut _, + core::ptr::addr_of_mut!(storage) as *mut _, &mut addrlen, ) })?; diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index b6a74fb4831..23c2be6adf9 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -182,7 +182,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - &mut proc_info as *mut _ as *mut libc::c_void, + core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, mem::size_of::<zx_info_process_t>(), &mut actual, &mut avail, @@ -219,7 +219,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - &mut proc_info as *mut _ as *mut libc::c_void, + core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, mem::size_of::<zx_info_process_t>(), &mut actual, &mut avail, diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index d5a77085725..97cbd1929d3 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -694,15 +694,15 @@ impl Command { let mut iov = [IoSlice::new(b"")]; let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = &mut iov as *mut _ as *mut _; + msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; msg.msg_iovlen = 1; // only attach cmsg if we successfully acquired the pidfd if pidfd >= 0 { msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; - msg.msg_control = &mut cmsg.buf as *mut _ as *mut _; + msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _; - let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _); + let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); (*hdr).cmsg_level = SOL_SOCKET; (*hdr).cmsg_type = SCM_RIGHTS; (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _; @@ -744,17 +744,17 @@ impl Command { let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = &mut iov as *mut _ as *mut _; + msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; msg.msg_iovlen = 1; msg.msg_controllen = mem::size_of::<Cmsg>() as _; - msg.msg_control = &mut cmsg as *mut _ as *mut _; + msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _; match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { Err(_) => return -1, Ok(_) => {} } - let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _); + let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); if hdr.is_null() || (*hdr).cmsg_level != SOL_SOCKET || (*hdr).cmsg_type != SCM_RIGHTS diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 97976407bb4..864de31c6eb 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -239,7 +239,7 @@ impl Thread { tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; - let ts_ptr = &mut ts as *mut _; + let ts_ptr = core::ptr::addr_of_mut!(ts); if libc::nanosleep(ts_ptr, ts_ptr) == -1 { assert_eq!(os::errno(), libc::EINTR); secs += ts.tv_sec as u64; @@ -418,8 +418,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { libc::sysctl( mib.as_mut_ptr(), 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, + core::ptr::addr_of_mut!(cpus) as *mut _, + core::ptr::addr_of_mut!(cpus_size) as *mut _, ptr::null_mut(), 0, ) @@ -864,7 +864,7 @@ pub mod guard { .unwrap(); match sysctlbyname.get() { Some(fcn) => { - if fcn(oid.as_ptr(), &mut guard as *mut _ as *mut _, &mut size as *mut _ as *mut _, crate::ptr::null_mut(), 0) == 0 { + if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 { return guard; } return 1; diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs index 8857f96501c..79b152cece9 100644 --- a/library/std/src/sys/pal/unix/thread_local_dtor.rs +++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs @@ -58,7 +58,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { unsafe extern "C" fn(*mut libc::c_void), >(dtor), t.cast(), - &__dso_handle as *const _ as *mut _, + core::ptr::addr_of!(__dso_handle) as *mut _, ); } return; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 084b8e0e216..e6cbd51e768 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -166,7 +166,7 @@ pub fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { let mut ret = (0u64, 0u64); unsafe { - let base = &mut ret as *mut (u64, u64) as *mut u8; + let base = core::ptr::addr_of_mut!(ret) as *mut u8; let len = mem::size_of_val(&ret); wasi::random_get(base, len).expect("random_get failure"); } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b82a83ae7a3..3a9e7b4660b 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -394,7 +394,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - &mut info as *mut _ as *mut c_void, + core::ptr::addr_of_mut!(info) as *mut c_void, size as c::DWORD, ))?; let mut attr = FileAttr { @@ -422,7 +422,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileStandardInfo, - &mut info as *mut _ as *mut c_void, + core::ptr::addr_of_mut!(info) as *mut c_void, size as c::DWORD, ))?; attr.file_size = info.AllocationSize as u64; @@ -638,7 +638,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - &mut info as *mut _ as *mut c_void, + core::ptr::addr_of_mut!(info) as *mut c_void, size as c::DWORD, ))?; Ok(info) @@ -1438,7 +1438,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pfrom.as_ptr(), pto.as_ptr(), Some(callback), - &mut size as *mut _ as *mut _, + core::ptr::addr_of_mut!(size) as *mut _, ptr::null_mut(), 0, ) diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index b73d9f3ff4c..77b8f3c410e 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -122,7 +122,7 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { let res = c::GetFileInformationByHandleEx( handle, c::FileNameInfo, - &mut name_info as *mut _ as *mut c_void, + core::ptr::addr_of_mut!(name_info) as *mut c_void, size_of::<FILE_NAME_INFO>() as u32, ); if res == 0 { diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index e37fbe9ef83..1e6169ea8ec 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -310,7 +310,7 @@ impl Socket { buf.as_mut_ptr() as *mut _, length, flags, - &mut storage as *mut _ as *mut _, + core::ptr::addr_of_mut!(storage) as *mut _, &mut addrlen, ) }; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index fd10df82d8b..013f588676a 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -375,7 +375,7 @@ impl AnonPipe { let mut overlapped: c::OVERLAPPED = crate::mem::zeroed(); // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`. // Therefore the documentation suggests using it to smuggle a pointer to the callback. - overlapped.hEvent = &mut async_result as *mut _ as *mut _; + overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _; // Asynchronous read of the pipe. // If successful, `callback` will be called once it completes. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 6a94d377140..e4ab2ca7da1 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -350,10 +350,10 @@ impl Command { StartupInfo: si, lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, }; - si_ptr = &mut si_ex as *mut _ as _; + si_ptr = core::ptr::addr_of_mut!(si_ex) as _; } else { si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD; - si_ptr = &mut si as *mut _ as _; + si_ptr = core::ptr::addr_of_mut!(si) as _; } unsafe { @@ -935,7 +935,7 @@ fn make_proc_thread_attribute_list( // It's theoretically possible for the attribute count to exceed a u32 value. // Therefore, we ensure that we don't add more attributes than the buffer was initialized for. for (&attribute, value) in attributes.iter().take(attribute_count as usize) { - let value_ptr = &*value.data as *const (dyn Send + Sync) as _; + let value_ptr = core::ptr::addr_of!(*value.data) as _; cvt(unsafe { c::UpdateProcThreadAttribute( proc_thread_attribute_list.0.as_mut_ptr() as _, diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs index 5d8fd13785a..bd1ae6b0607 100644 --- a/library/std/src/sys/pal/windows/rand.rs +++ b/library/std/src/sys/pal/windows/rand.rs @@ -7,7 +7,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { let ret = unsafe { c::BCryptGenRandom( ptr::null_mut(), - &mut v as *mut _ as *mut u8, + core::ptr::addr_of_mut!(v) as *mut u8, mem::size_of_val(&v) as c::ULONG, c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) @@ -28,7 +28,7 @@ fn fallback_rng() -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { - c::RtlGenRandom(&mut v as *mut _ as *mut c_void, mem::size_of_val(&v) as c::ULONG) + c::RtlGenRandom(core::ptr::addr_of_mut!(v) as *mut c_void, mem::size_of_val(&v) as c::ULONG) }; if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } diff --git a/library/std/src/sys/pal/windows/thread_parking.rs b/library/std/src/sys/pal/windows/thread_parking.rs index 343b530b15e..ea485d71f5a 100644 --- a/library/std/src/sys/pal/windows/thread_parking.rs +++ b/library/std/src/sys/pal/windows/thread_parking.rs @@ -215,7 +215,7 @@ impl Parker { } fn ptr(&self) -> c::LPVOID { - &self.state as *const _ as c::LPVOID + core::ptr::addr_of!(self.state) as c::LPVOID } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index de7d31baaaf..581c46af0ea 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -70,7 +70,7 @@ pub fn setsockopt<T>( sock.as_raw(), level, option_name, - &option_value as *const T as *const _, + core::ptr::addr_of!(option_value) as *const _, mem::size_of::<T>() as c::socklen_t, ))?; Ok(()) @@ -85,7 +85,7 @@ pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> i sock.as_raw(), level, option_name, - &mut option_value as *mut T as *mut _, + core::ptr::addr_of_mut!(option_value) as *mut _, &mut option_len, ))?; Ok(option_value) @@ -99,7 +99,7 @@ where unsafe { let mut storage: c::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c::socklen_t; - cvt(f(&mut storage as *mut _ as *mut _, &mut len))?; + cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?; sockaddr_to_addr(&storage, len as usize) } } @@ -444,7 +444,7 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; let addr = sockaddr_to_addr(&storage, len as usize)?; Ok((TcpStream { inner: sock }, addr)) } diff --git a/library/std/src/sys_common/once/queue.rs b/library/std/src/sys_common/once/queue.rs index 3cc1df113e3..730cdb768bd 100644 --- a/library/std/src/sys_common/once/queue.rs +++ b/library/std/src/sys_common/once/queue.rs @@ -212,7 +212,7 @@ fn wait(state_and_queue: &AtomicPtr<Masked>, mut current_state: *mut Masked) { signaled: AtomicBool::new(false), next: current_state.with_addr(current_state.addr() & !STATE_MASK) as *const Waiter, }; - let me = &node as *const Waiter as *const Masked as *mut Masked; + let me = core::ptr::addr_of!(node) as *const Masked as *mut Masked; // Try to slide in the node at the head of the linked list, making sure // that another thread didn't just replace the head of the linked list. diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index ada69aa8269..7b11e7c17b1 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -311,7 +311,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// Checks if the associated thread has finished running its main function. /// /// `is_finished` supports implementing a non-blocking join operation, by checking - /// `is_finished`, and calling `join` if it returns `false`. This function does not block. To + /// `is_finished`, and calling `join` if it returns `true`. This function does not block. To /// block while waiting on the thread to finish, use [`join`][Self::join]. /// /// This might return `true` for a brief moment after the thread's main diff --git a/library/stdarch b/library/stdarch -Subproject d5fab978fe1c2f0043db0451e9f4857eeba1743 +Subproject 56087ea170d878a7a57b3a5725e0c00f5f5cad7 diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index f5988a4df13..a64f2904633 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/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1b5f6f9dde3..527c408c89e 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -219,14 +219,14 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { let mut val: _Unwind_Word = core::ptr::null(); _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - &mut val as *mut _ as *mut c_void); + core::ptr::addr_of_mut!(val) as *mut c_void); val } pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { let mut value = value; _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - &mut value as *mut _ as *mut c_void); + core::ptr::addr_of_mut!(value) as *mut c_void); } pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index b813d82ca6f..9a50ad4437e 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 573d923ed8f..a14dfd1ca12 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/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index b736f4a7956..b6880cfc60f 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/html/format.rs b/src/librustdoc/html/format.rs index bb68c84f529..973036a4098 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -879,11 +879,16 @@ fn primitive_link_fragment( match m.primitive_locations.get(&prim) { Some(&def_id) if def_id.is_local() => { let len = cx.current.len(); - let len = if len == 0 { 0 } else { len - 1 }; + let path = if len == 0 { + let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); + format!("{cname_sym}/") + } else { + "../".repeat(len - 1) + }; write!( f, "<a class=\"primitive\" href=\"{}primitive.{}.html{fragment}\">", - "../".repeat(len), + path, prim.as_sym() )?; needs_termination = true; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 27a8079d893..61211a7d675 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2503,8 +2503,11 @@ impl<'test> TestCx<'test> { // overridden by `compile-flags`. rustc.arg("-Copt-level=2"); } - RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake - | CodegenUnits | JsDocTest | Assembly => { + Assembly | Codegen => { + rustc.arg("-Cdebug-assertions=no"); + } + RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake + | CodegenUnits | JsDocTest => { // do not use JSON output } } diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 87dc51bd612..1adae2b7a22 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "autocfg" @@ -91,9 +91,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bstr" @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -140,12 +140,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" [[package]] name = "cfg-if" @@ -208,15 +205,15 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -230,22 +227,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -285,9 +278,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -311,9 +304,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -334,9 +327,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -393,9 +386,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libffi" @@ -428,9 +421,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -479,9 +472,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -513,7 +506,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -616,9 +609,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -673,9 +666,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -685,9 +678,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -735,11 +728,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", @@ -748,9 +741,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scopeguard" @@ -760,27 +753,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -789,9 +782,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -809,15 +802,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -826,31 +819,30 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -859,9 +851,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -995,15 +987,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" @@ -1017,22 +1000,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.3", ] [[package]] @@ -1052,42 +1020,30 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -1097,15 +1053,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -1115,15 +1065,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -1133,15 +1077,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -1151,15 +1089,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -1169,15 +1101,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -1187,9 +1113,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "yansi-term" diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 60bf07b1736..944d2bbe879 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -279,7 +279,7 @@ Miri builds and vice-versa. You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. -Try deleting `~/.cache/miri`. +Try running `cargo miri clean`. #### "no mir for `std::rt::lang_start_internal`" @@ -465,7 +465,7 @@ Moreover, Miri recognizes some environment variables: must point to the `library` subdirectory of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build - cache manually (on Linux, `rm -rf ~/.cache/miri`; + cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`; on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`; and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`). * `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index fe384c9d497..6841a345ce1 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "bitflags" @@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "camino" @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -110,9 +110,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -127,9 +127,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -137,16 +137,16 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "option-ext" @@ -156,9 +156,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -194,13 +194,14 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544" +checksum = "a26170e1d79ea32f7ccec3188dd13cfc1f18c82764a9cbc1071667c0f865a4ea" dependencies = [ "anyhow", "rustc_version", "tempfile", + "walkdir", ] [[package]] @@ -220,11 +221,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", @@ -233,33 +234,42 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -268,9 +278,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -279,9 +289,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -290,31 +300,30 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -328,12 +337,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -348,7 +398,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -368,17 +418,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] @@ -389,9 +439,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -401,9 +451,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -413,9 +463,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -425,9 +475,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -437,9 +487,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -449,9 +499,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -461,6 +511,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 79ce1f4ca32..315f7a23a91 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -20,6 +20,7 @@ Subcommands: test, t Run tests nextest Run tests with nextest (requires cargo-nextest installed) setup Only perform automatic setup, but without asking questions (for getting a proper libstd) + clean Clean the Miri cache & target directory The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. @@ -74,14 +75,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. let Some(subcommand) = args.next() else { - show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)"); + show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`, `clean`)"); }; let subcommand = match &*subcommand { "setup" => MiriCommand::Setup, "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), + "clean" => MiriCommand::Clean, _ => show_error!( - "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." + "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`." ), }; let verbose = num_arg_flag("-v"); @@ -93,6 +95,16 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { let target = get_arg_flag_value("--target"); let target = target.as_ref().unwrap_or(host); + // If cleaning the the target directory & sysroot cache, + // delete them then exit. There is no reason to setup a new + // sysroot in this execution. + if let MiriCommand::Clean = subcommand { + let metadata = get_cargo_metadata(); + clean_target_dir(&metadata); + clean_sysroot(); + return; + } + // We always setup. let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose); @@ -110,6 +122,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { let cargo_cmd = match subcommand { MiriCommand::Forward(s) => s, MiriCommand::Setup => return, // `cargo miri setup` stops here. + MiriCommand::Clean => unreachable!(), }; let metadata = get_cargo_metadata(); let mut cmd = cargo(); @@ -142,11 +155,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); // Set `--target-dir` to `miri` inside the original target directory. - let mut target_dir = match get_arg_flag_value("--target-dir") { - Some(dir) => PathBuf::from(dir), - None => metadata.target_directory.clone().into_std_path_buf(), - }; - target_dir.push("miri"); + let target_dir = get_target_dir(&metadata); cmd.arg("--target-dir").arg(target_dir); // *After* we set all the flags that need setting, forward everything else. Make sure to skip diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index 8ae5b8c3e82..a98e1fcd485 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -67,13 +67,8 @@ pub fn setup( } // Determine where to put the sysroot. - let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") { - Some(dir) => PathBuf::from(dir), - None => { - let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); - user_dirs.cache_dir().to_owned() - } - }; + let sysroot_dir = get_sysroot_dir(); + // Sysroot configuration and build details. let no_std = match std::env::var_os("MIRI_NO_STD") { None => diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index 3c591268455..6c1a074cd8c 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -74,6 +74,8 @@ pub enum MiriCommand { Setup, /// A command to be forwarded to cargo. Forward(String), + /// Clean the miri cache + Clean, } /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. @@ -249,3 +251,65 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { } eprintln!("{prefix} running command: {cmd:?}"); } + +/// Get the target directory for miri output. +/// +/// Either in an argument passed-in, or from cargo metadata. +pub fn get_target_dir(meta: &Metadata) -> PathBuf { + let mut output = match get_arg_flag_value("--target-dir") { + Some(dir) => PathBuf::from(dir), + None => meta.target_directory.clone().into_std_path_buf(), + }; + output.push("miri"); + output +} + +/// Determines where the sysroot of this exeuction is +/// +/// Either in a user-specified spot by an envar, or in a default cache location. +pub fn get_sysroot_dir() -> PathBuf { + match std::env::var_os("MIRI_SYSROOT") { + Some(dir) => PathBuf::from(dir), + None => { + let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); + user_dirs.cache_dir().to_owned() + } + } +} + +/// An idempotent version of the stdlib's remove_dir_all +/// it is considered a success if the directory was not there. +fn remove_dir_all_idem(dir: &Path) -> std::io::Result<()> { + match std::fs::remove_dir_all(dir) { + Ok(_) => Ok(()), + // If the directory doesn't exist, it is still a success. + Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()), + Err(err) => Err(err), + } +} + +/// Deletes the Miri sysroot cache +/// Returns an error if the MIRI_SYSROOT env var is set. +pub fn clean_sysroot() { + if std::env::var_os("MIRI_SYSROOT").is_some() { + show_error!( + "MIRI_SYSROOT is set. Please clean your custom sysroot cache directory manually." + ) + } + + let sysroot_dir = get_sysroot_dir(); + + eprintln!("Cleaning sysroot cache at {}", sysroot_dir.display()); + + // Keep it simple, just remove the directory. + remove_dir_all_idem(&sysroot_dir).unwrap_or_else(|err| show_error!("{}", err)); +} + +/// Deletes the Miri target directory +pub fn clean_target_dir(meta: &Metadata) { + let target_dir = get_target_dir(meta); + + eprintln!("Cleaning target directory at {}", target_dir.display()); + + remove_dir_all_idem(&target_dir).unwrap_or_else(|err| show_error!("{}", err)) +} diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 04615f3d8c1..a6f7467f0a2 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "bitflags" @@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "cfg-if" @@ -55,9 +55,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "errno" @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -100,9 +100,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.151" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -110,16 +110,16 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "miri-script" @@ -157,9 +157,9 @@ checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15" [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -204,11 +204,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "shell-words" @@ -238,9 +238,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -249,18 +249,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -347,7 +347,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -367,17 +367,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] @@ -388,9 +388,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -400,9 +400,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -412,9 +412,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -424,9 +424,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -436,9 +436,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -448,9 +448,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -460,9 +460,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "xshell" diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat new file mode 100644 index 00000000000..91e8a6e8f3b --- /dev/null +++ b/src/tools/miri/miri.bat @@ -0,0 +1,10 @@ +:: This makes execution of ./miri on Linux and Windows the same. +:: Windows will not execute the bash script, and select this. +@echo off +set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target +cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml + +:: Forwards all arguments to this file to the executable. +:: We invoke the binary directly to avoid going through rustup, which would set some extra +:: env vars that we do not want. +%MIRI_SCRIPT_TARGET_DIR%\debug\miri-script %* diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ab6f899cd3a..02ab748c447 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -4316d0c6252cb1f833e582dfa68adb98efd5ddfb +c5f69bdd5173a948e0131f934fa7c4cbf5e0b55f diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index ea2d104694a..ca8773cac14 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -563,9 +563,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right_idx = src_index.checked_sub(left_len).unwrap(); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { - span_bug!( - this.cur_span(), - "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", + throw_ub_format!( + "`simd_shuffle_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}" ); }; this.write_immediate(*val, &dest)?; @@ -604,9 +603,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right_idx = src_index.checked_sub(left_len).unwrap(); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { - span_bug!( - this.cur_span(), - "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", + throw_ub_format!( + "`simd_shuffle` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}" ); }; this.write_immediate(*val, &dest)?; diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 8bed321e655..d8f7cafe3b2 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -99,18 +99,15 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> }; if with_dependencies { + // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary. + // (It's a separate crate, so we don't get an env var from cargo.) + let mut prog = miri_path(); + prog.set_file_name("cargo-miri"); + config.dependency_builder.program = prog; + let builder_args = ["miri", "run"]; // There is no `cargo miri build` so we just use `cargo miri run`. + config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect(); config.dependencies_crate_manifest_path = Some(Path::new("test_dependencies").join("Cargo.toml")); - let mut builder_args = vec!["run".into()]; - builder_args.extend(flagsplit(&env::var("CARGO_EXTRA_FLAGS").unwrap_or_default())); - builder_args.extend([ - "--manifest-path".into(), - "cargo-miri/Cargo.toml".into(), - "--".into(), - "miri".into(), - "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. - ]); - config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect(); // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>. config.dependency_builder.envs.push(("RUSTFLAGS".into(), None)); } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-extract.rs b/src/tools/miri/tests/fail/intrinsics/simd-extract.rs new file mode 100644 index 00000000000..02b9d30df5e --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd-extract.rs @@ -0,0 +1,8 @@ +#![feature(portable_simd, core_intrinsics)] +use std::simd::*; + +fn main() { + let v = i32x4::splat(0); + let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) }; + //~^ERROR: index 4 is out-of-bounds +} diff --git a/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr new file mode 100644 index 00000000000..dc6b22de492 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `simd_extract` index 4 is out-of-bounds of vector with length 4 + --> $DIR/simd-extract.rs:LL:CC + | +LL | let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_extract` index 4 is out-of-bounds of vector with length 4 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/simd-extract.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs index f362caa11dc..f362caa11dc 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs index 66c0895a5da..66c0895a5da 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/shims/mmap.rs index 0cbe8d94294..5acdedc67bf 100644 --- a/src/tools/miri/tests/pass-dep/shims/mmap.rs +++ b/src/tools/miri/tests/pass-dep/shims/mmap.rs @@ -155,8 +155,9 @@ fn test_mremap() { // Test all of our error conditions // Not aligned - let ptr = - unsafe { libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) }; + let ptr = unsafe { + libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) + }; assert_eq!(ptr, libc::MAP_FAILED); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs index 077bbfff164..c9d10cb83d4 100644 --- a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs @@ -4,8 +4,8 @@ #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; -use std::thread; -use std::{mem, ptr}; +use std::mem::MaybeUninit; +use std::{mem, ptr, thread}; fn main() { test_mutex_libc_init_recursive(); @@ -15,9 +15,10 @@ fn main() { #[cfg(target_os = "linux")] test_mutex_libc_static_initializer_recursive(); - test_mutex(); + check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); + check_cond(); } fn test_mutex_libc_init_recursive() { @@ -119,7 +120,7 @@ impl<T> Clone for SendPtr<T> { } } -fn test_mutex() { +fn check_mutex() { // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex. unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0)); @@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() { } } +fn check_cond() { + unsafe { + let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit(); + assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0); + let cond = SendPtr { ptr: cond.as_mut_ptr() }; + + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + let mutex = SendPtr { ptr: &mut mutex }; + + let mut data = 0; + let data = SendPtr { ptr: &mut data }; + + let t = thread::spawn(move || { + let mutex = mutex; // circumvent per-field closure capture + let cond = cond; + let data = data; + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 0); + data.ptr.write(1); + libc::pthread_cond_wait(cond.ptr, mutex.ptr); + assert!(data.ptr.read() == 3); + data.ptr.write(4); + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + }); + + thread::yield_now(); + + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 1); + data.ptr.write(2); + assert_eq!(libc::pthread_cond_signal(cond.ptr), 0); + thread::yield_now(); // the other thread wakes up but can't get the lock yet + assert!(data.ptr.read() == 2); + data.ptr.write(3); + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + + thread::yield_now(); // now the other thread gets the lock back + + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 4); + assert_eq!(libc::pthread_cond_broadcast(cond.ptr), 0); // just a smoke test + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + + t.join().unwrap(); + } +} + // std::sync::RwLock does not even used pthread_rwlock any more. // Do some smoke testing of the API surface. fn test_rwlock_libc_static_initializer() { diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 1d48e5312d4..a6c181098b7 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -63,10 +63,10 @@ fn check_conditional_variables_timed_wait_timeout() { let cvar = Condvar::new(); let guard = lock.lock().unwrap(); let now = Instant::now(); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(10)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 1000); + assert!(10 <= elapsed_time && elapsed_time <= 1000); } /// Test that signaling a conditional variable when waiting with a timeout works @@ -79,7 +79,7 @@ fn check_conditional_variables_timed_wait_notimeout() { let guard = lock.lock().unwrap(); let handle = thread::spawn(move || { - thread::sleep(Duration::from_millis(100)); // Make sure the other thread is waiting by the time we call `notify`. + thread::sleep(Duration::from_millis(1)); // Make sure the other thread is waiting by the time we call `notify`. let (_lock, cvar) = &*pair2; cvar.notify_one(); }); diff --git a/src/tools/miri/tests/pass/overflow_checks_off.rs b/src/tools/miri/tests/pass/overflow_checks_off.rs index 7b9d4f8fff5..831bffb6c5e 100644 --- a/src/tools/miri/tests/pass/overflow_checks_off.rs +++ b/src/tools/miri/tests/pass/overflow_checks_off.rs @@ -7,10 +7,9 @@ // Miri does not implement the codegen-time hack that backs `#[rustc_inherit_overflow_checks]`. // use std::ops::*; - // Disable _compile-time_ overflow linting // so that we can test runtime overflow checks - #![allow(arithmetic_overflow)] +#![allow(arithmetic_overflow)] fn main() { assert_eq!(-{ -0x80i8 }, -0x80); diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index 57d0b6a87b2..d4b3ab8ac09 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -268,15 +268,11 @@ fn simd_mask() { } // This used to cause an ICE. It exercises simd_select_bitmask with an array as input. - if cfg!(target_endian = "little") { - // FIXME this test currently fails on big-endian: - // <https://github.com/rust-lang/portable-simd/issues/379> - let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]); - assert_eq!( - mask32x4::from_bitmask_vector(bitmask), - mask32x4::from_array([true, false, true, true]), - ); - } + let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]); + assert_eq!( + mask32x4::from_bitmask_vector(bitmask), + mask32x4::from_array([true, false, true, true]), + ); let bitmask = u8x8::from_array([0b01000101, 0, 0, 0, 0, 0, 0, 0]); assert_eq!( mask32x8::from_bitmask_vector(bitmask), diff --git a/src/tools/miri/tests/pass/shims/windows-rand.rs b/src/tools/miri/tests/pass/shims/windows-rand.rs new file mode 100644 index 00000000000..e2bcb7bd7cb --- /dev/null +++ b/src/tools/miri/tests/pass/shims/windows-rand.rs @@ -0,0 +1,41 @@ +//@only-target-windows: this directly tests windows only random functions +use core::ffi::c_void; +use core::mem::size_of_val; +use core::ptr::null_mut; + +// Windows API definitions. +type NTSTATUS = i32; +type BOOLEAN = u8; +const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; +const BCRYPT_RNG_ALG_HANDLE: *mut c_void = 0x81 as *mut c_void; +#[link(name = "bcrypt")] +extern "system" { + fn BCryptGenRandom( + halgorithm: *mut c_void, + pbbuffer: *mut u8, + cbbuffer: u32, + dwflags: u32, + ) -> NTSTATUS; +} +#[link(name = "advapi32")] +extern "system" { + #[link_name = "SystemFunction036"] + fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> BOOLEAN; +} + +fn main() { + let mut key = [0u8; 24]; + let len: u32 = size_of_val(&key).try_into().unwrap(); + let ret = unsafe { + BCryptGenRandom(null_mut(), key.as_mut_ptr(), len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) + }; + // NTSTATUS codes use the high bit to indicate an error + assert!(ret >= 0); + + let ret = unsafe { BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, key.as_mut_ptr(), len, 0) }; + assert!(ret >= 0); + + let ret = unsafe { RtlGenRandom(key.as_mut_ptr(), len) }; + // RtlGenRandom returns a BOOLEAN where 0 indicates an error + assert_ne!(ret, 0); +} diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs index d30ca96ea41..0b9805681b4 100644 --- a/src/tools/miri/tests/pass/slices.rs +++ b/src/tools/miri/tests/pass/slices.rs @@ -29,7 +29,8 @@ fn slice_of_zst() { // In a slice of zero-size elements the pointer is meaningless. // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) }; + let slice: &[()] = + unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter().count(), 10); diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 62fbd57abc1..5a8b18e3fe1 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 be9f504e599..de61b2389ae 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 adb1c850516..ac536d0fdde 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 7b29d7bb798..3c87291dbad 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 8229b1ccf3d..cd14f7b855a 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 540f643ae7d..f07b1257662 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 38cfcf0f281..faa1eed15a4 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 be16a5e31a2..bb36950f95a 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 b51cb5de0f4..37fdece8768 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<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { 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 dae876f7ecb..87c90a4c6ab 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 88838f58fe7..32825406505 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 bf89ea711a0..d278b75e815 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 bd243518fc6..e678a2fee13 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<Interner>; pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; -pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; +pub(crate) type AdtDatum = chalk_solve::rust_ir::AdtDatum<Interner>; pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; @@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { self.db.trait_datum(self.krate, trait_id) } - fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { - self.db.struct_datum(self.krate, struct_id) + fn adt_datum(&self, struct_id: AdtId) -> Arc<AdtDatum> { + self.db.adt_datum(self.krate, struct_id) } fn adt_repr(&self, _struct_id: AdtId) -> Arc<rust_ir::AdtRepr<Interner>> { // FIXME: keep track of these @@ -136,81 +137,92 @@ impl chalk_solve::RustIrDatabase<Interner> 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<Interner>) -> 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<AssociatedTyValue> { self.db.associated_ty_value(self.krate, id) } @@ -489,6 +501,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { } } +impl<'a> ChalkContext<'a> { + fn for_trait_impls( + &self, + trait_id: hir_def::TraitId, + self_ty_fp: Option<TyFingerprint>, + 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<Interner> 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<StructDatum> { - debug!("struct_datum {:?}", struct_id); - let chalk_ir::AdtId(adt_id) = struct_id; + chalk_ir::AdtId(adt_id): AdtId, +) -> Arc<AdtDatum> { + 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 fbd366864a4..f9e8cff5539 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<dyn DefDatabase> { #[salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders<Ty>; - /// 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<Binders<Ty>>; @@ -220,12 +220,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { trait_id: chalk_db::TraitId, ) -> sync::Arc<chalk_db::TraitDatum>; - #[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<chalk_db::StructDatum>; + ) -> sync::Arc<chalk_db::AdtDatum>; #[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 c4329a7b82b..6c8a1875165 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<Body>, infer: Arc<InferenceResult>, - pub(super) diagnostics: Vec<BodyValidationDiagnostic>, + diagnostics: Vec<BodyValidationDiagnostic>, } impl ExprValidator { - fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> 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<WitnessPat<'p>>, - 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 1977f00517c..9cea414e1a0 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 428ed6748c6..c377a51e7d3 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 fbe6a982d6f..628a1fe2d28 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 eddfd0acfb9..e229a4ab317 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 9fe3d5b77ae..ed316f97268 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 02b1494062f..85c8d1685b8 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 db14addaf18..879c69c758f 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<T> !Send for *const T {} + +struct Yes; +trait IsSend { const IS_SEND: Yes; } +impl<T: Send> IsSend for T { const IS_SEND: Yes = Yes; } + +struct Struct<T>(T); +enum Enum<T> { A, B(T) } +union Union<T> { t: T } + +#[lang = "phantom_data"] +struct PhantomData<T: ?Sized>; + +fn f<T: Send, U>() { + T::IS_SEND; + //^^^^^^^^^^Yes + U::IS_SEND; + //^^^^^^^^^^{unknown} + <*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^{unknown} + Struct::<T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^Yes + Struct::<U>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^Yes + Struct::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes + Enum::<T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^Yes + Enum::<U>::IS_SEND; + //^^^^^^^^^^^^^^^^^^Yes + Enum::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^Yes + Union::<T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^Yes + Union::<U>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^Yes + Union::<*const T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes + PhantomData::<T>::IS_SEND; + //^^^^^^^^^^^^^^^^^^^^^^^^^Yes + PhantomData::<U>::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 08843a6c999..80cd0c9c794 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, @@ -242,6 +244,11 @@ pub struct UnresolvedAssocItem { } #[derive(Debug)] +pub struct UnresolvedIdent { + pub expr: InFile<AstPtr<ast::Expr>>, +} + +#[derive(Debug)] pub struct PrivateField { pub expr: InFile<AstPtr<ast::Expr>>, pub field: Field, @@ -281,6 +288,12 @@ pub struct MissingMatchArms { } #[derive(Debug)] +pub struct NonExhaustiveLet { + pub pat: InFile<AstPtr<ast::Pat>>, + pub uncovered_patterns: String, +} + +#[derive(Debug)] pub struct TypeMismatch { pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, pub expected: Type, @@ -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::<ast::Pat>() { + 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 08f7bb14caa..2d8811cf5eb 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<ExternAssocItem>; +} + +impl AsExternAssocItem for Function { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> { + as_extern_assoc_item(db, ExternAssocItem::Function, self.id) + } +} + +impl AsExternAssocItem for Static { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> { + as_extern_assoc_item(db, ExternAssocItem::Static, self.id) + } +} + +impl AsExternAssocItem for TypeAlias { + fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> { + 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<ExternAssocItem> +where + ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<LOC>>, + DEF: From<ID>, + 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<Function> { + match self { + Self::Function(v) => Some(v), + _ => None, + } + } + + pub fn as_static(self) -> Option<Static> { + match self { + Self::Static(v) => Some(v), + _ => None, + } + } + + pub fn as_type_alias(self) -> Option<TypeAlias> { + match self { + Self::TypeAlias(v) => Some(v), + _ => None, + } + } +} + impl AssocItem { pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 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 666d63ac155..edbf75affe6 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<Vec<Expr>> = fileds + let param_exprs: Vec<Vec<Expr>> = fields .into_iter() .map(|field| lookup.find(db, &field.ty(db))) .collect::<Option<_>>()?; 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 c2c0641961a..4bab2886851 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 296253aa1ee..2b2df144d6d 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 d95d94ec72e..1b6ff8bad53 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<String> { - 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<ExternAssocItem> { + 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<AssocItem> 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 6b0fecae267..10c285a13fb 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 2881748dd47..d31dad514aa 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 722161282fe..c65467a4324 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 7db5ea04fbd..785a42352bf 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 5e2541795ca..db28928a24e 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 c70f39eb286..09daefd084d 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 7632fdf1d09..8596f5792e0 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 bdb55a9d98a..91f1058d65b 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 00000000000..1a4d2877ef2 --- /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 b7667dc318f..7a040e46e33 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 <expr>; with <expr> } "#, - 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 ae8241ec2c6..47844876dc5 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<Vec< indent = indent + 1; } let else_replacement = match if_expr.else_branch()? { - ast::ElseBranch::Block(ref block) => { - 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<Vec< #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix}; - - fn check_diagnostics_with_needless_return_disabled(ra_fixture: &str) { - check_diagnostics_with_disabled(ra_fixture, std::iter::once("needless_return".to_owned())); - } + use crate::tests::{check_diagnostics_with_disabled, check_fix}; #[test] fn remove_unnecessary_else_for_return() { - check_diagnostics_with_needless_return_disabled( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -106,6 +110,7 @@ fn test() { } } "#, + &["needless_return", "E0425"], ); check_fix( r#" @@ -130,7 +135,7 @@ fn test() { #[test] fn remove_unnecessary_else_for_return2() { - check_diagnostics_with_needless_return_disabled( + check_diagnostics_with_disabled( r#" fn test() { if foo { @@ -143,6 +148,7 @@ fn test() { } } "#, + &["needless_return", "E0425"], ); check_fix( r#" @@ -172,8 +178,44 @@ fn test() { } #[test] + fn remove_unnecessary_else_for_return3() { + check_diagnostics_with_disabled( + r#" +fn test(a: bool) -> 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#" @@ -215,8 +258,43 @@ 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 8c97281b783..4c255322280 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 a6a0fdc655f..97943b7e8b3 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 65abfd8a294..4c01a2d155a 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 00000000000..295c8a2c615 --- /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 648d081898c..0614fdc5514 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 863a7ab783e..79bcaa0a9c4 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 9d21bb4cd9f..9f4368b04e7 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<Vec<Assist>>, // The node that will be affected by `#[allow]` and similar attributes. - pub main_node: Option<InFile<SyntaxNode>>, + pub main_node: Option<InFile<SyntaxNodePtr>>, } impl Diagnostic { @@ -172,9 +174,8 @@ impl Diagnostic { message: impl Into<String>, node: InFile<SyntaxNodePtr>, ) -> 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<SyntaxNode>) -> Diagnostic { + fn with_main_node(mut self, main_node: InFile<SyntaxNodePtr>) -> 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::<FxHashMap<_, _>>(); + 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::<FxHashMap<_, _>>(); let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default(); let mut clippy_stack: FxHashMap<String, Vec<Severity>> = 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 4e4a851f67e..901ceffbb26 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<Item = String>, -) { +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 19b181ae3b6..4a7350feb38 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> { +) -> 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 eff055c9599..563e78253a8 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<String> 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(|_| "<extern>".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<Type>, Name)>)], config: &HoverConfig, -) -> Option<Markup> { +) -> 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<String> { def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) } -fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> { +fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup { let mut buf = String::new(); if let Some(mod_path) = mod_path { @@ -696,7 +704,7 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> 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<hir::Module> { 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 69ddc1e45ef..ead4f91595f 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::<extern> ``` ```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 @@ -7202,6 +7238,65 @@ impl Iterator for S { } #[test] +fn extern_items() { + check( + r#" +extern "C" { + static STATIC$0: (); +} +"#, + expect![[r#" + *STATIC* + + ```rust + test::<extern> + ``` + + ```rust + static STATIC: () + ``` + "#]], + ); + check( + r#" +extern "C" { + fn fun$0(); +} +"#, + expect![[r#" + *fun* + + ```rust + test::<extern> + ``` + + ```rust + unsafe fn fun() + ``` + "#]], + ); + check( + r#" +extern "C" { + type Ty$0; +} +"#, + expect![[r#" + *Ty* + + ```rust + test::<extern> + ``` + + ```rust + // size = 0, align = 1 + type Ty + ``` + "#]], + ); +} + +#[test] fn notable_ranged() { check_hover_range( r#" 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 fef0ec35ba0..815a4ba7fd7 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 f2eedfa4316..f78153df38b 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<Vec<SourceChange>> = 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 ops: RenameResult<Vec<SourceChange>> = 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); + 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); + } } - } - 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<SourceChange> { + 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 5feaf21aa97..2929a7522e5 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 8c5592da63e..830d19a709c 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<vfs::loader::Message>, ) -> 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::<usize>().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 12eafcea442..72f95643c8b 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 3fe968c81ca..686d5b0438a 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 ff8fd295d88..5a814e23e7a 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<S> LiteralFormatter<S> { 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 c6a0a666555..15d260d5182 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<super::Span>; pub type TokenTree = ::tt::TokenTree<super::Span>; @@ -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 7e9d8057ac9..f40c850b253 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<TokenId>; pub type TokenTree = ::tt::TokenTree<TokenId>; @@ -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 5edaa720fc7..408db60e872 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<S: tt::Span> /*FromStr for*/ TokenStream<S> { - // type Err = LexError; - - pub(crate) fn from_str(src: &str, call_site: S) -> Result<TokenStream<S>, LexError> { + impl<S: tt::Span> TokenStream<S> { + pub(crate) fn from_str(src: &str, call_site: S) -> Result<TokenStream<S>, 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 e5bfe5ee92c..54a20357d26 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 ab72f1fba09..621b6ca3efa 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<Version>, sysroot: Option<&Sysroot>, ) -> io::Result<WorkspaceBuildScripts> { - 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 af635dda578..98917351c5e 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 b7ae76be8ce..bcb5dcadb5b 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<CfgFlag>, + toolchain: Option<Version>, + 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<AbsPathBuf>, config: &CargoConfig, ) -> anyhow::Result<ProjectWorkspace> { + 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 f9f26178259..815a98980b9 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<String>) { 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 493e614dce6..3f68c5d053b 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 64ea246a458..7062b60cbfc 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::<String>() - .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::<String>() + .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 2d56830c87f..27869a5a7e6 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 293807a383b..b2d507491b1 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::<std::path::Path>::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 eb9d4bf0f02..04a04395429 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 727007bba08..481ebfefd4e 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::<Cancellable<Vec<_>>>()?; 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::<Cancellable<Vec<_>>>()?; 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 10335cb1453..800c0eee53a 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::<lsp_types::request::WorkDoneProgressCreate>( 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 5895459d1fc..f6bc032c019 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 392a7170207..dfd25abc70f 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 4ccbc3de846..9eec21f6a15 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 0ec75bb043d..223da9b5290 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 5d1678ef120..a868d920b66 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 d6316710058..153df999f53 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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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<TableEntry<Q::Key, Q::Value>>, { 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 4fad791a26a..75204c8ff60 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<Q>, { - key: Q::Key, - database_key_index: DatabaseKeyIndex, + key_index: u32, + group_index: u16, state: RwLock<QueryState<Q>>, policy: PhantomData<MP>, lru_index: LruIndex, @@ -110,10 +110,10 @@ where Q: QueryFunction, MP: MemoizationPolicy<Q>, { - 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: &<Q as QueryDb<'_>>::DynDb) -> StampedValue<Q::Value> { + pub(super) fn read( + &self, + db: &<Q as QueryDb<'_>>::DynDb, + key: &Q::Key, + ) -> StampedValue<Q::Value> { 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: &<Q as QueryDb<'_>>::DynDb, + key: &Q::Key, revision_now: Revision, ) -> StampedValue<Q::Value> { 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<Memo<Q::Value>>, + key: &Q::Key, ) -> StampedValue<Q::Value> { - 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<TableEntry<Q::Key, Q::Value>> { + pub(super) fn as_table_entry(&self, key: &Q::Key) -> Option<TableEntry<Q::Key, Q::Value>> { 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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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<Q>, { - database_key_index: DatabaseKeyIndex, slot: &'me Slot<Q, MP>, runtime: &'me Runtime, } @@ -595,12 +613,8 @@ where Q: QueryFunction, MP: MemoizationPolicy<Q>, { - fn new( - database_key_index: DatabaseKeyIndex, - slot: &'me Slot<Q, MP>, - runtime: &'me Runtime, - ) -> Self { - Self { database_key_index, slot, runtime } + fn new(slot: &'me Slot<Q, MP>, 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<Memo<Q::Value>>) { - let mut write = self.slot.state.write(); - - 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), + 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)), + + // 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<Q>, { 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 0c82f6345ab..44abae3170f 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 c2539570e0f..922ec5a7752 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<V> { - database_key_index: DatabaseKeyIndex, + key_index: u32, stamped_value: RwLock<StampedValue<V>>, } @@ -54,27 +54,25 @@ where fn fmt_index( &self, _db: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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<Q> where Q: Query<Key = ()>, { - group_index: u16, slot: UnitSlot<Q::Value>, } @@ -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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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 822219f5185..c065e7e2bde 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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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: &<Q as QueryDb<'_>>::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 668dcfd925d..fe807598873 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 <Self as QueryDb<'_>>::GroupStorage, ) -> &'a std::sync::Arc<Self::Storage>; - /// 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 <Self as QueryDb<'_>>::GroupStorage, ) -> &'a std::sync::Arc<Self::Storage>; diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs index c6b9778f20a..1ff85a3ea45 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 71332e39cad..1a8ff33b2ef 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: &<Q as QueryDb<'_>>::DynDb, - index: DatabaseKeyIndex, + index: u32, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result; @@ -179,7 +186,7 @@ where fn maybe_changed_after( &self, db: &<Q as QueryDb<'_>>::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 d97aaf9deba..559b0338608 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 40b8856991f..a7d5a245782 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<AtomicRevision>, + revisions: [AtomicRevision; Durability::LEN], /// The dependency graph tracks which runtimes are blocked on one /// another, waiting for queries to terminate. dependency_graph: Mutex<DependencyGraph>, } -impl SharedState { - fn with_durabilities(durabilities: usize) -> Self { - SharedState { - next_id: AtomicUsize::new(1), - query_lock: Default::default(), - revisions: (0..durabilities).map(|_| AtomicRevision::start()).collect(), - pending_revision: AtomicRevision::start(), - dependency_graph: Default::default(), - } - } -} - impl std::panic::RefUnwindSafe for SharedState {} impl Default for SharedState { fn default() -> Self { - Self::with_durabilities(Durability::LEN) + #[allow(clippy::declare_interior_mutable_const)] + const START: AtomicRevision = AtomicRevision::start(); + SharedState { + next_id: AtomicU32::new(1), + query_lock: Default::default(), + revisions: [START; Durability::LEN], + pending_revision: START, + dependency_graph: Default::default(), + } } } 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() { - "<unlocked>" - } else if self.query_lock.try_read().is_some() { + let query_lock = if self.query_lock.is_locked_exclusive() { + "<wlocked>" + } else if self.query_lock.is_locked() { "<rlocked>" } else { - "<wlocked>" + "<unlocked>" }; 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 e41eb280dee..dd223eeeba9 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<ActiveQuery>; #[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 91b95dffe78..7ac21dec1a8 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<ActiveQuery> { - 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 6dc5030063b..3dcc32eece3 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 5d0e4866442..677d633ee7c 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 f75c7c142fe..8e2f9b03cb9 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 9a9ebae74e8..0504ca50b88 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<T>(this: &[T]) -> impl Iterator<Item = &[T]> { (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<T> IsNoneOr for Option<T> { + 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 3d33d255ad4..849fae5cf24 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 d81765649ff..b3982bdf2be 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<vscode.TextEditor | undef } export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { - const selections: vscode.Selection[] = []; - let lineDelta = 0; - await editor.edit((builder) => { - 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), - ), +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; + } + }); +} + +/** + * 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, ); - builder.replace(indel.range, newText); - } else { - builder.replace(indel.range, indel.newText); + + 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; } - lineDelta += - countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); + + return snippetEdit; + } else { + return edit; } }); - if (selections.length > 0) editor.selections = selections; - if (selections.length === 1) { - const selection = unwrapUndefinable(selections[0]); - editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport); - } } -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]; +// 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 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 2efafa10a82..285abb9efcb 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 902b2ec6907..4e840dbfbb4 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 99acecdd43c..efb4c5bcb83 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 7572dc6dcf8..e5a925b2cbf 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/tests/assembly/option-nonzero-eq.rs b/tests/assembly/option-nonzero-eq.rs index d6ec586d938..b04cf63fd78 100644 --- a/tests/assembly/option-nonzero-eq.rs +++ b/tests/assembly/option-nonzero-eq.rs @@ -5,7 +5,6 @@ //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 //@ ignore-sgx -//@ ignore-debug use std::cmp::Ordering; diff --git a/tests/assembly/slice-is_ascii.rs b/tests/assembly/slice-is_ascii.rs index 0b764395214..3a050347d89 100644 --- a/tests/assembly/slice-is_ascii.rs +++ b/tests/assembly/slice-is_ascii.rs @@ -5,7 +5,6 @@ //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 //@ ignore-sgx -//@ ignore-debug #![feature(str_internals)] diff --git a/tests/assembly/static-relocation-model.rs b/tests/assembly/static-relocation-model.rs index 975818bf94f..50527b85345 100644 --- a/tests/assembly/static-relocation-model.rs +++ b/tests/assembly/static-relocation-model.rs @@ -6,7 +6,6 @@ //@ [A64] needs-llvm-components: aarch64 //@ [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static //@ [ppc64le] needs-llvm-components: powerpc -//@ ignore-debug: alignment checks insert panics that we don't have a lang item for #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs index 9819dc20966..15b11f413cb 100644 --- a/tests/codegen/align-offset.rs +++ b/tests/codegen/align-offset.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug (debug assertions in `slice::from_raw_parts` block optimizations) #![crate_type = "lib"] diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs index b356f8f33f9..743a15989f7 100644 --- a/tests/codegen/array-map.rs +++ b/tests/codegen/array-map.rs @@ -1,6 +1,5 @@ //@ compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3 //@ only-x86_64 -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs index 30f285096ed..fab9f8632fc 100644 --- a/tests/codegen/ascii-char.rs +++ b/tests/codegen/ascii-char.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=1 -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] #![feature(ascii_char)] diff --git a/tests/codegen/binary-search-index-no-bound-check.rs b/tests/codegen/binary-search-index-no-bound-check.rs index d2627d67142..96f6bb54b3f 100644 --- a/tests/codegen/binary-search-index-no-bound-check.rs +++ b/tests/codegen/binary-search-index-no-bound-check.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] // Make sure no bounds checks are emitted when slicing or indexing diff --git a/tests/codegen/constant-branch.rs b/tests/codegen/constant-branch.rs new file mode 100644 index 00000000000..3328b1eb4a8 --- /dev/null +++ b/tests/codegen/constant-branch.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0 +// make sure that branching on a constant does not emit a conditional +// branch or a switch + +#![crate_type = "lib"] + +// CHECK-LABEL: @if_bool +#[no_mangle] +pub fn if_bool() { + // CHECK: br label %{{.+}} + _ = if true { + 0 + } else { + 1 + }; + + // CHECK: br label %{{.+}} + _ = if false { + 0 + } else { + 1 + }; +} + +// CHECK-LABEL: @if_constant_int_eq +#[no_mangle] +pub fn if_constant_int_eq() { + let val = 0; + // CHECK: br label %{{.+}} + _ = if val == 0 { + 0 + } else { + 1 + }; + + // CHECK: br label %{{.+}} + _ = if val == 1 { + 0 + } else { + 1 + }; +} + +// CHECK-LABEL: @if_constant_match +#[no_mangle] +pub fn if_constant_match() { + // CHECK: br label %{{.+}} + _ = match 1 { + 1 => 2, + 2 => 3, + _ => 4 + }; + + // CHECK: br label %{{.+}} + _ = match 1 { + 2 => 3, + _ => 4 + }; + + // CHECK: br label %[[MINUS1:.+]] + _ = match -1 { + // CHECK: [[MINUS1]]: + // CHECK: store i32 1 + -1 => 1, + _ => 0, + } +} diff --git a/tests/codegen/infallible-unwrap-in-opt-z.rs b/tests/codegen/infallible-unwrap-in-opt-z.rs index cbcba03ad0a..3756fafe384 100644 --- a/tests/codegen/infallible-unwrap-in-opt-z.rs +++ b/tests/codegen/infallible-unwrap-in-opt-z.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=z --edition=2021 -//@ ignore-debug #![crate_type = "lib"] diff --git a/tests/codegen/issue-97217.rs b/tests/codegen/issue-97217.rs index 93dd1228ce1..a0dfff2ef2e 100644 --- a/tests/codegen/issue-97217.rs +++ b/tests/codegen/issue-97217.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=3 -//@ ignore-debug: the debug assertions get in the way //@ min-llvm-version: 17.0.2 #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index 7c96f9a34f8..550d267a98f 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs index 6175d80c9cd..e3843e9edb0 100644 --- a/tests/codegen/issues/issue-101814.rs +++ b/tests/codegen/issues/issue-101814.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs index 5120c5f4e49..fd375e4e605 100644 --- a/tests/codegen/issues/issue-106369.rs +++ b/tests/codegen/issues/issue-106369.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs index 2c561d7be79..a09fac42c01 100644 --- a/tests/codegen/issues/issue-116878.rs +++ b/tests/codegen/issues/issue-116878.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] /// Make sure no bounds checks are emitted after a `get_unchecked`. diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs index 3f750157a81..756a75e2f0e 100644 --- a/tests/codegen/issues/issue-37945.rs +++ b/tests/codegen/issues/issue-37945.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O -Zmerge-functions=disabled //@ ignore-32bit LLVM has a bug with them -//@ ignore-debug // Check that LLVM understands that `Iter` pointer is not null. Issue #37945. diff --git a/tests/codegen/issues/issue-45222.rs b/tests/codegen/issues/issue-45222.rs index 8fa9d87f497..d2c1ba421c4 100644 --- a/tests/codegen/issues/issue-45222.rs +++ b/tests/codegen/issues/issue-45222.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-45466.rs b/tests/codegen/issues/issue-45466.rs index 165bc3ca411..fc714247dfb 100644 --- a/tests/codegen/issues/issue-45466.rs +++ b/tests/codegen/issues/issue-45466.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type="rlib"] diff --git a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs index c9bc7fc316e..b7568bea4d0 100644 --- a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs +++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs @@ -2,7 +2,6 @@ // prevent optimizing away bounds checks //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type="rlib"] diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs index f96a8e9da4b..c014a1c1b1d 100644 --- a/tests/codegen/issues/issue-69101-bounds-check.rs +++ b/tests/codegen/issues/issue-69101-bounds-check.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] // Make sure no bounds checks are emitted in the loop when upfront slicing diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs index bc71e15a41f..48f14fe2dfe 100644 --- a/tests/codegen/issues/issue-73258.rs +++ b/tests/codegen/issues/issue-73258.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs index db91a85474d..ef4538ac84e 100644 --- a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs +++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] // Make sure no bounds checks are emitted when slicing or indexing diff --git a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs index 9f65222b386..40827e32a01 100644 --- a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs +++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: The debug assertions get in the way //@ compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs index d0838a3e860..31020b77984 100644 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ b/tests/codegen/iter-repeat-n-trivial-drop.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] #![feature(iter_repeat_n)] diff --git a/tests/codegen/layout-size-checks.rs b/tests/codegen/layout-size-checks.rs index 55c2e86b40b..901f8f822f3 100644 --- a/tests/codegen/layout-size-checks.rs +++ b/tests/codegen/layout-size-checks.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/lib-optimizations/iter-sum.rs b/tests/codegen/lib-optimizations/iter-sum.rs index 6b6d61a3066..b563a6debb5 100644 --- a/tests/codegen/lib-optimizations/iter-sum.rs +++ b/tests/codegen/lib-optimizations/iter-sum.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: the debug assertions get in the way //@ compile-flags: -O //@ only-x86_64 (vectorization varies between architectures) #![crate_type = "lib"] diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index 0234b63aba5..c71cbbd08f9 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -4,7 +4,7 @@ // known to be `1` after inlining). //@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no -//@ ignore-debug: the debug assertions get in the way +//@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining #![crate_type = "lib"] diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs index b6885aad9e4..b00fbad05d9 100644 --- a/tests/codegen/mem-replace-simple-type.rs +++ b/tests/codegen/mem-replace-simple-type.rs @@ -1,6 +1,6 @@ //@ compile-flags: -O -C no-prepopulate-passes //@ only-x86_64 (to not worry about usize differing) -//@ ignore-debug (the debug assertions get in the way) +//@ ignore-debug: precondition checks make mem::replace not a candidate for MIR inlining #![crate_type = "lib"] diff --git a/tests/codegen/ptr-arithmetic.rs b/tests/codegen/ptr-arithmetic.rs index 3a8bfee84ec..6f115d33d8d 100644 --- a/tests/codegen/ptr-arithmetic.rs +++ b/tests/codegen/ptr-arithmetic.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -Z merge-functions=disabled -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs index 622a1cec4ac..4c623dee5e1 100644 --- a/tests/codegen/ptr-read-metadata.rs +++ b/tests/codegen/ptr-read-metadata.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -Z merge-functions=disabled -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/simd/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs index 010500139e5..2edee552ca6 100644 --- a/tests/codegen/simd/simd-wide-sum.rs +++ b/tests/codegen/simd/simd-wide-sum.rs @@ -1,7 +1,6 @@ //@ revisions: llvm mir-opt3 //@ compile-flags: -C opt-level=3 -Z merge-functions=disabled --edition=2021 //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way //@ [mir-opt3]compile-flags: -Zmir-opt-level=3 //@ [mir-opt3]build-pass diff --git a/tests/codegen/simd/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs index e03e2d4ff8d..32e75220d69 100644 --- a/tests/codegen/simd/swap-simd-types.rs +++ b/tests/codegen/simd/swap-simd-types.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O -C target-feature=+avx //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs index c9cd482a9a4..631d18d7809 100644 --- a/tests/codegen/slice-as_chunks.rs +++ b/tests/codegen/slice-as_chunks.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-64bit (because the LLVM type of i64 for usize shows up) -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] #![feature(slice_as_chunks)] diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs index 52714a76a8d..ecce9201071 100644 --- a/tests/codegen/slice-indexing.rs +++ b/tests/codegen/slice-indexing.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-64bit (because the LLVM type of i64 for usize shows up) -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/slice-iter-fold.rs b/tests/codegen/slice-iter-fold.rs index 5a9d789b984..1770cd4a119 100644 --- a/tests/codegen/slice-iter-fold.rs +++ b/tests/codegen/slice-iter-fold.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: the debug assertions get in the way //@ compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs index 43c64511e52..b2a4b2495b6 100644 --- a/tests/codegen/slice-iter-len-eq-zero.rs +++ b/tests/codegen/slice-iter-len-eq-zero.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug: the debug assertions add extra comparisons #![crate_type = "lib"] type Demo = [u8; 3]; diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs index c82ae3b61b4..c960688b00c 100644 --- a/tests/codegen/slice-iter-nonnull.rs +++ b/tests/codegen/slice-iter-nonnull.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug (these add extra checks that make it hard to verify) #![crate_type = "lib"] #![feature(exact_size_is_empty)] diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs index d34aecd1903..371e685ec6c 100644 --- a/tests/codegen/slice-ref-equality.rs +++ b/tests/codegen/slice-ref-equality.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -Zmerge-functions=disabled -//@ ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs index 40bc89bc9d0..21add929f05 100644 --- a/tests/codegen/slice-reverse.rs +++ b/tests/codegen/slice-reverse.rs @@ -1,6 +1,6 @@ //@ compile-flags: -O //@ only-x86_64 -//@ ignore-debug: the debug assertions in from_raw_parts get in the way +//@ ignore-debug: debug assertions prevent generating shufflevector #![crate_type = "lib"] diff --git a/tests/codegen/slice_as_from_ptr_range.rs b/tests/codegen/slice_as_from_ptr_range.rs index cc811e8f589..47c60461c0e 100644 --- a/tests/codegen/slice_as_from_ptr_range.rs +++ b/tests/codegen/slice_as_from_ptr_range.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-64bit (because we're using [ui]size) -//@ ignore-debug (because the assertions get in the way) #![crate_type = "lib"] #![feature(slice_from_ptr_range)] diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs index 20697890814..b182f3ed947 100644 --- a/tests/codegen/swap-large-types.rs +++ b/tests/codegen/swap-large-types.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs index 8d7f9f49eef..5fdf4a5804a 100644 --- a/tests/codegen/swap-small-types.rs +++ b/tests/codegen/swap-small-types.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O -Z merge-functions=disabled //@ only-x86_64 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs index 43d2a55c995..9217def76b5 100644 --- a/tests/codegen/transmute-optimized.rs +++ b/tests/codegen/transmute-optimized.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -Z merge-functions=disabled -//@ ignore-debug #![crate_type = "lib"] diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index 4e351d8d333..9cf2f2b0cb6 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -1,5 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug (because unchecked is checked in debug) #![crate_type = "lib"] #![feature(unchecked_shifts)] diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs index 953ba5e901a..77ef8d2a5fe 100644 --- a/tests/codegen/unwind-landingpad-inline.rs +++ b/tests/codegen/unwind-landingpad-inline.rs @@ -1,6 +1,5 @@ //@ min-llvm-version: 17.0.2 //@ compile-flags: -Copt-level=3 -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] // This test checks that we can inline drop_in_place in diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs index bae344ab01d..f88ed7ae8a5 100644 --- a/tests/codegen/vec-calloc.rs +++ b/tests/codegen/vec-calloc.rs @@ -1,6 +1,5 @@ //@ compile-flags: -O -Z merge-functions=disabled //@ only-x86_64 -//@ ignore-debug #![crate_type = "lib"] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index 3ac2ec13d47..7a175dc4f7e 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -1,4 +1,4 @@ -//@ ignore-debug: the debug assertions get in the way +//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata //@ compile-flags: -O -Z merge-functions=disabled #![crate_type = "lib"] diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index 0c225abd326..e4242c57402 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: the debug assertions get in the way //@ compile-flags: -O #![crate_type="lib"] diff --git a/tests/codegen/vec-iter.rs b/tests/codegen/vec-iter.rs index 47e11af5bc3..310680969c4 100644 --- a/tests/codegen/vec-iter.rs +++ b/tests/codegen/vec-iter.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: the debug assertions get in the way //@ compile-flags: -O #![crate_type = "lib"] #![feature(exact_size_is_empty)] diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index 9cbfbc115b0..77a94b0b429 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -1,4 +1,3 @@ -//@ ignore-debug: the debug assertions get in the way //@ compile-flags: -O #![crate_type = "lib"] diff --git a/tests/codegen/vec-reserve-extend.rs b/tests/codegen/vec-reserve-extend.rs index 12795937bc8..1f00f7d2063 100644 --- a/tests/codegen/vec-reserve-extend.rs +++ b/tests/codegen/vec-reserve-extend.rs @@ -1,6 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug -// (with debug assertions turned on, `assert_unchecked` generates a real assertion) #![crate_type = "lib"] diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index 33b70300bf4..4e996b234f9 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -4,7 +4,7 @@ //@ [old]ignore-llvm-version: 17 - 99 //@ [new]min-llvm-version: 17 //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way +//@ ignore-debug: plain old debug assertions //@ needs-unwind #![crate_type = "lib"] #![feature(shrink_to)] diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs index 5a2009b01d7..83765d10854 100644 --- a/tests/codegen/vec_pop_push_noop.rs +++ b/tests/codegen/vec_pop_push_noop.rs @@ -1,6 +1,4 @@ //@ compile-flags: -O -//@ ignore-debug -// (with debug assertions turned on, `assert_unchecked` generates a real assertion) #![crate_type = "lib"] diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs index cd549f8ebd4..31fcf035f11 100644 --- a/tests/codegen/vecdeque-drain.rs +++ b/tests/codegen/vecdeque-drain.rs @@ -1,7 +1,7 @@ // Check that draining at the front or back doesn't copy memory. //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way +//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata #![crate_type = "lib"] diff --git a/tests/codegen/vecdeque-nonempty-get-no-panic.rs b/tests/codegen/vecdeque-nonempty-get-no-panic.rs index 1128b4ed7a4..3f802de9eee 100644 --- a/tests/codegen/vecdeque-nonempty-get-no-panic.rs +++ b/tests/codegen/vecdeque-nonempty-get-no-panic.rs @@ -1,7 +1,6 @@ // Guards against regression for optimization discussed in issue #80836 //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs index 57b6b2abbea..be2c4810ebc 100644 --- a/tests/codegen/vecdeque_no_panic.rs +++ b/tests/codegen/vecdeque_no_panic.rs @@ -1,7 +1,7 @@ // This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. //@ compile-flags: -O -//@ ignore-debug: the debug assertions get in the way +//@ ignore-debug: plain old debug assertions #![crate_type = "lib"] diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs index bf4a74085ed..6c391d9114b 100644 --- a/tests/codegen/virtual-function-elimination.rs +++ b/tests/codegen/virtual-function-elimination.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0 //@ ignore-32bit -//@ ignore-debug // CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] // CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]] diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff new file mode 100644 index 00000000000..dd79cff1dcf --- /dev/null +++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff @@ -0,0 +1,19 @@ +- // MIR for `caller` before Inline ++ // MIR for `caller` after Inline + + fn caller() -> () { + let mut _0: (); + let _1: (); + + bb0: { + StorageLive(_1); + _1 = callee() -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff new file mode 100644 index 00000000000..4506a338edd --- /dev/null +++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff @@ -0,0 +1,19 @@ +- // MIR for `caller` before Inline ++ // MIR for `caller` after Inline + + fn caller() -> () { + let mut _0: (); + let _1: (); + + bb0: { + StorageLive(_1); + _1 = callee() -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir new file mode 100644 index 00000000000..d0772e51a07 --- /dev/null +++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir @@ -0,0 +1,14 @@ +// MIR for `caller` after PreCodegen + +fn caller() -> () { + let mut _0: (); + let _1: (); + + bb0: { + _1 = callee() -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } +} diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir new file mode 100644 index 00000000000..39ad4f1010b --- /dev/null +++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,14 @@ +// MIR for `caller` after PreCodegen + +fn caller() -> () { + let mut _0: (); + let _1: (); + + bb0: { + _1 = callee() -> [return: bb1, unwind continue]; + } + + bb1: { + return; + } +} diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.rs b/tests/mir-opt/inline/rustc_no_mir_inline.rs new file mode 100644 index 00000000000..b008df32726 --- /dev/null +++ b/tests/mir-opt/inline/rustc_no_mir_inline.rs @@ -0,0 +1,17 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir + +#[inline] +#[rustc_no_mir_inline] +pub fn callee() {} + +// EMIT_MIR rustc_no_mir_inline.caller.Inline.diff +// EMIT_MIR rustc_no_mir_inline.caller.PreCodegen.after.mir +pub fn caller() { + // CHECK-LABEL: fn caller( + // CHECK: callee() + callee(); +} diff --git a/tests/mir-opt/pre-codegen/slice_filter.rs b/tests/mir-opt/pre-codegen/slice_filter.rs index 45686f0bf88..35881ff2b18 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.rs +++ b/tests/mir-opt/pre-codegen/slice_filter.rs @@ -1,6 +1,5 @@ // skip-filecheck //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=2 -//@ ignore-debug: standard library debug assertions add a panic that breaks this optimization #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 7370da5629c..65cac0a81ef 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -1,6 +1,6 @@ // MIR for `variant_a::{closure#0}` after PreCodegen -fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:8:25: 8:39}, _2: &&(usize, usize, usize, usize)) -> bool { +fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; let mut _3: &(usize, usize, usize, usize); let _4: &usize; diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir index 5477796512c..d9e118d879a 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir @@ -1,6 +1,6 @@ // MIR for `variant_b::{closure#0}` after PreCodegen -fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:12:25: 12:41}, _2: &&(usize, usize, usize, usize)) -> bool { +fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; let mut _3: &(usize, usize, usize, usize); let _4: usize; diff --git a/tests/ui/cfg/cfg-target-abi.rs b/tests/ui/cfg/cfg-target-abi.rs index 5d13337c1c3..306ae077325 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 0c55e35a993..859a36c604c 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 6535cd9a1a1..5f52421fef5 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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 <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> 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/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs index 048fca762d5..62efce64876 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<T> { Some(*const T), // Can also use PhantomData<T> @@ -15,8 +11,7 @@ const C: &[O<B>] = &[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 9c80cb3a849..7d5e5b5b0c6 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<B>]` in a pattern, the type must implement `PartialEq` - --> $DIR/issue-65466.rs:18:9 +error: to use a constant of type `&[O<B>]` 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 <https://github.com/rust-lang/rust/issues/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<B>]` 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 <https://github.com/rust-lang/rust/issues/116122> - = note: `#[warn(const_patterns_without_partial_eq)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs index 907617052f1..47a06e8a72b 100644 --- a/tests/ui/consts/promote-not.rs +++ b/tests/ui/consts/promote-not.rs @@ -49,6 +49,10 @@ fn main() { // No promotion of fallible operations. let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &((1+1)/(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(i32::MIN/-1); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(i32::MIN/(0-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(-128i8/-1); //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index 524d6981721..67ac5922efd 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -105,6 +105,50 @@ LL | } error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:52:29 | +LL | let _val: &'static _ = &((1+1)/(1-1)); + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:53:29 + | +LL | let _val: &'static _ = &(i32::MIN/-1); + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:54:29 + | +LL | let _val: &'static _ = &(i32::MIN/(0-1)); + | ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:55:29 + | +LL | let _val: &'static _ = &(-128i8/-1); + | ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:56:29 + | LL | let _val: &'static _ = &(1%0); | ---------- ^^^^^ creates a temporary value which is freed while still in use | | @@ -114,7 +158,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:53:29 + --> $DIR/promote-not.rs:57:29 | LL | let _val: &'static _ = &(1%(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -125,7 +169,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:54:29 + --> $DIR/promote-not.rs:58:29 | LL | let _val: &'static _ = &([1,2,3][4]+1); | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -136,7 +180,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:57:29 + --> $DIR/promote-not.rs:61:29 | LL | let _val: &'static _ = &TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -147,7 +191,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:59:29 + --> $DIR/promote-not.rs:63:29 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -158,7 +202,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:59:30 + --> $DIR/promote-not.rs:63:30 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -169,7 +213,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:62:29 + --> $DIR/promote-not.rs:66:29 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -180,7 +224,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:62:31 + --> $DIR/promote-not.rs:66:31 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -191,7 +235,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:29 + --> $DIR/promote-not.rs:69:29 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -202,7 +246,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:31 + --> $DIR/promote-not.rs:69:31 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement @@ -210,6 +254,6 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1]; | | creates a temporary value which is freed while still in use | type annotation requires that borrow lasts for `'static` -error: aborting due to 20 previous errors +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promotion.rs b/tests/ui/consts/promotion.rs index 211dcf8a4e8..b18495a4a6b 100644 --- a/tests/ui/consts/promotion.rs +++ b/tests/ui/consts/promotion.rs @@ -28,8 +28,11 @@ fn main() { // make sure that this does not cause trouble despite overflowing assert_static(&(0-1)); - // div-by-non-0 is okay + // div-by-non-0 (and also not MIN/-1) is okay assert_static(&(1/1)); + assert_static(&(0/1)); + assert_static(&(1/-1)); + assert_static(&(i32::MIN/1)); assert_static(&(1%1)); // in-bounds array access is okay 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 d005dc3ad45..00000000000 --- 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 4829f8572cc..00000000000 --- 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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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/impl-trait/in-trait/async-and-ret-ref.stderr b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr index 79a86b0a3ae..15aa3cf54bb 100644 --- a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr +++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr @@ -6,8 +6,6 @@ LL | async fn foo() -> &'static impl T; | | | the associated type `<Self as MyTrait>::{opaque#0}` must be valid for the static lifetime... | ...so that the reference type `&'static impl T` does not outlive the data it points at - | - = help: consider adding an explicit lifetime bound `<Self as MyTrait>::{opaque#0}: 'static`... error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs new file mode 100644 index 00000000000..a36799c3ebd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs @@ -0,0 +1,16 @@ +trait Original { + fn f() -> impl Fn(); +} + +trait Erased { + fn f(&self) -> Box<dyn Fn()>; +} + +impl<T: Original> Erased for T { + fn f(&self) -> Box<dyn Fn()> { + Box::new(<T as Original>::f()) + //~^ ERROR the associated type `<T as Original>::{opaque#0}` may not live long enough + } +} + +fn main () {} diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr new file mode 100644 index 00000000000..5ec0ee38347 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr @@ -0,0 +1,12 @@ +error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough + --> $DIR/missing-static-bound-from-impl.rs:11:9 + | +LL | Box::new(<T as Original>::f()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime... + | ...so that the type `impl Fn()` will meet its required lifetime bounds + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/lint/lint-overflowing-ops.noopt.stderr b/tests/ui/lint/lint-overflowing-ops.noopt.stderr index f89ee8569c6..1b7b73cec38 100644 --- a/tests/ui/lint/lint-overflowing-ops.noopt.stderr +++ b/tests/ui/lint/lint-overflowing-ops.noopt.stderr @@ -876,498 +876,353 @@ error: this operation will panic at runtime LL | let _n = &(i8::MIN / -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:251:15 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:251:14 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:254:14 + --> $DIR/lint-overflowing-ops.rs:253:14 | LL | let _n = 1i16 / 0; | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:255:15 + --> $DIR/lint-overflowing-ops.rs:254:15 | LL | let _n = &(1i16 / 0); | ^^^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:256:14 + --> $DIR/lint-overflowing-ops.rs:255:14 | LL | let _n = i16::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:257:15 + --> $DIR/lint-overflowing-ops.rs:256:15 | LL | let _n = &(i16::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:257:15 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:257:14 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:260:14 + --> $DIR/lint-overflowing-ops.rs:258:14 | LL | let _n = 1i32 / 0; | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:261:15 + --> $DIR/lint-overflowing-ops.rs:259:15 | LL | let _n = &(1i32 / 0); | ^^^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:262:14 + --> $DIR/lint-overflowing-ops.rs:260:14 | LL | let _n = i32::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:263:15 + --> $DIR/lint-overflowing-ops.rs:261:15 | LL | let _n = &(i32::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:263:15 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:263:14 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:266:14 + --> $DIR/lint-overflowing-ops.rs:263:14 | LL | let _n = 1i64 / 0; | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:267:15 + --> $DIR/lint-overflowing-ops.rs:264:15 | LL | let _n = &(1i64 / 0); | ^^^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:268:14 + --> $DIR/lint-overflowing-ops.rs:265:14 | LL | let _n = i64::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:269:15 + --> $DIR/lint-overflowing-ops.rs:266:15 | LL | let _n = &(i64::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:269:15 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:269:14 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:272:14 + --> $DIR/lint-overflowing-ops.rs:268:14 | LL | let _n = 1i128 / 0; | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:273:15 + --> $DIR/lint-overflowing-ops.rs:269:15 | LL | let _n = &(1i128 / 0); | ^^^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:274:14 + --> $DIR/lint-overflowing-ops.rs:270:14 | LL | let _n = i128::MIN / -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:275:15 + --> $DIR/lint-overflowing-ops.rs:271:15 | LL | let _n = &(i128::MIN / -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:275:15 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:275:14 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:278:14 + --> $DIR/lint-overflowing-ops.rs:273:14 | LL | let _n = 1isize / 0; | ^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:279:15 + --> $DIR/lint-overflowing-ops.rs:274:15 | LL | let _n = &(1isize / 0); | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:280:14 + --> $DIR/lint-overflowing-ops.rs:275:14 | LL | let _n = isize::MIN / -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:281:15 + --> $DIR/lint-overflowing-ops.rs:276:15 | LL | let _n = &(isize::MIN / -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:281:15 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:281:14 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:286:14 + --> $DIR/lint-overflowing-ops.rs:280:14 | LL | let _n = 1u8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:287:15 + --> $DIR/lint-overflowing-ops.rs:281:15 | LL | let _n = &(1u8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:289:14 + --> $DIR/lint-overflowing-ops.rs:283:14 | LL | let _n = 1u16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:290:15 + --> $DIR/lint-overflowing-ops.rs:284:15 | LL | let _n = &(1u16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:292:14 + --> $DIR/lint-overflowing-ops.rs:286:14 | LL | let _n = 1u32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:293:15 + --> $DIR/lint-overflowing-ops.rs:287:15 | LL | let _n = &(1u32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:295:14 + --> $DIR/lint-overflowing-ops.rs:289:14 | LL | let _n = 1u64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:296:15 + --> $DIR/lint-overflowing-ops.rs:290:15 | LL | let _n = &(1u64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:298:14 + --> $DIR/lint-overflowing-ops.rs:292:14 | LL | let _n = 1u128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:299:15 + --> $DIR/lint-overflowing-ops.rs:293:15 | LL | let _n = &(1u128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:301:14 + --> $DIR/lint-overflowing-ops.rs:295:14 | LL | let _n = 1usize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:302:15 + --> $DIR/lint-overflowing-ops.rs:296:15 | LL | let _n = &(1usize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:304:14 + --> $DIR/lint-overflowing-ops.rs:298:14 | LL | let _n = 1i8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:305:15 + --> $DIR/lint-overflowing-ops.rs:299:15 | LL | let _n = &(1i8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:306:14 + --> $DIR/lint-overflowing-ops.rs:300:14 | LL | let _n = i8::MIN % -1; | ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:307:15 + --> $DIR/lint-overflowing-ops.rs:301:15 | LL | let _n = &(i8::MIN % -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:307:15 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:307:14 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:310:14 + --> $DIR/lint-overflowing-ops.rs:303:14 | LL | let _n = 1i16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:311:15 + --> $DIR/lint-overflowing-ops.rs:304:15 | LL | let _n = &(1i16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:312:14 + --> $DIR/lint-overflowing-ops.rs:305:14 | LL | let _n = i16::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:313:15 + --> $DIR/lint-overflowing-ops.rs:306:15 | LL | let _n = &(i16::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:313:15 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:313:14 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:316:14 + --> $DIR/lint-overflowing-ops.rs:308:14 | LL | let _n = 1i32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:317:15 + --> $DIR/lint-overflowing-ops.rs:309:15 | LL | let _n = &(1i32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:318:14 + --> $DIR/lint-overflowing-ops.rs:310:14 | LL | let _n = i32::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:319:15 + --> $DIR/lint-overflowing-ops.rs:311:15 | LL | let _n = &(i32::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:319:15 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:319:14 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:322:14 + --> $DIR/lint-overflowing-ops.rs:313:14 | LL | let _n = 1i64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:323:15 + --> $DIR/lint-overflowing-ops.rs:314:15 | LL | let _n = &(1i64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:324:14 + --> $DIR/lint-overflowing-ops.rs:315:14 | LL | let _n = i64::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:325:15 + --> $DIR/lint-overflowing-ops.rs:316:15 | LL | let _n = &(i64::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:325:15 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:325:14 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:328:14 + --> $DIR/lint-overflowing-ops.rs:318:14 | LL | let _n = 1i128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:329:15 + --> $DIR/lint-overflowing-ops.rs:319:15 | LL | let _n = &(1i128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:330:14 + --> $DIR/lint-overflowing-ops.rs:320:14 | LL | let _n = i128::MIN % -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:331:15 + --> $DIR/lint-overflowing-ops.rs:321:15 | LL | let _n = &(i128::MIN % -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:331:15 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:331:14 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:334:14 + --> $DIR/lint-overflowing-ops.rs:323:14 | LL | let _n = 1isize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:335:15 + --> $DIR/lint-overflowing-ops.rs:324:15 | LL | let _n = &(1isize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:336:14 + --> $DIR/lint-overflowing-ops.rs:325:14 | LL | let _n = isize::MIN % -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:337:15 + --> $DIR/lint-overflowing-ops.rs:326:15 | LL | let _n = &(isize::MIN % -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:337:15 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:337:14 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:341:14 + --> $DIR/lint-overflowing-ops.rs:329:14 | LL | let _n = [1, 2, 3][4]; | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:342:15 + --> $DIR/lint-overflowing-ops.rs:330:15 | LL | let _n = &([1, 2, 3][4]); | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 -error: aborting due to 215 previous errors +error: aborting due to 203 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/lint/lint-overflowing-ops.opt.stderr b/tests/ui/lint/lint-overflowing-ops.opt.stderr index 7ac5c4e0d76..1b7b73cec38 100644 --- a/tests/ui/lint/lint-overflowing-ops.opt.stderr +++ b/tests/ui/lint/lint-overflowing-ops.opt.stderr @@ -876,594 +876,353 @@ error: this operation will panic at runtime LL | let _n = &(i8::MIN / -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:251:15 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:251:14 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:251:14 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:254:14 + --> $DIR/lint-overflowing-ops.rs:253:14 | LL | let _n = 1i16 / 0; | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:255:15 + --> $DIR/lint-overflowing-ops.rs:254:15 | LL | let _n = &(1i16 / 0); | ^^^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:256:14 + --> $DIR/lint-overflowing-ops.rs:255:14 | LL | let _n = i16::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:257:15 + --> $DIR/lint-overflowing-ops.rs:256:15 | LL | let _n = &(i16::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:257:15 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:257:14 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:257:14 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:260:14 + --> $DIR/lint-overflowing-ops.rs:258:14 | LL | let _n = 1i32 / 0; | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:261:15 + --> $DIR/lint-overflowing-ops.rs:259:15 | LL | let _n = &(1i32 / 0); | ^^^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:262:14 + --> $DIR/lint-overflowing-ops.rs:260:14 | LL | let _n = i32::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:263:15 + --> $DIR/lint-overflowing-ops.rs:261:15 | LL | let _n = &(i32::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:263:15 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:263:14 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:263:14 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:266:14 + --> $DIR/lint-overflowing-ops.rs:263:14 | LL | let _n = 1i64 / 0; | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:267:15 + --> $DIR/lint-overflowing-ops.rs:264:15 | LL | let _n = &(1i64 / 0); | ^^^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:268:14 + --> $DIR/lint-overflowing-ops.rs:265:14 | LL | let _n = i64::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:269:15 + --> $DIR/lint-overflowing-ops.rs:266:15 | LL | let _n = &(i64::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:269:15 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:269:14 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:269:14 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:272:14 + --> $DIR/lint-overflowing-ops.rs:268:14 | LL | let _n = 1i128 / 0; | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:273:15 + --> $DIR/lint-overflowing-ops.rs:269:15 | LL | let _n = &(1i128 / 0); | ^^^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:274:14 + --> $DIR/lint-overflowing-ops.rs:270:14 | LL | let _n = i128::MIN / -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:275:15 + --> $DIR/lint-overflowing-ops.rs:271:15 | LL | let _n = &(i128::MIN / -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:275:15 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:275:14 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:275:14 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:278:14 + --> $DIR/lint-overflowing-ops.rs:273:14 | LL | let _n = 1isize / 0; | ^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:279:15 + --> $DIR/lint-overflowing-ops.rs:274:15 | LL | let _n = &(1isize / 0); | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:280:14 + --> $DIR/lint-overflowing-ops.rs:275:14 | LL | let _n = isize::MIN / -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:281:15 + --> $DIR/lint-overflowing-ops.rs:276:15 | LL | let _n = &(isize::MIN / -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:281:15 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:281:14 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:281:14 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:286:14 + --> $DIR/lint-overflowing-ops.rs:280:14 | LL | let _n = 1u8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:287:15 + --> $DIR/lint-overflowing-ops.rs:281:15 | LL | let _n = &(1u8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:289:14 + --> $DIR/lint-overflowing-ops.rs:283:14 | LL | let _n = 1u16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:290:15 + --> $DIR/lint-overflowing-ops.rs:284:15 | LL | let _n = &(1u16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:292:14 + --> $DIR/lint-overflowing-ops.rs:286:14 | LL | let _n = 1u32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:293:15 + --> $DIR/lint-overflowing-ops.rs:287:15 | LL | let _n = &(1u32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:295:14 + --> $DIR/lint-overflowing-ops.rs:289:14 | LL | let _n = 1u64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:296:15 + --> $DIR/lint-overflowing-ops.rs:290:15 | LL | let _n = &(1u64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:298:14 + --> $DIR/lint-overflowing-ops.rs:292:14 | LL | let _n = 1u128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:299:15 + --> $DIR/lint-overflowing-ops.rs:293:15 | LL | let _n = &(1u128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:301:14 + --> $DIR/lint-overflowing-ops.rs:295:14 | LL | let _n = 1usize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:302:15 + --> $DIR/lint-overflowing-ops.rs:296:15 | LL | let _n = &(1usize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:304:14 + --> $DIR/lint-overflowing-ops.rs:298:14 | LL | let _n = 1i8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:305:15 + --> $DIR/lint-overflowing-ops.rs:299:15 | LL | let _n = &(1i8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:306:14 + --> $DIR/lint-overflowing-ops.rs:300:14 | LL | let _n = i8::MIN % -1; | ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:307:15 + --> $DIR/lint-overflowing-ops.rs:301:15 | LL | let _n = &(i8::MIN % -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:307:15 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:307:14 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:307:14 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:310:14 + --> $DIR/lint-overflowing-ops.rs:303:14 | LL | let _n = 1i16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:311:15 + --> $DIR/lint-overflowing-ops.rs:304:15 | LL | let _n = &(1i16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:312:14 + --> $DIR/lint-overflowing-ops.rs:305:14 | LL | let _n = i16::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:313:15 + --> $DIR/lint-overflowing-ops.rs:306:15 | LL | let _n = &(i16::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:313:15 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:313:14 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:313:14 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:316:14 + --> $DIR/lint-overflowing-ops.rs:308:14 | LL | let _n = 1i32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:317:15 + --> $DIR/lint-overflowing-ops.rs:309:15 | LL | let _n = &(1i32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:318:14 + --> $DIR/lint-overflowing-ops.rs:310:14 | LL | let _n = i32::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:319:15 + --> $DIR/lint-overflowing-ops.rs:311:15 | LL | let _n = &(i32::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:319:15 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:319:14 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:319:14 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:322:14 + --> $DIR/lint-overflowing-ops.rs:313:14 | LL | let _n = 1i64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:323:15 + --> $DIR/lint-overflowing-ops.rs:314:15 | LL | let _n = &(1i64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:324:14 + --> $DIR/lint-overflowing-ops.rs:315:14 | LL | let _n = i64::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:325:15 + --> $DIR/lint-overflowing-ops.rs:316:15 | LL | let _n = &(i64::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:325:15 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:325:14 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:325:14 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:328:14 + --> $DIR/lint-overflowing-ops.rs:318:14 | LL | let _n = 1i128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:329:15 + --> $DIR/lint-overflowing-ops.rs:319:15 | LL | let _n = &(1i128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:330:14 + --> $DIR/lint-overflowing-ops.rs:320:14 | LL | let _n = i128::MIN % -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:331:15 + --> $DIR/lint-overflowing-ops.rs:321:15 | LL | let _n = &(i128::MIN % -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:331:15 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:331:14 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:331:14 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:334:14 + --> $DIR/lint-overflowing-ops.rs:323:14 | LL | let _n = 1isize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:335:15 + --> $DIR/lint-overflowing-ops.rs:324:15 | LL | let _n = &(1isize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:336:14 + --> $DIR/lint-overflowing-ops.rs:325:14 | LL | let _n = isize::MIN % -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:337:15 + --> $DIR/lint-overflowing-ops.rs:326:15 | LL | let _n = &(isize::MIN % -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:337:15 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:337:14 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^^ - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:337:14 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:341:14 + --> $DIR/lint-overflowing-ops.rs:329:14 | LL | let _n = [1, 2, 3][4]; | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:342:15 + --> $DIR/lint-overflowing-ops.rs:330:15 | LL | let _n = &([1, 2, 3][4]); | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 -error: aborting due to 215 previous errors +error: aborting due to 203 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr b/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr index f89ee8569c6..1b7b73cec38 100644 --- a/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr +++ b/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr @@ -876,498 +876,353 @@ error: this operation will panic at runtime LL | let _n = &(i8::MIN / -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:251:15 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:251:14 - | -LL | let _n = &(i8::MIN / -1); - | ^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:254:14 + --> $DIR/lint-overflowing-ops.rs:253:14 | LL | let _n = 1i16 / 0; | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:255:15 + --> $DIR/lint-overflowing-ops.rs:254:15 | LL | let _n = &(1i16 / 0); | ^^^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:256:14 + --> $DIR/lint-overflowing-ops.rs:255:14 | LL | let _n = i16::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:257:15 + --> $DIR/lint-overflowing-ops.rs:256:15 | LL | let _n = &(i16::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:257:15 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:257:14 - | -LL | let _n = &(i16::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:260:14 + --> $DIR/lint-overflowing-ops.rs:258:14 | LL | let _n = 1i32 / 0; | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:261:15 + --> $DIR/lint-overflowing-ops.rs:259:15 | LL | let _n = &(1i32 / 0); | ^^^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:262:14 + --> $DIR/lint-overflowing-ops.rs:260:14 | LL | let _n = i32::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:263:15 + --> $DIR/lint-overflowing-ops.rs:261:15 | LL | let _n = &(i32::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:263:15 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:263:14 - | -LL | let _n = &(i32::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:266:14 + --> $DIR/lint-overflowing-ops.rs:263:14 | LL | let _n = 1i64 / 0; | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:267:15 + --> $DIR/lint-overflowing-ops.rs:264:15 | LL | let _n = &(1i64 / 0); | ^^^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:268:14 + --> $DIR/lint-overflowing-ops.rs:265:14 | LL | let _n = i64::MIN / -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:269:15 + --> $DIR/lint-overflowing-ops.rs:266:15 | LL | let _n = &(i64::MIN / -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:269:15 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:269:14 - | -LL | let _n = &(i64::MIN / -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:272:14 + --> $DIR/lint-overflowing-ops.rs:268:14 | LL | let _n = 1i128 / 0; | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:273:15 + --> $DIR/lint-overflowing-ops.rs:269:15 | LL | let _n = &(1i128 / 0); | ^^^^^^^^^^^ attempt to divide `1_i128` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:274:14 + --> $DIR/lint-overflowing-ops.rs:270:14 | LL | let _n = i128::MIN / -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:275:15 + --> $DIR/lint-overflowing-ops.rs:271:15 | LL | let _n = &(i128::MIN / -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:275:15 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:275:14 - | -LL | let _n = &(i128::MIN / -1); - | ^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:278:14 + --> $DIR/lint-overflowing-ops.rs:273:14 | LL | let _n = 1isize / 0; | ^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:279:15 + --> $DIR/lint-overflowing-ops.rs:274:15 | LL | let _n = &(1isize / 0); | ^^^^^^^^^^^^ attempt to divide `1_isize` by zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:280:14 + --> $DIR/lint-overflowing-ops.rs:275:14 | LL | let _n = isize::MIN / -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:281:15 + --> $DIR/lint-overflowing-ops.rs:276:15 | LL | let _n = &(isize::MIN / -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:281:15 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:281:14 - | -LL | let _n = &(isize::MIN / -1); - | ^^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:286:14 + --> $DIR/lint-overflowing-ops.rs:280:14 | LL | let _n = 1u8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:287:15 + --> $DIR/lint-overflowing-ops.rs:281:15 | LL | let _n = &(1u8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:289:14 + --> $DIR/lint-overflowing-ops.rs:283:14 | LL | let _n = 1u16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:290:15 + --> $DIR/lint-overflowing-ops.rs:284:15 | LL | let _n = &(1u16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:292:14 + --> $DIR/lint-overflowing-ops.rs:286:14 | LL | let _n = 1u32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:293:15 + --> $DIR/lint-overflowing-ops.rs:287:15 | LL | let _n = &(1u32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:295:14 + --> $DIR/lint-overflowing-ops.rs:289:14 | LL | let _n = 1u64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:296:15 + --> $DIR/lint-overflowing-ops.rs:290:15 | LL | let _n = &(1u64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:298:14 + --> $DIR/lint-overflowing-ops.rs:292:14 | LL | let _n = 1u128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:299:15 + --> $DIR/lint-overflowing-ops.rs:293:15 | LL | let _n = &(1u128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:301:14 + --> $DIR/lint-overflowing-ops.rs:295:14 | LL | let _n = 1usize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:302:15 + --> $DIR/lint-overflowing-ops.rs:296:15 | LL | let _n = &(1usize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:304:14 + --> $DIR/lint-overflowing-ops.rs:298:14 | LL | let _n = 1i8 % 0; | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:305:15 + --> $DIR/lint-overflowing-ops.rs:299:15 | LL | let _n = &(1i8 % 0); | ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:306:14 + --> $DIR/lint-overflowing-ops.rs:300:14 | LL | let _n = i8::MIN % -1; | ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:307:15 + --> $DIR/lint-overflowing-ops.rs:301:15 | LL | let _n = &(i8::MIN % -1); | ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:307:15 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:307:14 - | -LL | let _n = &(i8::MIN % -1); - | ^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:310:14 + --> $DIR/lint-overflowing-ops.rs:303:14 | LL | let _n = 1i16 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:311:15 + --> $DIR/lint-overflowing-ops.rs:304:15 | LL | let _n = &(1i16 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:312:14 + --> $DIR/lint-overflowing-ops.rs:305:14 | LL | let _n = i16::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:313:15 + --> $DIR/lint-overflowing-ops.rs:306:15 | LL | let _n = &(i16::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:313:15 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:313:14 - | -LL | let _n = &(i16::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:316:14 + --> $DIR/lint-overflowing-ops.rs:308:14 | LL | let _n = 1i32 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:317:15 + --> $DIR/lint-overflowing-ops.rs:309:15 | LL | let _n = &(1i32 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:318:14 + --> $DIR/lint-overflowing-ops.rs:310:14 | LL | let _n = i32::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:319:15 + --> $DIR/lint-overflowing-ops.rs:311:15 | LL | let _n = &(i32::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:319:15 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:319:14 - | -LL | let _n = &(i32::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:322:14 + --> $DIR/lint-overflowing-ops.rs:313:14 | LL | let _n = 1i64 % 0; | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:323:15 + --> $DIR/lint-overflowing-ops.rs:314:15 | LL | let _n = &(1i64 % 0); | ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:324:14 + --> $DIR/lint-overflowing-ops.rs:315:14 | LL | let _n = i64::MIN % -1; | ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:325:15 + --> $DIR/lint-overflowing-ops.rs:316:15 | LL | let _n = &(i64::MIN % -1); | ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:325:15 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:325:14 - | -LL | let _n = &(i64::MIN % -1); - | ^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:328:14 + --> $DIR/lint-overflowing-ops.rs:318:14 | LL | let _n = 1i128 % 0; | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:329:15 + --> $DIR/lint-overflowing-ops.rs:319:15 | LL | let _n = &(1i128 % 0); | ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:330:14 + --> $DIR/lint-overflowing-ops.rs:320:14 | LL | let _n = i128::MIN % -1; | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:331:15 + --> $DIR/lint-overflowing-ops.rs:321:15 | LL | let _n = &(i128::MIN % -1); | ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:331:15 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:331:14 - | -LL | let _n = &(i128::MIN % -1); - | ^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:334:14 + --> $DIR/lint-overflowing-ops.rs:323:14 | LL | let _n = 1isize % 0; | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:335:15 + --> $DIR/lint-overflowing-ops.rs:324:15 | LL | let _n = &(1isize % 0); | ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:336:14 + --> $DIR/lint-overflowing-ops.rs:325:14 | LL | let _n = isize::MIN % -1; | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:337:15 + --> $DIR/lint-overflowing-ops.rs:326:15 | LL | let _n = &(isize::MIN % -1); | ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow -error[E0080]: evaluation of constant value failed - --> $DIR/lint-overflowing-ops.rs:337:15 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) - -note: erroneous constant encountered - --> $DIR/lint-overflowing-ops.rs:337:14 - | -LL | let _n = &(isize::MIN % -1); - | ^^^^^^^^^^^^^^^^^^ - error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:341:14 + --> $DIR/lint-overflowing-ops.rs:329:14 | LL | let _n = [1, 2, 3][4]; | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 error: this operation will panic at runtime - --> $DIR/lint-overflowing-ops.rs:342:15 + --> $DIR/lint-overflowing-ops.rs:330:15 | LL | let _n = &([1, 2, 3][4]); | ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 -error: aborting due to 215 previous errors +error: aborting due to 203 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/lint/lint-overflowing-ops.rs b/tests/ui/lint/lint-overflowing-ops.rs index 4ef99f6c5fa..3aadf773243 100644 --- a/tests/ui/lint/lint-overflowing-ops.rs +++ b/tests/ui/lint/lint-overflowing-ops.rs @@ -249,37 +249,31 @@ fn main() { let _n = &(1i8 / 0); //~ ERROR: this operation will panic at runtime let _n = i8::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(i8::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i16 / 0; //~ ERROR: this operation will panic at runtime let _n = &(1i16 / 0); //~ ERROR: this operation will panic at runtime let _n = i16::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(i16::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i32 / 0; //~ ERROR: this operation will panic at runtime let _n = &(1i32 / 0); //~ ERROR: this operation will panic at runtime let _n = i32::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(i32::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i64 / 0; //~ ERROR: this operation will panic at runtime let _n = &(1i64 / 0); //~ ERROR: this operation will panic at runtime let _n = i64::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(i64::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i128 / 0; //~ ERROR: this operation will panic at runtime let _n = &(1i128 / 0); //~ ERROR: this operation will panic at runtime let _n = i128::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(i128::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1isize / 0; //~ ERROR: this operation will panic at runtime let _n = &(1isize / 0); //~ ERROR: this operation will panic at runtime let _n = isize::MIN / -1; //~ ERROR: this operation will panic at runtime let _n = &(isize::MIN / -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed // Modulus @@ -305,37 +299,31 @@ fn main() { let _n = &(1i8 % 0); //~ ERROR: this operation will panic at runtime let _n = i8::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(i8::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i16 % 0; //~ ERROR: this operation will panic at runtime let _n = &(1i16 % 0); //~ ERROR: this operation will panic at runtime let _n = i16::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(i16::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i32 % 0; //~ ERROR: this operation will panic at runtime let _n = &(1i32 % 0); //~ ERROR: this operation will panic at runtime let _n = i32::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(i32::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i64 % 0; //~ ERROR: this operation will panic at runtime let _n = &(1i64 % 0); //~ ERROR: this operation will panic at runtime let _n = i64::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(i64::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1i128 % 0; //~ ERROR: this operation will panic at runtime let _n = &(1i128 % 0); //~ ERROR: this operation will panic at runtime let _n = i128::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(i128::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed let _n = 1isize % 0; //~ ERROR: this operation will panic at runtime let _n = &(1isize % 0); //~ ERROR: this operation will panic at runtime let _n = isize::MIN % -1; //~ ERROR: this operation will panic at runtime let _n = &(isize::MIN % -1); //~ ERROR: this operation will panic at runtime - //~^ERROR: evaluation of constant value failed // Out of bounds access let _n = [1, 2, 3][4]; //~ ERROR: this operation will panic at runtime 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 d4972714608..f15eae83896 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<Enum8> = 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 a7fc0cfc054..4155586c160 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<Enum8>` 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<Enum8>` 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 <https://github.com/rust-lang/rust/issues/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<Enum8>` 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 <https://github.com/rust-lang/rust/issues/116122> - = note: `#[warn(const_patterns_without_partial_eq)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.rs b/tests/ui/simd/not-out-of-bounds.rs index 158e9956435..36d7a5865bc 100644 --- a/tests/ui/simd/shuffle-not-out-of-bounds.rs +++ b/tests/ui/simd/not-out-of-bounds.rs @@ -1,6 +1,6 @@ //@ build-fail #![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, core_intrinsics)] // Test for #73542 to verify out-of-bounds shuffle vectors do not compile. @@ -28,9 +28,7 @@ struct u8x32([u8; 32]); #[derive(Copy, Clone)] struct u8x64([u8; 64]); -extern "platform-intrinsic" { - pub fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U; -} +use std::intrinsics::simd::*; // Test vectors by lane size. Since LLVM does not distinguish between a shuffle // over two f32s and a shuffle over two u64s, or any other such combination, @@ -70,13 +68,16 @@ fn main() { test_shuffle_lanes!(32, u8x32, simd_shuffle); test_shuffle_lanes!(64, u8x64, simd_shuffle); - extern "platform-intrinsic" { - fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; - } let v = u8x2([0, 0]); const I: [u32; 2] = [4, 4]; unsafe { let _: u8x2 = simd_shuffle(v, v, I); //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic } + + // also check insert/extract + unsafe { + simd_insert(v, 2, 0); //~ ERROR invalid monomorphization of `simd_insert` intrinsic + let _val: u8 = simd_extract(v, 2); //~ ERROR invalid monomorphization of `simd_extract` intrinsic + } } diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.stderr b/tests/ui/simd/not-out-of-bounds.stderr index 59e5ab85866..5682935c1f1 100644 --- a/tests/ui/simd/shuffle-not-out-of-bounds.stderr +++ b/tests/ui/simd/not-out-of-bounds.stderr @@ -1,5 +1,5 @@ -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -9,8 +9,8 @@ LL | test_shuffle_lanes!(2, u8x2, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 8) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 8) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -20,8 +20,8 @@ LL | test_shuffle_lanes!(4, u8x4, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 16) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 16) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -31,8 +31,8 @@ LL | test_shuffle_lanes!(8, u8x8, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 32) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 32) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -42,8 +42,8 @@ LL | test_shuffle_lanes!(16, u8x16, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 64) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 64) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -53,8 +53,8 @@ LL | test_shuffle_lanes!(32, u8x32, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 128) - --> $DIR/shuffle-not-out-of-bounds.rs:51:21 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 128) + --> $DIR/not-out-of-bounds.rs:49:21 | LL | $y(vec1, vec2, ARR) | ^^^^^^^^^^^^^^^^^^^ @@ -64,12 +64,24 @@ LL | test_shuffle_lanes!(64, u8x64, simd_shuffle); | = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) - --> $DIR/shuffle-not-out-of-bounds.rs:79:23 +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) + --> $DIR/not-out-of-bounds.rs:74:23 | LL | let _: u8x2 = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `u8` (element of input `u8x2`), found `i32` + --> $DIR/not-out-of-bounds.rs:80:9 + | +LL | simd_insert(v, 2, 0); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_extract` intrinsic: SIMD index #1 is out of bounds (limit 2) + --> $DIR/not-out-of-bounds.rs:81:24 + | +LL | let _val: u8 = simd_extract(v, 2); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0511`. |
