diff --git a/RELEASES.md b/RELEASES.md index 10a400fda5c3..424e12ceec05 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -62,9 +62,9 @@ Stabilized APIs - [`::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl) - [`::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr) - [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array) -- [`<[T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array) +- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array) - [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array) -- [`<*mut [T]>::as_array_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array) +- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array) - [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if) - [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if) - [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128) diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index a5294bbf7171..fd45f0ea0e9e 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -27,6 +27,7 @@ pub enum CanonAbi { C, Rust, RustCold, + RustPreserveNone, /// An ABI that rustc does not know how to call or define. Custom, @@ -54,7 +55,7 @@ pub enum CanonAbi { impl CanonAbi { pub fn is_rustic_abi(self) -> bool { match self { - CanonAbi::Rust | CanonAbi::RustCold => true, + CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true, CanonAbi::C | CanonAbi::Custom | CanonAbi::Arm(_) @@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone, CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index e44dea1ce593..9173245d8aa4 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -42,6 +42,13 @@ pub enum ExternAbi { /// in a platform-agnostic way. RustInvalid, + /// Preserves no registers. + /// + /// Note, that this ABI is not stable in the registers it uses, is intended as an optimization + /// and may fall-back to a more conservative calling convention if the backend does not support + /// forcing callers to save all registers. + RustPreserveNone, + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, @@ -163,6 +170,7 @@ abi_impls! { RustCall =><= "rust-call", RustCold =><= "rust-cold", RustInvalid =><= "rust-invalid", + RustPreserveNone =><= "rust-preserve-none", Stdcall { unwind: false } =><= "stdcall", Stdcall { unwind: true } =><= "stdcall-unwind", System { unwind: false } =><= "system", @@ -243,7 +251,7 @@ impl ExternAbi { /// - are subject to change between compiler versions pub fn is_rustic_abi(self) -> bool { use ExternAbi::*; - matches!(self, Rust | RustCall | RustCold) + matches!(self, Rust | RustCall | RustCold | RustPreserveNone) } /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports* @@ -315,7 +323,8 @@ impl ExternAbi { | Self::Thiscall { .. } | Self::Vectorcall { .. } | Self::SysV64 { .. } - | Self::Win64 { .. } => true, + | Self::Win64 { .. } + | Self::RustPreserveNone => true, } } } diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index 9acdd672178a..d185cc9163eb 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -95,6 +95,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { ExternAbi::RustCold => { Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) } + ExternAbi::RustPreserveNone => Err(UnstableAbi { + abi, + feature: sym::rust_preserve_none_cc, + explain: GateReason::Experimental, + }), ExternAbi::RustInvalid => { Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index eddcf12fca29..2457e0a777e4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> { CanonAbi::C | CanonAbi::Rust | CanonAbi::RustCold + | CanonAbi::RustPreserveNone | CanonAbi::Arm(_) | CanonAbi::X86(_) => { /* nothing to check */ } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 09d71f5dd557..5a46f79e2ba0 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv( CanonAbi::Rust | CanonAbi::C => default_call_conv, CanonAbi::RustCold => CallConv::Cold, + // Cranelift doesn't currently have anything for this. + CanonAbi::RustPreserveNone => default_call_conv, + // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index cc2c9fca94df..56ed7c01ed20 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -243,6 +243,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, + // gcc/gccjit does not have anything for this. + CanonAbi::RustPreserveNone => return None, CanonAbi::RustCold => FnAttribute::Cold, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index c3c1caf086f0..994077251acc 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -694,6 +694,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm: match abi { CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, CanonAbi::RustCold => llvm::PreserveMost, + CanonAbi::RustPreserveNone => match &sess.target.arch { + Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone, + _ => llvm::CCallConv, + }, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 28e91a25a21a..f5eb9c10db99 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -370,7 +370,7 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute { llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc") } -/// Helper for `FnAbi::apply_attrs_llfn`: +/// Helper for `FnAbiLlvmExt::apply_attrs_llfn`: /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( @@ -516,7 +516,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) { + // "Does not capture provenance" means "if the function call stashes the pointer somewhere, + // accessing that pointer after the function returns is UB". That is definitely the case here since + // freeing will destroy the provenance. + let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); + &[allocated_pointer, captures_addr] + } else { + &[allocated_pointer] + }; + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs); } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 454d5c4ffb24..4956549f2ed3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -167,6 +167,7 @@ pub(crate) enum CallConv { PreserveMost = 14, PreserveAll = 15, Tail = 18, + PreserveNone = 21, X86StdcallCallConv = 64, X86FastcallCallConv = 65, ArmAapcsCallConv = 67, diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 7688df2d3a55..a51aa90355bc 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -431,8 +431,6 @@ impl ToInternal for Level { } } -pub(crate) struct FreeFunctions; - pub(crate) struct Rustc<'a, 'b> { ecx: &'a mut ExtCtxt<'b>, def_site: Span, @@ -461,13 +459,28 @@ impl<'a, 'b> Rustc<'a, 'b> { } impl server::Types for Rustc<'_, '_> { - type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type Span = Span; type Symbol = Symbol; } -impl server::FreeFunctions for Rustc<'_, '_> { +impl server::Server for Rustc<'_, '_> { + fn globals(&mut self) -> ExpnGlobals { + ExpnGlobals { + def_site: self.def_site, + call_site: self.call_site, + mixed_site: self.mixed_site, + } + } + + fn intern_symbol(string: &str) -> Self::Symbol { + Symbol::intern(string) + } + + fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { + f(symbol.as_str()) + } + fn injected_env_var(&mut self, var: &str) -> Option { self.ecx.sess.opts.logical_env.get(var).cloned() } @@ -552,14 +565,20 @@ impl server::FreeFunctions for Rustc<'_, '_> { } diag.emit(); } -} -impl server::TokenStream for Rustc<'_, '_> { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { + fn ts_drop(&mut self, stream: Self::TokenStream) { + drop(stream); + } + + fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream { + stream.clone() + } + + fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool { stream.is_empty() } - fn from_str(&mut self, src: &str) -> Self::TokenStream { + fn ts_from_str(&mut self, src: &str) -> Self::TokenStream { unwrap_or_emit_fatal(source_str_to_stream( self.psess(), FileName::proc_macro_source_code(src), @@ -568,11 +587,11 @@ impl server::TokenStream for Rustc<'_, '_> { )) } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { + fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String { pprust::tts_to_string(stream) } - fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result { + fn ts_expand_expr(&mut self, stream: &Self::TokenStream) -> Result { // Parse the expression from our tokenstream. let expr: PResult<'_, _> = try { let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr")); @@ -633,14 +652,14 @@ impl server::TokenStream for Rustc<'_, '_> { } } - fn from_token_tree( + fn ts_from_token_tree( &mut self, tree: TokenTree, ) -> Self::TokenStream { Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::>()) } - fn concat_trees( + fn ts_concat_trees( &mut self, base: Option, trees: Vec>, @@ -654,7 +673,7 @@ impl server::TokenStream for Rustc<'_, '_> { stream } - fn concat_streams( + fn ts_concat_streams( &mut self, base: Option, streams: Vec, @@ -666,16 +685,14 @@ impl server::TokenStream for Rustc<'_, '_> { stream } - fn into_trees( + fn ts_into_trees( &mut self, stream: Self::TokenStream, ) -> Vec> { FromInternal::from_internal((stream, self)) } -} -impl server::Span for Rustc<'_, '_> { - fn debug(&mut self, span: Self::Span) -> String { + fn span_debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { format!("{span:?}") } else { @@ -683,7 +700,7 @@ impl server::Span for Rustc<'_, '_> { } } - fn file(&mut self, span: Self::Span) -> String { + fn span_file(&mut self, span: Self::Span) -> String { self.psess() .source_map() .lookup_char_pos(span.lo()) @@ -693,7 +710,7 @@ impl server::Span for Rustc<'_, '_> { .to_string() } - fn local_file(&mut self, span: Self::Span) -> Option { + fn span_local_file(&mut self, span: Self::Span) -> Option { self.psess() .source_map() .lookup_char_pos(span.lo()) @@ -708,15 +725,15 @@ impl server::Span for Rustc<'_, '_> { }) } - fn parent(&mut self, span: Self::Span) -> Option { + fn span_parent(&mut self, span: Self::Span) -> Option { span.parent_callsite() } - fn source(&mut self, span: Self::Span) -> Self::Span { + fn span_source(&mut self, span: Self::Span) -> Self::Span { span.source_callsite() } - fn byte_range(&mut self, span: Self::Span) -> Range { + fn span_byte_range(&mut self, span: Self::Span) -> Range { let source_map = self.psess().source_map(); let relative_start_pos = source_map.lookup_byte_offset(span.lo()).pos; @@ -724,25 +741,25 @@ impl server::Span for Rustc<'_, '_> { Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize } } - fn start(&mut self, span: Self::Span) -> Self::Span { + fn span_start(&mut self, span: Self::Span) -> Self::Span { span.shrink_to_lo() } - fn end(&mut self, span: Self::Span) -> Self::Span { + fn span_end(&mut self, span: Self::Span) -> Self::Span { span.shrink_to_hi() } - fn line(&mut self, span: Self::Span) -> usize { + fn span_line(&mut self, span: Self::Span) -> usize { let loc = self.psess().source_map().lookup_char_pos(span.lo()); loc.line } - fn column(&mut self, span: Self::Span) -> usize { + fn span_column(&mut self, span: Self::Span) -> usize { let loc = self.psess().source_map().lookup_char_pos(span.lo()); loc.col.to_usize() + 1 } - fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { + fn span_join(&mut self, first: Self::Span, second: Self::Span) -> Option { let self_loc = self.psess().source_map().lookup_char_pos(first.lo()); let other_loc = self.psess().source_map().lookup_char_pos(second.lo()); @@ -753,7 +770,7 @@ impl server::Span for Rustc<'_, '_> { Some(first.to(second)) } - fn subspan( + fn span_subspan( &mut self, span: Self::Span, start: Bound, @@ -789,11 +806,11 @@ impl server::Span for Rustc<'_, '_> { Some(span.with_lo(new_lo).with_hi(new_hi)) } - fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { + fn span_resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { span.with_ctxt(at.ctxt()) } - fn source_text(&mut self, span: Self::Span) -> Option { + fn span_source_text(&mut self, span: Self::Span) -> Option { self.psess().source_map().span_to_snippet(span).ok() } @@ -821,11 +838,11 @@ impl server::Span for Rustc<'_, '_> { /// span from the metadata of `my_proc_macro` (which we have access to, /// since we've loaded `my_proc_macro` from disk in order to execute it). /// In this way, we have obtained a span pointing into `my_proc_macro` - fn save_span(&mut self, span: Self::Span) -> usize { + fn span_save_span(&mut self, span: Self::Span) -> usize { self.psess().save_proc_macro_span(span) } - fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span { + fn span_recover_proc_macro_span(&mut self, id: usize) -> Self::Span { let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site); *self.rebased_spans.entry(id).or_insert_with(|| { // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding, @@ -833,29 +850,9 @@ impl server::Span for Rustc<'_, '_> { resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt()) }) } -} -impl server::Symbol for Rustc<'_, '_> { - fn normalize_and_validate_ident(&mut self, string: &str) -> Result { + fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result { let sym = nfc_normalize(string); if rustc_lexer::is_ident(sym.as_str()) { Ok(sym) } else { Err(()) } } } - -impl server::Server for Rustc<'_, '_> { - fn globals(&mut self) -> ExpnGlobals { - ExpnGlobals { - def_site: self.def_site, - call_site: self.call_site, - mixed_site: self.mixed_site, - } - } - - fn intern_symbol(string: &str) -> Self::Symbol { - Symbol::intern(string) - } - - fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - f(symbol.as_str()) - } -} diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 22db43b7ee64..c99af9658cde 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -634,6 +634,8 @@ declare_features! ( (unstable, rtm_target_feature, "1.35.0", Some(150258)), /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), + /// Allows `extern "rust-preserve-none"`. + (unstable, rust_preserve_none_cc, "CURRENT_RUSTC_VERSION", Some(151401)), /// Target features on s390x. (unstable, s390x_target_feature, "1.82.0", Some(150259)), /// Allows the use of the `sanitize` attribute. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 4594b9217f83..a26b44e79dc7 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { CanonAbi::C | CanonAbi::Rust | CanonAbi::RustCold + | CanonAbi::RustPreserveNone | CanonAbi::Arm(_) | CanonAbi::X86(_) => {} } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 52ea6cdeaa0e..0e87b90dc6c1 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1365,6 +1365,7 @@ pub fn can_coerce<'tcx>( /// - WARNING: I don't believe this final type is guaranteed to be /// related to your initial `expected_ty` in any particular way, /// although it will typically be a subtype, so you should check it. +/// Check the note below for more details. /// - Invoking `complete()` may cause us to go and adjust the "adjustments" on /// previously coerced expressions. /// @@ -1378,6 +1379,28 @@ pub fn can_coerce<'tcx>( /// } /// let final_ty = coerce.complete(fcx); /// ``` +/// +/// NOTE: Why does the `expected_ty` participate in the LUB? +/// When coercing, each branch should use the following expectations for type inference: +/// - The branch can be coerced to the expected type of the match/if/whatever. +/// - The branch can be coercion lub'd with the types of the previous branches. +/// Ideally we'd have some sort of `Expectation::ParticipatesInCoerceLub(ongoing_lub_ty, final_ty)`, +/// but adding and using this feels very challenging. +/// What we instead do is to use the expected type of the match/if/whatever as +/// the initial coercion lub. This allows us to use the lub of "expected type of match" with +/// "types from previous branches" as the coercion target, which can contains both expectations. +/// +/// Two concerns with this approach: +/// - We may have incompatible `final_ty` if that lub is different from the expected +/// type of the match. However, in this case coercing the final type of the +/// `CoerceMany` to its expected type would have error'd anyways, so we don't care. +/// - We may constrain the `expected_ty` too early. For some branches with +/// type `a` and `b`, we end up with `(a lub expected_ty) lub b` instead of +/// `(a lub b) lub expected_ty`. They should be the same type. However, +/// `a lub expected_ty` may constrain inference variables in `expected_ty`. +/// In this case the difference does matter and we get actually incorrect results. +/// FIXME: Ideally we'd compute the final type without unnecessarily constraining +/// the expected type of the match when computing the types of its branches. pub(crate) struct CoerceMany<'tcx> { expected_ty: Ty<'tcx>, final_ty: Option>, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 885af3b909b8..5b40531f9462 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1670,11 +1670,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce_to = expected .to_option(self) - .and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index()) + .and_then(|uty| { + self.try_structurally_resolve_type(expr.span, uty) + .builtin_index() + // Avoid using the original type variable as the coerce_to type, as it may resolve + // during the first coercion instead of being the LUB type. + .filter(|t| !self.try_structurally_resolve_type(expr.span, *t).is_ty_var()) + }) .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_capacity(coerce_to, args.len()); for e in args { + // FIXME: the element expectation should use + // `try_structurally_resolve_and_adjust_for_branches` just like in `if` and `match`. + // While that fixes nested coercion, it will break [some + // code like this](https://github.com/rust-lang/rust/pull/140283#issuecomment-2958776528). + // If we find a way to support recursive tuple coercion, this break can be avoided. let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); coerce.coerce(self, &cause, e, e_ty); diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 7c6b7157f71a..3d8d5d59b118 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -72,7 +72,7 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { - write!(f, "{}", tcx.dep_kind_info(kind).name) + write!(f, "{}", tcx.dep_kind_vtable(kind).name) } else { default_dep_kind_debug(kind, f) } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3228a0499acc..60b45f7391b5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -992,7 +992,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( hir_arena, untracked, dep_graph, - rustc_query_impl::query_callbacks(arena), + rustc_query_impl::make_dep_kind_vtables(arena), rustc_query_impl::query_system( providers.queries, providers.extern_queries, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 0bdc1bfd45ee..0f254aaa9fa0 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -104,7 +104,7 @@ macro_rules! arena_types { [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, - [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, + [] dep_kind_vtable: rustc_middle::dep_graph::DepKindVTable<'tcx>, [decode] trait_impl_trait_tys: rustc_data_structures::unord::UnordMap< diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 049e868879e9..f28ba10d52e2 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -18,7 +18,7 @@ pub use rustc_query_system::dep_graph::{ pub type DepGraph = rustc_query_system::dep_graph::DepGraph; -pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct>; +pub type DepKindVTable<'tcx> = rustc_query_system::dep_graph::DepKindVTable>; pub struct DepsType; @@ -79,8 +79,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } #[inline] - fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dk.as_usize()] + fn dep_kind_vtable(&self, dk: DepKind) -> &DepKindVTable<'tcx> { + &self.dep_kind_vtables[dk.as_usize()] } fn with_reduced_queries(self, f: impl FnOnce() -> T) -> T { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5ba5a3c3d4dc..f015d0edc56c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -59,7 +59,7 @@ use rustc_type_ir::{ use tracing::{debug, instrument}; use crate::arena::Arena; -use crate::dep_graph::{DepGraph, DepKindStruct}; +use crate::dep_graph::{DepGraph, DepKindVTable}; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds}; use crate::lint::lint_level; use crate::metadata::ModChild; @@ -1580,7 +1580,7 @@ pub struct GlobalCtxt<'tcx> { untracked: Untracked, pub query_system: QuerySystem<'tcx>, - pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>], + pub(crate) dep_kind_vtables: &'tcx [DepKindVTable<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock>>, @@ -1801,7 +1801,7 @@ impl<'tcx> TyCtxt<'tcx> { hir_arena: &'tcx WorkerLocal>, untracked: Untracked, dep_graph: DepGraph, - query_kinds: &'tcx [DepKindStruct<'tcx>], + dep_kind_vtables: &'tcx [DepKindVTable<'tcx>], query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, current_gcx: CurrentGcx, @@ -1831,7 +1831,7 @@ impl<'tcx> TyCtxt<'tcx> { consts: common_consts, untracked, query_system, - query_kinds, + dep_kind_vtables, ty_rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 81b8142d03f3..14ebcc968f7a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1288,7 +1288,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | RiscvInterruptS | RustInvalid | Unadjusted => false, - Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(), + Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(), } } diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index a5a2fcd71a9a..98dc054918eb 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -986,7 +986,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { // warn twice, for the unused local and for the unused assignment. Therefore, we remove // from the list of assignments the ones that happen at the definition site. statements.retain(|source_info, _| { - source_info.span.find_ancestor_inside(binding.pat_span).is_none() + !binding.introductions.iter().any(|intro| intro.span == source_info.span) }); // Extra assignments that we recognize thanks to the initialization span. We need to diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index aced39059f6b..bc18068cfa05 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -432,6 +432,7 @@ pub enum CallConvention { Cold, PreserveMost, PreserveAll, + PreserveNone, Custom, diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index f0a18ef08fc6..d4f128f87d6f 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1139,6 +1139,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + RustPreserveNone, RustInvalid, Custom, } diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index d9f314a8e29c..73a3fed111b3 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -615,6 +615,7 @@ impl RustcInternal for Abi { Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, + Abi::RustPreserveNone => rustc_abi::ExternAbi::RustPreserveNone, Abi::Custom => rustc_abi::ExternAbi::Custom, } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 03328d084ee9..e4130d7fa4cb 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -123,6 +123,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::C => CallConvention::C, CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::RustPreserveNone => CallConvention::PreserveNone, CanonAbi::Custom => CallConvention::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => CallConvention::ArmAapcs, diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 34662c9ca023..cee144122c0e 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -1020,6 +1020,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::RustCall => Abi::RustCall, ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, + ExternAbi::RustPreserveNone => Abi::RustPreserveNone, ExternAbi::RustInvalid => Abi::RustInvalid, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index c9abc4bdcdfc..57027e937a4a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::HashStable; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; -use rustc_middle::dep_graph::{self, DepKind, DepKindStruct, DepNodeIndex}; +use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNodeIndex}; use rustc_middle::query::erase::{Erase, erase, restore}; use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns}; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 7479a992e297..246152f5390c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -12,7 +12,7 @@ use rustc_hir::limit::Limit; use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::dep_graph::{ - self, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, + self, DepContext, DepKind, DepKindVTable, DepNode, DepNodeIndex, SerializedDepNodeIndex, dep_kinds, }; use rustc_middle::query::Key; @@ -489,14 +489,17 @@ where } } -pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx> +pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>( + is_anon: bool, + is_eval_always: bool, +) -> DepKindVTable<'tcx> where Q: QueryConfigRestored<'tcx>, { let fingerprint_style = >>::Key::fingerprint_style(); if is_anon || !fingerprint_style.reconstructible() { - return DepKindStruct { + return DepKindVTable { is_anon, is_eval_always, fingerprint_style, @@ -506,7 +509,7 @@ where }; } - DepKindStruct { + DepKindVTable { is_anon, is_eval_always, fingerprint_style, @@ -811,15 +814,19 @@ macro_rules! define_queries { for<'tcx> fn(TyCtxt<'tcx>) ] = &[$(query_impl::$name::query_key_hash_verify),*]; - #[allow(nonstandard_style)] - mod query_callbacks { + /// Module containing a named function for each dep kind (including queries) + /// that creates a `DepKindVTable`. + /// + /// Consumed via `make_dep_kind_array!` to create a list of vtables. + #[expect(non_snake_case)] + mod _dep_kind_vtable_ctors { use super::*; use rustc_middle::bug; use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. - pub(crate) fn Null<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn Null<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, @@ -830,8 +837,8 @@ macro_rules! define_queries { } // We use this for the forever-red node. - pub(crate) fn Red<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn Red<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, @@ -841,8 +848,8 @@ macro_rules! define_queries { } } - pub(crate) fn SideEffect<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn SideEffect<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, @@ -855,8 +862,8 @@ macro_rules! define_queries { } } - pub(crate) fn AnonZeroDeps<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn AnonZeroDeps<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: true, is_eval_always: false, fingerprint_style: FingerprintStyle::Opaque, @@ -866,8 +873,8 @@ macro_rules! define_queries { } } - pub(crate) fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn TraitSelect<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: true, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, @@ -877,8 +884,8 @@ macro_rules! define_queries { } } - pub(crate) fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn CompileCodegenUnit<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Opaque, @@ -888,8 +895,8 @@ macro_rules! define_queries { } } - pub(crate) fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn CompileMonoItem<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Opaque, @@ -899,8 +906,8 @@ macro_rules! define_queries { } } - pub(crate) fn Metadata<'tcx>() -> DepKindStruct<'tcx> { - DepKindStruct { + pub(crate) fn Metadata<'tcx>() -> DepKindVTable<'tcx> { + DepKindVTable { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, @@ -910,16 +917,17 @@ macro_rules! define_queries { } } - $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> { - $crate::plumbing::query_callback::>( + $(pub(crate) fn $name<'tcx>() -> DepKindVTable<'tcx> { + use $crate::query_impl::$name::QueryType; + $crate::plumbing::make_dep_kind_vtable_for_query::>( is_anon!([$($modifiers)*]), is_eval_always!([$($modifiers)*]), ) })* } - pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { - arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(query_callbacks)) + pub fn make_dep_kind_vtables<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindVTable<'tcx>] { + arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(_dep_kind_vtable_ctors)) } } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index bdd1d5f3e88a..72bdcd2d534d 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -221,12 +221,12 @@ where } } -/// This struct stores metadata about each DepKind. +/// This struct stores function pointers and other metadata for a particular DepKind. /// /// Information is retrieved by indexing the `DEP_KINDS` array using the integer value /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual /// jump table instead of large matches. -pub struct DepKindStruct { +pub struct DepKindVTable { /// Anonymous queries cannot be replayed from one compiler invocation to the next. /// When their result is needed, it is recomputed. They are useful for fine-grained /// dependency tracking, and caching within one compiler invocation. diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 8b9e4fe1bf29..874b41cbf3b1 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -7,7 +7,7 @@ mod serialized; use std::panic; -pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId}; +pub use dep_node::{DepKind, DepKindVTable, DepNode, DepNodeParams, WorkProductId}; pub(crate) use graph::DepGraphData; pub use graph::{DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result}; pub use query::DepGraphQuery; @@ -35,21 +35,21 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; - fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct; + fn dep_kind_vtable(&self, dep_node: DepKind) -> &DepKindVTable; #[inline(always)] fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle { - let data = self.dep_kind_info(kind); - if data.is_anon { + let vtable = self.dep_kind_vtable(kind); + if vtable.is_anon { return FingerprintStyle::Opaque; } - data.fingerprint_style + vtable.fingerprint_style } #[inline(always)] /// Return whether this kind always require evaluation. fn is_eval_always(self, kind: DepKind) -> bool { - self.dep_kind_info(kind).is_eval_always + self.dep_kind_vtable(kind).is_eval_always } /// Try to force a dep node to execute and see if it's green. @@ -65,9 +65,10 @@ pub trait DepContext: Copy { prev_index: SerializedDepNodeIndex, frame: &MarkFrame<'_>, ) -> bool { - let cb = self.dep_kind_info(dep_node.kind); - if let Some(f) = cb.force_from_dep_node { - match panic::catch_unwind(panic::AssertUnwindSafe(|| f(self, dep_node, prev_index))) { + if let Some(force_fn) = self.dep_kind_vtable(dep_node.kind).force_from_dep_node { + match panic::catch_unwind(panic::AssertUnwindSafe(|| { + force_fn(self, dep_node, prev_index) + })) { Err(value) => { if !value.is::() { print_markframe_trace(self.dep_graph(), frame); @@ -83,9 +84,8 @@ pub trait DepContext: Copy { /// Load data from the on-disk cache. fn try_load_from_on_disk_cache(self, dep_node: DepNode) { - let cb = self.dep_kind_info(dep_node.kind); - if let Some(f) = cb.try_load_from_on_disk_cache { - f(self, dep_node) + if let Some(try_load_fn) = self.dep_kind_vtable(dep_node.kind).try_load_from_on_disk_cache { + try_load_fn(self, dep_node) } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 79d08d33c0b1..0431151c74c9 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -626,7 +626,7 @@ pub fn print_query_stack( file, "#{} [{}] {}", count_total, - qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, + qcx.dep_context().dep_kind_vtable(query_info.query.dep_kind).name, query_info.query.description ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 96e883a2d9ce..8fd228211f3c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1918,6 +1918,7 @@ symbols! { rust_future, rust_logo, rust_out, + rust_preserve_none_cc, rustc, rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index d7fc18cd3761..c0fdd946778b 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -88,6 +88,7 @@ impl AbiMap { (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, + (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone, (ExternAbi::Custom, _) => CanonAbi::Custom, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index fde7dfcabb70..bc12e1eb9737 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -466,9 +466,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sha512", Stable, &["avx2"]), ("sm3", Stable, &["avx"]), ("sm4", Stable, &["avx2"]), - // This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to - // stabilize. It must be in this list for the ABI check to be able to use it. - ("soft-float", Stability::Unstable(sym::x87_target_feature), &[]), + ("soft-float", Stability::Forbidden { reason: "use a soft-float target instead" }, &[]), ("sse", Stable, &[]), ("sse2", Stable, &["sse"]), ("sse3", Stable, &["sse2"]), diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f58ebd488d7c..cec41524325e 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -252,7 +252,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::mem::{self, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] @@ -3845,15 +3845,15 @@ unsafe fn data_offset(ptr: *const T) -> usize { // Because RcInner is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to - // satisfy the requirements of align_of_val_raw; this is an implementation + // satisfy the requirements of Alignment::of_val_raw; this is an implementation // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) } + unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) } } #[inline] -fn data_offset_align(align: Alignment) -> usize { +fn data_offset_alignment(alignment: Alignment) -> usize { let layout = Layout::new::>(); - layout.size() + layout.padding_needed_for(align) + layout.size() + layout.padding_needed_for(alignment) } /// A uniquely owned [`Rc`]. @@ -4478,7 +4478,7 @@ impl UniqueRcUninit { /// Returns the pointer to be written into to initialize the [`Rc`]. fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.alignment()); + let offset = data_offset_alignment(self.layout_for_value.alignment()); unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index bf5cbafbac63..cc8d80aee456 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -444,13 +444,16 @@ impl [T] { impl ConvertVec for T { #[inline] fn to_vec(s: &[Self], alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(s.len(), alloc); + let len = s.len(); + let mut v = Vec::with_capacity_in(len, alloc); // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); + if len > 0 { + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), len); + v.set_len(len); + } } v } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index fc44a468c8a4..a5e4fab916ab 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -19,7 +19,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::mem::{self, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[cfg(not(no_global_oom_handling))] @@ -4206,15 +4206,15 @@ unsafe fn data_offset(ptr: *const T) -> usize { // Because ArcInner is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to - // satisfy the requirements of align_of_val_raw; this is an implementation + // satisfy the requirements of Alignment::of_val_raw; this is an implementation // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) } + unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) } } #[inline] -fn data_offset_align(align: Alignment) -> usize { +fn data_offset_alignment(alignment: Alignment) -> usize { let layout = Layout::new::>(); - layout.size() + layout.padding_needed_for(align) + layout.size() + layout.padding_needed_for(alignment) } /// A unique owning pointer to an [`ArcInner`] **that does not imply the contents are initialized,** @@ -4258,7 +4258,7 @@ impl UniqueArcUninit { /// Returns the pointer to be written into to initialize the [`Arc`]. fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.alignment()); + let offset = data_offset_alignment(self.layout_for_value.alignment()); unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 93432f3e049e..aaf22e80ec60 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2818,7 +2818,11 @@ impl Vec { let count = other.len(); self.reserve(count); let len = self.len(); - unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; + if count > 0 { + unsafe { + ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) + }; + } self.len += count; } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 3a2111350a4e..4bffdd17696f 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -67,15 +67,16 @@ impl Layout { #[inline] const fn is_size_align_valid(size: usize, align: usize) -> bool { - let Some(align) = Alignment::new(align) else { return false }; - if size > Self::max_size_for_align(align) { - return false; - } - true + let Some(alignment) = Alignment::new(align) else { return false }; + Self::is_size_alignment_valid(size, alignment) + } + + const fn is_size_alignment_valid(size: usize, alignment: Alignment) -> bool { + size <= Self::max_size_for_alignment(alignment) } #[inline(always)] - const fn max_size_for_align(align: Alignment) -> usize { + const fn max_size_for_alignment(alignment: Alignment) -> usize { // (power-of-two implies align != 0.) // Rounded up size is: @@ -93,18 +94,28 @@ impl Layout { // SAFETY: the maximum possible alignment is `isize::MAX + 1`, // so the subtraction cannot overflow. - unsafe { unchecked_sub(isize::MAX as usize + 1, align.as_usize()) } + unsafe { unchecked_sub(isize::MAX as usize + 1, alignment.as_usize()) } } - /// Internal helper constructor to skip revalidating alignment validity. + /// Constructs a `Layout` from a given `size` and `alignment`, + /// or returns `LayoutError` if any of the following conditions + /// are not met: + /// + /// * `size`, when rounded up to the nearest multiple of `alignment`, + /// must not overflow `isize` (i.e., the rounded value must be + /// less than or equal to `isize::MAX`). + #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - const fn from_size_alignment(size: usize, align: Alignment) -> Result { - if size > Self::max_size_for_align(align) { - return Err(LayoutError); + pub const fn from_size_alignment( + size: usize, + alignment: Alignment, + ) -> Result { + if Layout::is_size_alignment_valid(size, alignment) { + // SAFETY: Layout::size invariants checked above. + Ok(Layout { size, align: alignment }) + } else { + Err(LayoutError) } - - // SAFETY: Layout::size invariants checked above. - Ok(Layout { size, align }) } /// Creates a layout, bypassing all checks. @@ -132,6 +143,30 @@ impl Layout { unsafe { Layout { size, align: mem::transmute(align) } } } + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify the preconditions from + /// [`Layout::from_size_alignment`]. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[must_use] + #[inline] + #[track_caller] + pub const unsafe fn from_size_alignment_unchecked(size: usize, alignment: Alignment) -> Self { + assert_unsafe_precondition!( + check_library_ub, + "Layout::from_size_alignment_unchecked requires \ + that the rounded-up allocation size does not exceed isize::MAX", + ( + size: usize = size, + alignment: Alignment = alignment, + ) => Layout::is_size_alignment_valid(size, alignment) + ); + // SAFETY: the caller is required to uphold the preconditions. + Layout { size, align: alignment } + } + /// The minimum size in bytes for a memory block of this layout. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] @@ -153,6 +188,16 @@ impl Layout { self.align.as_usize() } + /// The minimum byte alignment for a memory block of this layout. + /// + /// The returned alignment is guaranteed to be a power of two. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[must_use = "this returns the minimum alignment, without modifying the layout"] + #[inline] + pub const fn alignment(&self) -> Alignment { + self.align + } + /// Constructs a `Layout` suitable for holding a value of type `T`. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")] @@ -170,9 +215,9 @@ impl Layout { #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { - let (size, align) = (size_of_val(t), align_of_val(t)); + let (size, alignment) = (size_of_val(t), Alignment::of_val(t)); // SAFETY: see rationale in `new` for why this is using the unsafe variant - unsafe { Layout::from_size_align_unchecked(size, align) } + unsafe { Layout::from_size_alignment_unchecked(size, alignment) } } /// Produces layout describing a record that could be used to @@ -204,11 +249,12 @@ impl Layout { /// [extern type]: ../../unstable-book/language-features/extern-types.html #[unstable(feature = "layout_for_ptr", issue = "69835")] #[must_use] + #[inline] pub const unsafe fn for_value_raw(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller - let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; + let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) }; // SAFETY: see rationale in `new` for why this is using the unsafe variant - unsafe { Layout::from_size_align_unchecked(size, align) } + unsafe { Layout::from_size_alignment_unchecked(size, alignment) } } /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. @@ -243,13 +289,33 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn align_to(&self, align: usize) -> Result { - if let Some(align) = Alignment::new(align) { - Layout::from_size_alignment(self.size, Alignment::max(self.align, align)) + if let Some(alignment) = Alignment::new(align) { + self.adjust_alignment_to(alignment) } else { Err(LayoutError) } } + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `alignment`. + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// Returns an error if the combination of `self.size()` and the given + /// `alignment` violates the conditions listed in [`Layout::from_size_alignment`]. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[inline] + pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result { + Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment)) + } + /// Returns the amount of padding we must insert after `self` /// to ensure that the following address will satisfy `alignment`. /// @@ -267,7 +333,7 @@ impl Layout { #[must_use = "this returns the padding needed, without modifying the `Layout`"] #[inline] pub const fn padding_needed_for(&self, alignment: Alignment) -> usize { - let len_rounded_up = self.size_rounded_up_to_custom_align(alignment); + let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment); // SAFETY: Cannot overflow because the rounded-up value is never less unsafe { unchecked_sub(len_rounded_up, self.size) } } @@ -277,7 +343,7 @@ impl Layout { /// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`) /// because the original size is at most `isize::MAX`. #[inline] - const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize { + const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize { // SAFETY: // Rounded up value is: // size_rounded_up = (size + align - 1) & !(align - 1); @@ -297,7 +363,7 @@ impl Layout { // (Size 0 Align MAX is already aligned, so stays the same, but things like // Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.) unsafe { - let align_m1 = unchecked_sub(align.as_usize(), 1); + let align_m1 = unchecked_sub(alignment.as_usize(), 1); unchecked_add(self.size, align_m1) & !align_m1 } } @@ -317,10 +383,10 @@ impl Layout { // > `size`, when rounded up to the nearest multiple of `align`, // > must not overflow isize (i.e., the rounded value must be // > less than or equal to `isize::MAX`) - let new_size = self.size_rounded_up_to_custom_align(self.align); + let new_size = self.size_rounded_up_to_custom_alignment(self.align); // SAFETY: padded size is guaranteed to not exceed `isize::MAX`. - unsafe { Layout::from_size_align_unchecked(new_size, self.align()) } + unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) } } /// Creates a layout describing the record for `n` instances of @@ -426,8 +492,8 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { - let new_align = Alignment::max(self.align, next.align); - let offset = self.size_rounded_up_to_custom_align(next.align); + let new_alignment = Alignment::max(self.align, next.align); + let offset = self.size_rounded_up_to_custom_alignment(next.align); // SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning // to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the @@ -435,7 +501,7 @@ impl Layout { // `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow. let new_size = unsafe { unchecked_add(offset, next.size) }; - if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) { + if let Ok(layout) = Layout::from_size_alignment(new_size, new_alignment) { Ok((layout, offset)) } else { Err(LayoutError) @@ -496,7 +562,7 @@ impl Layout { #[inline] const fn inner(element_layout: Layout, n: usize) -> Result { - let Layout { size: element_size, align } = element_layout; + let Layout { size: element_size, align: alignment } = element_layout; // We need to check two things about the size: // - That the total size won't overflow a `usize`, and @@ -504,7 +570,7 @@ impl Layout { // By using division we can check them both with a single threshold. // That'd usually be a bad idea, but thankfully here the element size // and alignment are constants, so the compiler will fold all of it. - if element_size != 0 && n > Layout::max_size_for_align(align) / element_size { + if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size { return Err(LayoutError); } @@ -517,17 +583,9 @@ impl Layout { // SAFETY: We just checked above that the `array_size` will not // exceed `isize::MAX` even when rounded up to the alignment. // And `Alignment` guarantees it's a power of two. - unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) } + unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) } } } - - /// Perma-unstable access to `align` as `Alignment` type. - #[unstable(issue = "none", feature = "std_internals")] - #[doc(hidden)] - #[inline] - pub const fn alignment(&self) -> Alignment { - self.align - } } #[stable(feature = "alloc_layout", since = "1.28.0")] diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 1c1f4d78c03f..cd2a9e00b5a6 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -66,7 +66,7 @@ impl IntoIterator for [T; N] { // FIXME: If normal `transmute` ever gets smart enough to allow this // directly, use it instead of `transmute_unchecked`. let data: [MaybeUninit; N] = unsafe { transmute_unchecked(self) }; - // SAFETY: The original array was entirely initialized and the the alive + // SAFETY: The original array was entirely initialized and the alive // range we're passing here represents that fact. let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) }; IntoIter { inner: ManuallyDrop::new(inner) } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 1671c8219de1..7c486875a826 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -9,6 +9,7 @@ use crate::alloc::Layout; use crate::clone::TrivialClone; use crate::marker::{Destruct, DiscriminantKind}; use crate::panic::const_assert; +use crate::ptr::Alignment; use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; mod manually_drop; @@ -1257,6 +1258,10 @@ pub trait SizedTypeProperties: Sized { #[lang = "mem_align_const"] const ALIGN: usize = intrinsics::align_of::(); + #[doc(hidden)] + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + const ALIGNMENT: Alignment = Alignment::of::(); + /// `true` if this type requires no storage. /// `false` if its [size](size_of) is greater than zero. /// diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bc7d3a1de715..42c95e6c9cd2 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,5 +1,6 @@ #![allow(clippy::enum_clike_unportable_variant)] +use crate::marker::MetaSized; use crate::num::NonZero; use crate::ub_checks::assert_unsafe_precondition; use crate::{cmp, fmt, hash, mem, num}; @@ -50,6 +51,79 @@ impl Alignment { const { Alignment::new(align_of::()).unwrap() } } + /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. + /// + /// Every reference to a value of the type `T` must be a multiple of this number. + /// + /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_alignment_type)] + /// use std::ptr::Alignment; + /// + /// assert_eq!(Alignment::of_val(&5i32).as_usize(), 4); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + pub const fn of_val(val: &T) -> Self { + let align = mem::align_of_val(val); + // SAFETY: `align_of_val` returns valid alignment + unsafe { Alignment::new_unchecked(align) } + } + + /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. + /// + /// Every reference to a value of the type `T` must be a multiple of this number. + /// + /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface + /// + /// # Safety + /// + /// This function is only safe to call if the following conditions hold: + /// + /// - If `T` is `Sized`, this function is always safe to call. + /// - If the unsized tail of `T` is: + /// - a [slice], then the length of the slice tail must be an initialized + /// integer, and the size of the *entire value* + /// (dynamic tail length + statically sized prefix) must fit in `isize`. + /// For the special case where the dynamic tail length is 0, this function + /// is safe to call. + /// - a [trait object], then the vtable part of the pointer must point + /// to a valid vtable acquired by an unsizing coercion, and the size + /// of the *entire value* (dynamic tail length + statically sized prefix) + /// must fit in `isize`. + /// - an (unstable) [extern type], then this function is always safe to + /// call, but may panic or otherwise return the wrong value, as the + /// extern type's layout is not known. This is the same behavior as + /// [`Alignment::of_val`] on a reference to a type with an extern type tail. + /// - otherwise, it is conservatively not allowed to call this function. + /// + /// [trait object]: ../../book/ch17-02-trait-objects.html + /// [extern type]: ../../unstable-book/language-features/extern-types.html + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_alignment_type)] + /// #![feature(layout_for_ptr)] + /// use std::ptr::Alignment; + /// + /// assert_eq!(unsafe { Alignment::of_val_raw(&5i32) }.as_usize(), 4); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + // #[unstable(feature = "layout_for_ptr", issue = "69835")] + pub const unsafe fn of_val_raw(val: *const T) -> Self { + // SAFETY: precondition propagated to the caller + let align = unsafe { mem::align_of_val_raw(val) }; + // SAFETY: `align_of_val_raw` returns valid alignment + unsafe { Alignment::new_unchecked(align) } + } + /// Creates an `Alignment` from a `usize`, or returns `None` if it's /// not a power of two. /// diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index bdaa865a998d..0d87a727ae40 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -6,93 +6,66 @@ use std::sync::atomic::AtomicU32; use super::*; -macro_rules! define_client_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleCounters { - $(pub(super) $oty: AtomicU32,)* - $(pub(super) $ity: AtomicU32,)* - } +#[repr(C)] +pub(super) struct HandleCounters { + pub(super) token_stream: AtomicU32, + pub(super) span: AtomicU32, +} - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicU32::new(1),)* - $($ity: AtomicU32::new(1),)* - }; +static COUNTERS: HandleCounters = + HandleCounters { token_stream: AtomicU32::new(1), span: AtomicU32::new(1) }; - $( - pub(crate) struct $oty { - handle: handle::Handle, - } +pub(crate) struct TokenStream { + handle: handle::Handle, +} - impl !Send for $oty {} - impl !Sync for $oty {} +impl !Send for TokenStream {} +impl !Sync for TokenStream {} - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - mem::ManuallyDrop::new(self).handle.encode(w, s); - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl Decode<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - } - } - } - )* - - $( - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - } - - impl !Send for $ity {} - impl !Sync for $ity {} - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl Decode<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - } - } - } - )* +// Forward `Drop::drop` to the inherent `drop` method. +impl Drop for TokenStream { + fn drop(&mut self) { + Methods::ts_drop(TokenStream { handle: self.handle }); + } +} + +impl Encode for TokenStream { + fn encode(self, w: &mut Writer, s: &mut S) { + mem::ManuallyDrop::new(self).handle.encode(w, s); + } +} + +impl Encode for &TokenStream { + fn encode(self, w: &mut Writer, s: &mut S) { + self.handle.encode(w, s); + } +} + +impl Decode<'_, '_, S> for TokenStream { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + TokenStream { handle: handle::Handle::decode(r, s) } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) struct Span { + handle: handle::Handle, +} + +impl !Send for Span {} +impl !Sync for Span {} + +impl Encode for Span { + fn encode(self, w: &mut Writer, s: &mut S) { + self.handle.encode(w, s); + } +} + +impl Decode<'_, '_, S> for Span { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + Span { handle: handle::Handle::decode(r, s) } } } -with_api_handle_types!(define_client_handles); // FIXME(eddyb) generate these impls by pattern-matching on the // names of methods - also could use the presence of `fn drop` @@ -102,7 +75,7 @@ with_api_handle_types!(define_client_handles); impl Clone for TokenStream { fn clone(&self) -> Self { - self.clone() + Methods::ts_clone(self) } } @@ -122,23 +95,27 @@ impl Span { impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) + f.write_str(&Methods::span_debug(*self)) } } +pub(crate) use super::Methods; pub(crate) use super::symbol::Symbol; macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(impl $name { + ( + Methods { + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + }, + $($name:ident),* $(,)? + ) => { + impl Methods { $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? { Bridge::with(|bridge| { let mut buf = bridge.cached_buffer.take(); buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); + api_tags::Method::$method.encode(&mut buf, &mut ()); $($arg.encode(&mut buf, &mut ());)* buf = bridge.dispatch.call(buf); @@ -150,7 +127,7 @@ macro_rules! define_client_side { r.unwrap_or_else(|e| panic::resume_unwind(e.into())) }) })* - })* + } } } with_api!(self, self, define_client_side); diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs index 8c53bb609f60..f0c01e39de32 100644 --- a/library/proc_macro/src/bridge/handle.rs +++ b/library/proc_macro/src/bridge/handle.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use std::hash::Hash; use std::num::NonZero; -use std::ops::{Index, IndexMut}; +use std::ops::Index; use std::sync::atomic::{AtomicU32, Ordering}; use super::fxhash::FxHashMap; @@ -47,12 +47,6 @@ impl Index for OwnedStore { } } -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - /// Like `OwnedStore`, but avoids storing any value more than once. pub(super) struct InternedStore { owned: OwnedStore, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index b0ee9c0cc302..6f7c8726f925 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -21,14 +21,15 @@ use crate::{Delimiter, Level, Spacing}; /// `with_api!(MySelf, my_self, my_macro)` expands to: /// ```rust,ignore (pseudo-code) /// my_macro! { -/// // ... -/// Literal { +/// Methods { /// // ... -/// fn character(ch: char) -> MySelf::Literal; +/// fn lit_character(ch: char) -> MySelf::Literal; /// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); +/// fn lit_span(my_self: &MySelf::Literal) -> MySelf::Span; +/// fn lit_set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); /// }, +/// Literal, +/// Span, /// // ... /// } /// ``` @@ -48,77 +49,62 @@ use crate::{Delimiter, Level, Spacing}; macro_rules! with_api { ($S:ident, $self:ident, $m:ident) => { $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); + Methods { fn injected_env_var(var: &str) -> Option; fn track_env_var(var: &str, value: Option<&str>); fn track_path(path: &str); fn literal_from_str(s: &str) -> Result, ()>; fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( + + fn ts_drop(stream: $S::TokenStream); + fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream; + fn ts_is_empty(stream: &$S::TokenStream) -> bool; + fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>; + fn ts_from_str(src: &str) -> $S::TokenStream; + fn ts_to_string(stream: &$S::TokenStream) -> String; + fn ts_from_token_tree( tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>, ) -> $S::TokenStream; - fn concat_trees( + fn ts_concat_trees( base: Option<$S::TokenStream>, trees: Vec>, ) -> $S::TokenStream; - fn concat_streams( + fn ts_concat_streams( base: Option<$S::TokenStream>, streams: Vec<$S::TokenStream>, ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream + fn ts_into_trees( + stream: $S::TokenStream ) -> Vec>; - }, - Span { - fn debug($self: $S::Span) -> String; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn byte_range($self: $S::Span) -> Range; - fn start($self: $S::Span) -> $S::Span; - fn end($self: $S::Span) -> $S::Span; - fn line($self: $S::Span) -> usize; - fn column($self: $S::Span) -> usize; - fn file($self: $S::Span) -> String; - fn local_file($self: $S::Span) -> Option; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn subspan($self: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - Symbol { - fn normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>; - }, - } - }; -} -// Similar to `with_api`, but only lists the types requiring handles, and they -// are divided into the two storage categories. -macro_rules! with_api_handle_types { - ($m:ident) => { - $m! { - 'owned: - FreeFunctions, + fn span_debug(span: $S::Span) -> String; + fn span_parent(span: $S::Span) -> Option<$S::Span>; + fn span_source(span: $S::Span) -> $S::Span; + fn span_byte_range(span: $S::Span) -> Range; + fn span_start(span: $S::Span) -> $S::Span; + fn span_end(span: $S::Span) -> $S::Span; + fn span_line(span: $S::Span) -> usize; + fn span_column(span: $S::Span) -> usize; + fn span_file(span: $S::Span) -> String; + fn span_local_file(span: $S::Span) -> Option; + fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>; + fn span_subspan(span: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; + fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span; + fn span_source_text(span: $S::Span) -> Option; + fn span_save_span(span: $S::Span) -> usize; + fn span_recover_proc_macro_span(id: usize) -> $S::Span; + + fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>; + }, TokenStream, - - 'interned: Span, - // Symbol is handled manually + Symbol, } }; } +pub(crate) struct Methods; + #[allow(unsafe_code)] mod arena; #[allow(unsafe_code)] @@ -171,20 +157,16 @@ mod api_tags { use super::rpc::{Decode, Encode, Reader, Writer}; macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - + ( + Methods { + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + }, + $($name:ident),* $(,)? + ) => { pub(super) enum Method { - $($name($name)),* + $($method),* } - rpc_encode_decode!(enum Method { $($name(m)),* }); + rpc_encode_decode!(enum Method { $($method),* }); } } with_api!(self, self, declare_tags); diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index e9ef26c07f24..b79de9984453 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -5,108 +5,66 @@ use std::marker::PhantomData; use super::*; -macro_rules! define_server_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* +pub(super) struct HandleStore { + token_stream: handle::OwnedStore>, + span: handle::InternedStore>, +} + +impl HandleStore { + fn new(handle_counters: &'static client::HandleCounters) -> Self { + HandleStore { + token_stream: handle::OwnedStore::new(&handle_counters.token_stream), + span: handle::InternedStore::new(&handle_counters.span), } - - impl HandleStore { - fn new(handle_counters: &'static client::HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - impl Encode>> for Marked { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl Decode<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl<'s, S: Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl<'s, S: Types> Decode<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - )* - - $( - impl Encode>> for Marked { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl Decode<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - )* } } -with_api_handle_types!(define_server_handles); + +impl Encode> for Marked { + fn encode(self, w: &mut Writer, s: &mut HandleStore) { + s.token_stream.alloc(self).encode(w, s); + } +} + +impl Decode<'_, '_, HandleStore> for Marked { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { + s.token_stream.take(handle::Handle::decode(r, &mut ())) + } +} + +impl<'s, S: Types> Decode<'_, 's, HandleStore> + for &'s Marked +{ + fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore) -> Self { + &s.token_stream[handle::Handle::decode(r, &mut ())] + } +} + +impl Encode> for Marked { + fn encode(self, w: &mut Writer, s: &mut HandleStore) { + s.span.alloc(self).encode(w, s); + } +} + +impl Decode<'_, '_, HandleStore> for Marked { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { + s.span.copy(handle::Handle::decode(r, &mut ())) + } +} pub trait Types { - type FreeFunctions: 'static; type TokenStream: 'static + Clone; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* { + ( + Methods { + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + }, + $($name:ident),* $(,)? + ) => { + pub trait Server: Types { fn globals(&mut self) -> ExpnGlobals; /// Intern a symbol received from RPC @@ -114,51 +72,25 @@ macro_rules! declare_server_traits { /// Recover the string value of a symbol, and invoke a callback with it. fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)); + + $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)* } } } with_api!(Self, self_, declare_server_traits); -pub(super) struct MarkedTypes(S); - -impl Server for MarkedTypes { - fn globals(&mut self) -> ExpnGlobals { - <_>::mark(Server::globals(&mut self.0)) - } - fn intern_symbol(ident: &str) -> Self::Symbol { - <_>::mark(S::intern_symbol(ident)) - } - fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - S::with_symbol_string(symbol.unmark(), f) - } -} - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - struct Dispatcher { handle_store: HandleStore, server: S, } macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { + ( + Methods { + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + }, + $($name:ident),* $(,)? + ) => { // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. pub trait DispatcherTrait { // HACK(eddyb) these are here to allow `Self::$name` to work below. @@ -167,35 +99,37 @@ macro_rules! define_dispatcher_impl { fn dispatch(&mut self, buf: Buffer) -> Buffer; } - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* + impl DispatcherTrait for Dispatcher { + $(type $name = Marked;)* fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; let mut reader = &buf[..]; match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - $(let $arg = <$arg_ty>::decode(&mut reader, handle_store);)* - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `std`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; + $(api_tags::Method::$method => { + let mut call_method = || { + $(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)* + let r = server.$method($($arg),*); + $( + let r: $ret_ty = Mark::mark(r); + )* + r + }; + // HACK(eddyb) don't use `panic::catch_unwind` in a panic. + // If client and server happen to use the same `std`, + // `catch_unwind` asserts that the panic counter was 0, + // even when the closure passed to it didn't panic. + let r = if thread::panicking() { + Ok(call_method()) + } else { + panic::catch_unwind(panic::AssertUnwindSafe(call_method)) + .map_err(PanicMessage::from) + }; - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* + buf.clear(); + r.encode(&mut buf, handle_store); + })* } buf } @@ -354,8 +288,8 @@ pub trait MessagePipe: Sized { fn run_server< S: Server, - I: Encode>>, - O: for<'a, 's> Decode<'a, 's, HandleStore>>, + I: Encode>, + O: for<'a, 's> Decode<'a, 's, HandleStore>, >( strategy: &impl ExecutionStrategy, handle_counters: &'static client::HandleCounters, @@ -364,13 +298,13 @@ fn run_server< run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; + let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server }; let globals = dispatcher.server.globals(); let mut buf = Buffer::new(); - (globals, input).encode(&mut buf, &mut dispatcher.handle_store); + (> as Mark>::mark(globals), input) + .encode(&mut buf, &mut dispatcher.handle_store); buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); @@ -394,11 +328,13 @@ impl client::Client { strategy, handle_counters, server, - as Types>::TokenStream::mark(input), + >::mark(input), run, force_show_panics, ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) + .map(|s| { + >>::unmark(s).unwrap_or_default() + }) } } @@ -421,12 +357,14 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream handle_counters, server, ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), + >::mark(input), + >::mark(input2), ), run, force_show_panics, ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) + .map(|s| { + >>::unmark(s).unwrap_or_default() + }) } } diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index e070ec07681d..edba142bad72 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -46,7 +46,7 @@ impl Symbol { if string.is_ascii() { Err(()) } else { - client::Symbol::normalize_and_validate_ident(string) + client::Methods::symbol_normalize_and_validate_ident(string) } .unwrap_or_else(|_| panic!("`{:?}` is not a valid identifier", string)) } @@ -99,18 +99,14 @@ impl Encode for Symbol { } } -impl Decode<'_, '_, server::HandleStore>> - for Marked -{ - fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore>) -> Self { +impl Decode<'_, '_, server::HandleStore> for Marked { + fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore) -> Self { Mark::mark(S::intern_symbol(<&str>::decode(r, s))) } } -impl Encode>> - for Marked -{ - fn encode(self, w: &mut Writer, s: &mut server::HandleStore>) { +impl Encode> for Marked { + fn encode(self, w: &mut Writer, s: &mut server::HandleStore) { S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s)) } } diff --git a/library/proc_macro/src/diagnostic.rs b/library/proc_macro/src/diagnostic.rs index 5a209f7c7aa1..39a8ecb2ee52 100644 --- a/library/proc_macro/src/diagnostic.rs +++ b/library/proc_macro/src/diagnostic.rs @@ -170,6 +170,6 @@ impl Diagnostic { } } - crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self)); + crate::bridge::client::Methods::emit_diagnostic(to_internal(self)); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index a005f743ddfa..95a7ea7d7b3b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -58,6 +58,7 @@ use rustc_literal_escaper::{MixedUnit, unescape_byte_str, unescape_c_str, unesca #[unstable(feature = "proc_macro_totokens", issue = "130977")] pub use to_tokens::ToTokens; +use crate::bridge::client::Methods as BridgeMethods; use crate::escape::{EscapeOptions, escape_bytes}; /// Errors returned when trying to retrieve a literal unescaped value. @@ -158,7 +159,7 @@ impl TokenStream { /// Checks if this `TokenStream` is empty. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) + self.0.as_ref().map(|h| BridgeMethods::ts_is_empty(h)).unwrap_or(true) } /// Parses this `TokenStream` as an expression and attempts to expand any @@ -174,7 +175,7 @@ impl TokenStream { #[unstable(feature = "proc_macro_expand", issue = "90765")] pub fn expand_expr(&self) -> Result { let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { + match BridgeMethods::ts_expand_expr(stream) { Ok(stream) => Ok(TokenStream(Some(stream))), Err(_) => Err(ExpandError), } @@ -193,7 +194,7 @@ impl FromStr for TokenStream { type Err = LexError; fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) + Ok(TokenStream(Some(BridgeMethods::ts_from_str(src)))) } } @@ -212,7 +213,7 @@ impl FromStr for TokenStream { impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { - Some(ts) => write!(f, "{}", ts.to_string()), + Some(ts) => write!(f, "{}", BridgeMethods::ts_to_string(ts)), None => Ok(()), } } @@ -252,7 +253,7 @@ fn tree_to_bridge_tree( #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) + TokenStream(Some(BridgeMethods::ts_from_token_tree(tree_to_bridge_tree(tree)))) } } @@ -281,7 +282,7 @@ impl ConcatTreesHelper { if self.trees.is_empty() { TokenStream(None) } else { - TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees))) + TokenStream(Some(BridgeMethods::ts_concat_trees(None, self.trees))) } } @@ -289,7 +290,7 @@ impl ConcatTreesHelper { if self.trees.is_empty() { return; } - stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees)) + stream.0 = Some(BridgeMethods::ts_concat_trees(stream.0.take(), self.trees)) } } @@ -314,7 +315,7 @@ impl ConcatStreamsHelper { if self.streams.len() <= 1 { TokenStream(self.streams.pop()) } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) + TokenStream(Some(BridgeMethods::ts_concat_streams(None, self.streams))) } } @@ -326,7 +327,7 @@ impl ConcatStreamsHelper { if base.is_none() && self.streams.len() == 1 { stream.0 = self.streams.pop(); } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); + stream.0 = Some(BridgeMethods::ts_concat_streams(base, self.streams)); } } } @@ -377,7 +378,7 @@ impl Extend for TokenStream { macro_rules! extend_items { ($($item:ident)*) => { $( - #[stable(feature = "token_stream_extend_tt_items", since = "1.92.0")] + #[stable(feature = "token_stream_extend_ts_items", since = "1.92.0")] impl Extend<$item> for TokenStream { fn extend>(&mut self, iter: T) { self.extend(iter.into_iter().map(TokenTree::$item)); @@ -392,7 +393,7 @@ extend_items!(Group Literal Punct Ident); /// Public implementation details for the `TokenStream` type, such as iterators. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub mod token_stream { - use crate::{Group, Ident, Literal, Punct, TokenStream, TokenTree, bridge}; + use crate::{BridgeMethods, Group, Ident, Literal, Punct, TokenStream, TokenTree, bridge}; /// An iterator over `TokenStream`'s `TokenTree`s. /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, @@ -437,7 +438,9 @@ pub mod token_stream { type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) + IntoIter( + self.0.map(|v| BridgeMethods::ts_into_trees(v)).unwrap_or_default().into_iter(), + ) } } } @@ -509,7 +512,7 @@ impl Span { /// `self` was generated from, if any. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn parent(&self) -> Option { - self.0.parent().map(Span) + BridgeMethods::span_parent(self.0).map(Span) } /// The span for the origin source code that `self` was generated from. If @@ -517,25 +520,25 @@ impl Span { /// value is the same as `*self`. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn source(&self) -> Span { - Span(self.0.source()) + Span(BridgeMethods::span_source(self.0)) } /// Returns the span's byte position range in the source file. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn byte_range(&self) -> Range { - self.0.byte_range() + BridgeMethods::span_byte_range(self.0) } /// Creates an empty span pointing to directly before this span. #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn start(&self) -> Span { - Span(self.0.start()) + Span(BridgeMethods::span_start(self.0)) } /// Creates an empty span pointing to directly after this span. #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn end(&self) -> Span { - Span(self.0.end()) + Span(BridgeMethods::span_end(self.0)) } /// The one-indexed line of the source file where the span starts. @@ -543,7 +546,7 @@ impl Span { /// To obtain the line of the span's end, use `span.end().line()`. #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn line(&self) -> usize { - self.0.line() + BridgeMethods::span_line(self.0) } /// The one-indexed column of the source file where the span starts. @@ -551,7 +554,7 @@ impl Span { /// To obtain the column of the span's end, use `span.end().column()`. #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn column(&self) -> usize { - self.0.column() + BridgeMethods::span_column(self.0) } /// The path to the source file in which this span occurs, for display purposes. @@ -560,7 +563,7 @@ impl Span { /// It might be remapped (e.g. `"/src/lib.rs"`) or an artificial path (e.g. `""`). #[stable(feature = "proc_macro_span_file", since = "1.88.0")] pub fn file(&self) -> String { - self.0.file() + BridgeMethods::span_file(self.0) } /// The path to the source file in which this span occurs on the local file system. @@ -570,7 +573,7 @@ impl Span { /// This path should not be embedded in the output of the macro; prefer `file()` instead. #[stable(feature = "proc_macro_span_file", since = "1.88.0")] pub fn local_file(&self) -> Option { - self.0.local_file().map(PathBuf::from) + BridgeMethods::span_local_file(self.0).map(PathBuf::from) } /// Creates a new span encompassing `self` and `other`. @@ -578,14 +581,14 @@ impl Span { /// Returns `None` if `self` and `other` are from different files. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) + BridgeMethods::span_join(self.0, other.0).map(Span) } /// Creates a new span with the same line/column information as `self` but /// that resolves symbols as though it were at `other`. #[stable(feature = "proc_macro_span_resolved_at", since = "1.45.0")] pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) + Span(BridgeMethods::span_resolved_at(self.0, other.0)) } /// Creates a new span with the same name resolution behavior as `self` but @@ -610,21 +613,21 @@ impl Span { /// be used for diagnostics only. #[stable(feature = "proc_macro_source_text", since = "1.66.0")] pub fn source_text(&self) -> Option { - self.0.source_text() + BridgeMethods::span_source_text(self.0) } // Used by the implementation of `Span::quote` #[doc(hidden)] #[unstable(feature = "proc_macro_internals", issue = "27812")] pub fn save_span(&self) -> usize { - self.0.save_span() + BridgeMethods::span_save_span(self.0) } // Used by the implementation of `Span::quote` #[doc(hidden)] #[unstable(feature = "proc_macro_internals", issue = "27812")] pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) + Span(BridgeMethods::span_recover_proc_macro_span(id)) } diagnostic_method!(error, Level::Error); @@ -1389,7 +1392,12 @@ impl Literal { // was 'c' or whether it was '\u{63}'. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn subspan>(&self, range: R) -> Option { - self.0.span.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) + BridgeMethods::span_subspan( + self.0.span, + range.start_bound().cloned(), + range.end_bound().cloned(), + ) + .map(Span) } fn with_symbol_and_suffix(&self, f: impl FnOnce(&str, &str) -> R) -> R { @@ -1559,7 +1567,7 @@ impl FromStr for Literal { type Err = LexError; fn from_str(src: &str) -> Result { - match bridge::client::FreeFunctions::literal_from_str(src) { + match BridgeMethods::literal_from_str(src) { Ok(literal) => Ok(Literal(literal)), Err(()) => Err(LexError), } @@ -1601,11 +1609,12 @@ impl fmt::Debug for Literal { )] /// Functionality for adding environment state to the build dependency info. pub mod tracked { - use std::env::{self, VarError}; use std::ffi::OsStr; use std::path::Path; + use crate::BridgeMethods; + /// Retrieve an environment variable and add it to build dependency info. /// The build system executing the compiler will know that the variable was accessed during /// compilation, and will be able to rerun the build when the value of that variable changes. @@ -1614,9 +1623,8 @@ pub mod tracked { #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] pub fn env_var + AsRef>(key: K) -> Result { let key: &str = key.as_ref(); - let value = crate::bridge::client::FreeFunctions::injected_env_var(key) - .map_or_else(|| env::var(key), Ok); - crate::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); + let value = BridgeMethods::injected_env_var(key).map_or_else(|| env::var(key), Ok); + BridgeMethods::track_env_var(key, value.as_deref().ok()); value } @@ -1626,6 +1634,6 @@ pub mod tracked { #[unstable(feature = "proc_macro_tracked_path", issue = "99515")] pub fn path>(path: P) { let path: &str = path.as_ref().to_str().unwrap(); - crate::bridge::client::FreeFunctions::track_path(path); + BridgeMethods::track_path(path); } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 44db1bf22bc8..8bec157e4e6e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -468,7 +468,9 @@ extern crate std as realstd; // The standard macros that are not built-in to the compiler. #[macro_use] -mod macros; +#[doc(hidden)] +#[unstable(feature = "std_internals", issue = "none")] +pub mod macros; // The runtime entry point and a few unstable public functions used by the // compiler diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 25e2b7ea1370..0bb14552432d 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -347,35 +347,70 @@ macro_rules! eprintln { /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html /// [`log`]: https://crates.io/crates/log #[macro_export] +#[allow_internal_unstable(std_internals)] #[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { - // NOTE: We cannot use `concat!` to make a static string as a format argument - // of `eprintln!` because `file!` could contain a `{` or - // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` - // will be malformed. () => { $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!()) }; - ($val:expr $(,)?) => { + ($($val:expr),+ $(,)?) => { + $crate::macros::dbg_internal!(() () ($($val),+)) + }; +} + +/// Internal macro that processes a list of expressions and produces a chain of +/// nested `match`es, one for each expression, before finally calling `eprint!` +/// with the collected information and returning all the evaluated expressions +/// in a tuple. +/// +/// E.g. `dbg_internal!(() () (1, 2))` expands into +/// ```rust, ignore +/// match 1 { +/// tmp_1 => match 2 { +/// tmp_2 => { +/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); +/// (tmp_1, tmp_2) +/// } +/// } +/// } +/// ``` +/// +/// This is necessary so that `dbg!` outputs don't get torn, see #136703. +#[doc(hidden)] +#[rustc_macro_transparency = "semiopaque"] +pub macro dbg_internal { + (($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{ + $crate::eprint!( + $crate::concat!($($piece),+), + $( + $crate::stringify!($processed), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&$bound as &dyn $crate::fmt::Debug + ),+, + // The location returned here is that of the macro invocation, so + // it will be the same for all expressions. Thus, label these + // arguments so that they can be reused in every piece of the + // formatting template. + file=$crate::file!(), + line=$crate::line!(), + column=$crate::column!() + ); + // Comma separate the variables only when necessary so that this will + // not yield a tuple for a single expression, but rather just parenthesize + // the expression. + ($($bound),+) + }}, + (($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { - tmp => { - $crate::eprintln!("[{}:{}:{}] {} = {:#?}", - $crate::file!(), - $crate::line!(), - $crate::column!(), - $crate::stringify!($val), - // The `&T: Debug` check happens here (not in the format literal desugaring) - // to avoid format literal related messages and suggestions. - &&tmp as &dyn $crate::fmt::Debug, - ); - tmp - } + tmp => $crate::macros::dbg_internal!( + ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") + ($($processed => $bound,)* $val => tmp) + ($($rest),*) + ), } - }; - ($($val:expr),+ $(,)?) => { - ($($crate::dbg!($val)),+,) - }; + }, } diff --git a/library/std/src/sys/thread/windows.rs b/library/std/src/sys/thread/windows.rs index 6a21b11e0312..ea18572489ee 100644 --- a/library/std/src/sys/thread/windows.rs +++ b/library/std/src/sys/thread/windows.rs @@ -8,7 +8,7 @@ use crate::sys::pal::time::WaitableTimer; use crate::sys::pal::{dur2timeout, to_u16s}; use crate::sys::{FromInner, c, stack_overflow}; use crate::thread::ThreadInit; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -120,11 +120,28 @@ pub fn sleep(dur: Duration) { timer.set(dur)?; timer.wait() } + // Directly forward to `Sleep` for its zero duration behavior when indeed + // zero in order to skip the `Instant::now` calls, useless in this case. + if dur.is_zero() { + unsafe { c::Sleep(0) }; // Attempt to use high-precision sleep (Windows 10, version 1803+). - // On error fallback to the standard `Sleep` function. - // Also preserves the zero duration behavior of `Sleep`. - if dur.is_zero() || high_precision_sleep(dur).is_err() { - unsafe { c::Sleep(dur2timeout(dur)) } + // On error, fallback to the standard `Sleep` function. + } else if high_precision_sleep(dur).is_err() { + let start = Instant::now(); + unsafe { c::Sleep(dur2timeout(dur)) }; + + // See #149935: `Sleep` under Windows 7 and probably 8 as well seems a + // bit buggy for us as it can last less than the requested time while + // our API is meant to guarantee that. This is fixed by measuring the + // effective time difference and if needed, sleeping a bit more in + // order to ensure the duration is always exceeded. A fixed single + // millisecond works because `Sleep` operates based on a system-wide + // (until Windows 10 2004 that makes it process-local) interrupt timer + // that counts in "tick" units of ~15ms by default: a 1ms timeout + // therefore passes the next tick boundary. + if start.elapsed() < dur { + unsafe { c::Sleep(1) }; + } } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 52b38421eec2..844251f2c64d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -509,6 +509,12 @@ impl Step for RustAnalyzer { cargo.arg("--workspace"); cargo.arg("--exclude=xtask"); + if build_compiler.stage == 0 { + // This builds a proc macro against the bootstrap libproc_macro, which is not ABI + // compatible with the ABI proc-macro-srv expects to load. + cargo.arg("--exclude=proc-macro-srv"); + } + let mut skip_tests = vec![]; // NOTE: the following test skips is a bit cheeky in that it assumes there are no diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 152516baf734..9197870cb695 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::macros::{MacroCall, macro_backtrace}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; +use rustc_hir::{Arm, Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::{Span, SyntaxContext, sym}; @@ -90,33 +90,27 @@ impl LateLintPass<'_> for DbgMacro { (macro_call.span, String::from("()")) } }, - // dbg!(1) - ExprKind::Match(val, ..) => ( - macro_call.span, - snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability) - .to_string(), - ), - // dbg!(2, 3) - ExprKind::Tup( - [ - Expr { - kind: ExprKind::Match(first, ..), - .. - }, - .., - Expr { - kind: ExprKind::Match(last, ..), - .. - }, - ], - ) => { - let snippet = snippet_with_applicability( - cx, - first.span.source_callsite().to(last.span.source_callsite()), - "..", - &mut applicability, - ); - (macro_call.span, format!("({snippet})")) + ExprKind::Match(first, arms, _) => { + let vals = collect_vals(first, arms); + let suggestion = match vals.as_slice() { + // dbg!(1) => 1 + &[val] => { + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability) + .to_string() + } + // dbg!(2, 3) => (2, 3) + &[first, .., last] => { + let snippet = snippet_with_applicability( + cx, + first.span.source_callsite().to(last.span.source_callsite()), + "..", + &mut applicability, + ); + format!("({snippet})") + } + _ => unreachable!(), + }; + (macro_call.span, suggestion) }, _ => unreachable!(), }; @@ -169,3 +163,33 @@ fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } + +/// Extracts all value expressions from the `match`-tree generated by `dbg!`. +/// +/// E.g. from +/// ```rust, ignore +/// match 1 { +/// tmp_1 => match 2 { +/// tmp_2 => { +/// /* printing */ +/// (tmp_1, tmp_2) +/// } +/// } +/// } +/// ``` +/// this extracts `1` and `2`. +fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> { + let mut vals = vec![first]; + loop { + let [arm] = arms else { unreachable!("dbg! macro expansion only has single-arm matches") }; + + match is_async_move_desugar(arm.body).unwrap_or(arm.body).peel_drop_temps().kind { + ExprKind::Block(..) => return vals, + ExprKind::Match(val, a, _) => { + vals.push(val); + arms = a; + } + _ => unreachable!("dbg! macro expansion only results in block or match expressions"), + } + } +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr index 354cb882fd9f..24a807afd73d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr @@ -16,7 +16,7 @@ help: ALLOC was deallocated here: | LL | }; | ^ - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index d653ec3a069c..845b4f977ca3 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -11,7 +11,7 @@ LL | dbg!(x.0); | = 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: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: ALLOC (stack variable, size: 132, align: 4) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 41c381220cfd..f8920904f06f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -230,6 +230,7 @@ pub enum FnAbi { Win64, Win64Unwind, X86Interrupt, + RustPreserveNone, Unknown, } @@ -271,6 +272,7 @@ impl FnAbi { s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS, s if *s == sym::rust_dash_call => FnAbi::RustCall, s if *s == sym::rust_dash_cold => FnAbi::RustCold, + s if *s == sym::rust_dash_preserve_dash_none => FnAbi::RustPreserveNone, s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic, s if *s == sym::Rust => FnAbi::Rust, s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind, @@ -314,6 +316,7 @@ impl FnAbi { FnAbi::Rust => "Rust", FnAbi::RustCall => "rust-call", FnAbi::RustCold => "rust-cold", + FnAbi::RustPreserveNone => "rust-preserve-none", FnAbi::RustIntrinsic => "rust-intrinsic", FnAbi::Stdcall => "stdcall", FnAbi::StdcallUnwind => "stdcall-unwind", diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 6181413a46db..cbaac64be4bd 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -109,6 +109,7 @@ define_symbols! { vectorcall_dash_unwind = "vectorcall-unwind", win64_dash_unwind = "win64-unwind", x86_dash_interrupt = "x86-interrupt", + rust_dash_preserve_dash_none = "preserve-none", @PLAIN: __ra_fixup, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/bridge.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/bridge.rs index fc063a07b5f8..fc62f9413a34 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/bridge.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/bridge.rs @@ -1,6 +1,6 @@ //! `proc_macro::bridge` newtypes. -use proc_macro::bridge as pm_bridge; +use rustc_proc_macro::bridge as pm_bridge; pub use pm_bridge::{DelimSpan, Diagnostic, ExpnGlobals, LitKind}; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index 02bdcc50d387..8680e9180e3a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -3,7 +3,7 @@ mod proc_macros; mod version; -use proc_macro::bridge; +use rustc_proc_macro::bridge; use std::{fmt, fs, io, time::SystemTime}; use temp_dir::TempDir; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs index c763301135ee..76c5097101c7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -1,6 +1,6 @@ //! Proc macro ABI use crate::{ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream}; -use proc_macro::bridge; +use rustc_proc_macro::bridge; #[repr(transparent)] pub(crate) struct ProcMacros([bridge::client::ProcMacro]); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index f2d1dfbba4cc..920d58b4e981 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -22,9 +22,9 @@ )] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] -extern crate proc_macro; #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; +extern crate rustc_proc_macro; #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; @@ -52,7 +52,7 @@ use temp_dir::TempDir; pub use crate::server_impl::token_id::SpanId; -pub use proc_macro::Delimiter; +pub use rustc_proc_macro::Delimiter; pub use span; pub use crate::bridge::*; @@ -181,7 +181,9 @@ impl ProcMacroSrv<'_> { } pub trait ProcMacroSrvSpan: Copy + Send + Sync { - type Server<'a>: proc_macro::bridge::server::Server>; + type Server<'a>: rustc_proc_macro::bridge::server::Server< + TokenStream = crate::token_stream::TokenStream, + >; fn make_server<'a>( call_site: Self, def_site: Self, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 32725afc5527..ec30630c10bb 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -10,7 +10,7 @@ use std::{ }; use intern::Symbol; -use proc_macro::bridge::server; +use rustc_proc_macro::bridge::server; use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TextRange, TextSize}; use crate::{ @@ -19,8 +19,6 @@ use crate::{ server_impl::literal_from_str, }; -pub struct FreeFunctions; - pub struct RaSpanServer<'a> { // FIXME: Report this back to the caller to track as dependencies pub tracked_env_vars: HashMap, Option>>, @@ -33,13 +31,28 @@ pub struct RaSpanServer<'a> { } impl server::Types for RaSpanServer<'_> { - type FreeFunctions = FreeFunctions; type TokenStream = crate::token_stream::TokenStream; type Span = Span; type Symbol = Symbol; } -impl server::FreeFunctions for RaSpanServer<'_> { +impl server::Server for RaSpanServer<'_> { + fn globals(&mut self) -> ExpnGlobals { + ExpnGlobals { + def_site: self.def_site, + call_site: self.call_site, + mixed_site: self.mixed_site, + } + } + + fn intern_symbol(ident: &str) -> Self::Symbol { + Symbol::intern(ident) + } + + fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { + f(symbol.as_str()) + } + fn injected_env_var(&mut self, _: &str) -> Option { None } @@ -58,13 +71,19 @@ impl server::FreeFunctions for RaSpanServer<'_> { fn emit_diagnostic(&mut self, _: Diagnostic) { // FIXME handle diagnostic } -} -impl server::TokenStream for RaSpanServer<'_> { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { + fn ts_drop(&mut self, stream: Self::TokenStream) { + drop(stream); + } + + fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream { + stream.clone() + } + + fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool { stream.is_empty() } - fn from_str(&mut self, src: &str) -> Self::TokenStream { + fn ts_from_str(&mut self, src: &str) -> Self::TokenStream { Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| { Self::TokenStream::from_str( &format!("compile_error!(\"failed to parse str to token stream: {e}\")"), @@ -73,15 +92,15 @@ impl server::TokenStream for RaSpanServer<'_> { .unwrap() }) } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { + fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String { stream.to_string() } - fn from_token_tree(&mut self, tree: TokenTree) -> Self::TokenStream { + fn ts_from_token_tree(&mut self, tree: TokenTree) -> Self::TokenStream { Self::TokenStream::new(vec![tree]) } - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { + fn ts_expand_expr(&mut self, self_: &Self::TokenStream) -> Result { // FIXME: requires db, more importantly this requires name resolution so we would need to // eagerly expand this proc-macro, but we can't know that this proc-macro is eager until we // expand it ... @@ -90,7 +109,7 @@ impl server::TokenStream for RaSpanServer<'_> { Ok(self_.clone()) } - fn concat_trees( + fn ts_concat_trees( &mut self, base: Option, trees: Vec>, @@ -106,7 +125,7 @@ impl server::TokenStream for RaSpanServer<'_> { } } - fn concat_streams( + fn ts_concat_streams( &mut self, base: Option, streams: Vec, @@ -118,28 +137,26 @@ impl server::TokenStream for RaSpanServer<'_> { stream } - fn into_trees(&mut self, stream: Self::TokenStream) -> Vec> { + fn ts_into_trees(&mut self, stream: Self::TokenStream) -> Vec> { (*stream.0).clone() } -} -impl server::Span for RaSpanServer<'_> { - fn debug(&mut self, span: Self::Span) -> String { + fn span_debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn file(&mut self, span: Self::Span) -> String { + fn span_file(&mut self, span: Self::Span) -> String { self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default() } - fn local_file(&mut self, span: Self::Span) -> Option { + fn span_local_file(&mut self, span: Self::Span) -> Option { self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id())) } - fn save_span(&mut self, _span: Self::Span) -> usize { + fn span_save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools // This is called by the quote proc-macro which is expanded when the proc-macro is compiled // As such, r-a will never observe this 0 } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { + fn span_recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { // FIXME, quote is incompatible with third-party tools // This is called by the expansion of quote!, r-a will observe this, but we don't have // access to the spans that were encoded @@ -149,23 +166,23 @@ impl server::Span for RaSpanServer<'_> { /// /// See PR: /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, span: Self::Span) -> Option { + fn span_source_text(&mut self, span: Self::Span) -> Option { self.callback.as_mut()?.source_text(span) } - fn parent(&mut self, _span: Self::Span) -> Option { + fn span_parent(&mut self, _span: Self::Span) -> Option { // FIXME requires db, looks up the parent call site None } - fn source(&mut self, span: Self::Span) -> Self::Span { + fn span_source(&mut self, span: Self::Span) -> Self::Span { // FIXME requires db, returns the top level call site span } - fn byte_range(&mut self, span: Self::Span) -> Range { + fn span_byte_range(&mut self, span: Self::Span) -> Range { // FIXME requires db to resolve the ast id, THIS IS NOT INCREMENTAL Range { start: span.range.start().into(), end: span.range.end().into() } } - fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { + fn span_join(&mut self, first: Self::Span, second: Self::Span) -> Option { // We can't modify the span range for fixup spans, those are meaningful to fixup, so just // prefer the non-fixup span. if first.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { @@ -193,7 +210,7 @@ impl server::Span for RaSpanServer<'_> { ctx: second.ctx, }) } - fn subspan( + fn span_subspan( &mut self, span: Self::Span, start: Bound, @@ -237,11 +254,11 @@ impl server::Span for RaSpanServer<'_> { }) } - fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { + fn span_resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { Span { ctx: at.ctx, ..span } } - fn end(&mut self, span: Self::Span) -> Self::Span { + fn span_end(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return span; @@ -249,7 +266,7 @@ impl server::Span for RaSpanServer<'_> { Span { range: TextRange::empty(span.range.end()), ..span } } - fn start(&mut self, span: Self::Span) -> Self::Span { + fn span_start(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return span; @@ -257,38 +274,18 @@ impl server::Span for RaSpanServer<'_> { Span { range: TextRange::empty(span.range.start()), ..span } } - fn line(&mut self, _span: Self::Span) -> usize { + fn span_line(&mut self, _span: Self::Span) -> usize { // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL 1 } - fn column(&mut self, _span: Self::Span) -> usize { + fn span_column(&mut self, _span: Self::Span) -> usize { // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL 1 } -} -impl server::Symbol for RaSpanServer<'_> { - fn normalize_and_validate_ident(&mut self, string: &str) -> Result { + fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result { // FIXME: nfc-normalize and validate idents Ok(::intern_symbol(string)) } } - -impl server::Server for RaSpanServer<'_> { - fn globals(&mut self) -> ExpnGlobals { - ExpnGlobals { - def_site: self.def_site, - call_site: self.call_site, - mixed_site: self.mixed_site, - } - } - - fn intern_symbol(ident: &str) -> Self::Symbol { - Symbol::intern(ident) - } - - fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - f(symbol.as_str()) - } -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index a968ea4cd225..3bf07290c8c0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -6,7 +6,7 @@ use std::{ }; use intern::Symbol; -use proc_macro::bridge::server; +use rustc_proc_macro::bridge::server; use crate::{ ProcMacroClientHandle, @@ -25,8 +25,6 @@ impl std::fmt::Debug for SpanId { type Span = SpanId; -pub struct FreeFunctions; - pub struct SpanIdServer<'a> { // FIXME: Report this back to the caller to track as dependencies pub tracked_env_vars: HashMap, Option>>, @@ -39,161 +37,11 @@ pub struct SpanIdServer<'a> { } impl server::Types for SpanIdServer<'_> { - type FreeFunctions = FreeFunctions; type TokenStream = crate::token_stream::TokenStream; type Span = Span; type Symbol = Symbol; } -impl server::FreeFunctions for SpanIdServer<'_> { - fn injected_env_var(&mut self, _: &str) -> Option { - None - } - fn track_env_var(&mut self, var: &str, value: Option<&str>) { - self.tracked_env_vars.insert(var.into(), value.map(Into::into)); - } - fn track_path(&mut self, path: &str) { - self.tracked_paths.insert(path.into()); - } - - fn literal_from_str(&mut self, s: &str) -> Result, ()> { - literal_from_str(s, self.call_site) - } - - fn emit_diagnostic(&mut self, _: Diagnostic) {} -} - -impl server::TokenStream for SpanIdServer<'_> { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| { - Self::TokenStream::from_str( - &format!("compile_error!(\"failed to parse str to token stream: {e}\")"), - self.call_site, - ) - .unwrap() - }) - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree(&mut self, tree: TokenTree) -> Self::TokenStream { - Self::TokenStream::new(vec![tree]) - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - match base { - Some(mut base) => { - for tt in trees { - base.push_tree(tt); - } - base - } - None => Self::TokenStream::new(trees), - } - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut stream = base.unwrap_or_default(); - for s in streams { - stream.push_stream(s); - } - stream - } - - fn into_trees(&mut self, stream: Self::TokenStream) -> Vec> { - (*stream.0).clone() - } -} - -impl server::Span for SpanIdServer<'_> { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn file(&mut self, _span: Self::Span) -> String { - String::new() - } - fn local_file(&mut self, _span: Self::Span) -> Option { - None - } - fn save_span(&mut self, _span: Self::Span) -> usize { - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - self.call_site - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - span - } - fn byte_range(&mut self, _span: Self::Span) -> Range { - Range { start: 0, end: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn subspan( - &mut self, - span: Self::Span, - _start: Bound, - _end: Bound, - ) -> Option { - // Just return the span again, because some macros will unwrap the result. - Some(span) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - self.call_site - } - - fn end(&mut self, _self_: Self::Span) -> Self::Span { - self.call_site - } - - fn start(&mut self, _self_: Self::Span) -> Self::Span { - self.call_site - } - - fn line(&mut self, _span: Self::Span) -> usize { - 1 - } - - fn column(&mut self, _span: Self::Span) -> usize { - 1 - } -} - -impl server::Symbol for SpanIdServer<'_> { - fn normalize_and_validate_ident(&mut self, string: &str) -> Result { - // FIXME: nfc-normalize and validate idents - Ok(::intern_symbol(string)) - } -} - impl server::Server for SpanIdServer<'_> { fn globals(&mut self) -> ExpnGlobals { ExpnGlobals { @@ -210,4 +58,153 @@ impl server::Server for SpanIdServer<'_> { fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { f(symbol.as_str()) } + + fn injected_env_var(&mut self, _: &str) -> Option { + None + } + fn track_env_var(&mut self, var: &str, value: Option<&str>) { + self.tracked_env_vars.insert(var.into(), value.map(Into::into)); + } + fn track_path(&mut self, path: &str) { + self.tracked_paths.insert(path.into()); + } + + fn literal_from_str(&mut self, s: &str) -> Result, ()> { + literal_from_str(s, self.call_site) + } + + fn emit_diagnostic(&mut self, _: Diagnostic) {} + + fn ts_drop(&mut self, stream: Self::TokenStream) { + drop(stream); + } + + fn ts_clone(&mut self, stream: &Self::TokenStream) -> Self::TokenStream { + stream.clone() + } + + fn ts_is_empty(&mut self, stream: &Self::TokenStream) -> bool { + stream.is_empty() + } + fn ts_from_str(&mut self, src: &str) -> Self::TokenStream { + Self::TokenStream::from_str(src, self.call_site).unwrap_or_else(|e| { + Self::TokenStream::from_str( + &format!("compile_error!(\"failed to parse str to token stream: {e}\")"), + self.call_site, + ) + .unwrap() + }) + } + fn ts_to_string(&mut self, stream: &Self::TokenStream) -> String { + stream.to_string() + } + fn ts_from_token_tree(&mut self, tree: TokenTree) -> Self::TokenStream { + Self::TokenStream::new(vec![tree]) + } + + fn ts_expand_expr(&mut self, self_: &Self::TokenStream) -> Result { + Ok(self_.clone()) + } + + fn ts_concat_trees( + &mut self, + base: Option, + trees: Vec>, + ) -> Self::TokenStream { + match base { + Some(mut base) => { + for tt in trees { + base.push_tree(tt); + } + base + } + None => Self::TokenStream::new(trees), + } + } + + fn ts_concat_streams( + &mut self, + base: Option, + streams: Vec, + ) -> Self::TokenStream { + let mut stream = base.unwrap_or_default(); + for s in streams { + stream.push_stream(s); + } + stream + } + + fn ts_into_trees(&mut self, stream: Self::TokenStream) -> Vec> { + (*stream.0).clone() + } + + fn span_debug(&mut self, span: Self::Span) -> String { + format!("{:?}", span.0) + } + fn span_file(&mut self, _span: Self::Span) -> String { + String::new() + } + fn span_local_file(&mut self, _span: Self::Span) -> Option { + None + } + fn span_save_span(&mut self, _span: Self::Span) -> usize { + 0 + } + fn span_recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { + self.call_site + } + /// Recent feature, not yet in the proc_macro + /// + /// See PR: + /// https://github.com/rust-lang/rust/pull/55780 + fn span_source_text(&mut self, _span: Self::Span) -> Option { + None + } + + fn span_parent(&mut self, _span: Self::Span) -> Option { + None + } + fn span_source(&mut self, span: Self::Span) -> Self::Span { + span + } + fn span_byte_range(&mut self, _span: Self::Span) -> Range { + Range { start: 0, end: 0 } + } + fn span_join(&mut self, first: Self::Span, _second: Self::Span) -> Option { + // Just return the first span again, because some macros will unwrap the result. + Some(first) + } + fn span_subspan( + &mut self, + span: Self::Span, + _start: Bound, + _end: Bound, + ) -> Option { + // Just return the span again, because some macros will unwrap the result. + Some(span) + } + fn span_resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { + self.call_site + } + + fn span_end(&mut self, _self_: Self::Span) -> Self::Span { + self.call_site + } + + fn span_start(&mut self, _self_: Self::Span) -> Self::Span { + self.call_site + } + + fn span_line(&mut self, _span: Self::Span) -> usize { + 1 + } + + fn span_column(&mut self, _span: Self::Span) -> usize { + 1 + } + + fn symbol_normalize_and_validate_ident(&mut self, string: &str) -> Result { + // FIXME: nfc-normalize and validate idents + Ok(::intern_symbol(string)) + } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs index 36827d2561f9..2358f6963c79 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs @@ -4,8 +4,8 @@ use core::fmt; use std::{mem, sync::Arc}; use intern::Symbol; -use proc_macro::Delimiter; use rustc_lexer::{DocStyle, LiteralKind}; +use rustc_proc_macro::Delimiter; use crate::bridge::{DelimSpan, Group, Ident, LitKind, Literal, Punct, TokenTree}; @@ -52,7 +52,7 @@ impl TokenStream { S: SpanLike + Copy, { let mut groups = Vec::new(); - groups.push((proc_macro::Delimiter::None, 0..0, vec![])); + groups.push((rustc_proc_macro::Delimiter::None, 0..0, vec![])); let mut offset = 0; let mut tokens = rustc_lexer::tokenize(s, rustc_lexer::FrontmatterAllowed::No).peekable(); while let Some(token) = tokens.next() { @@ -102,7 +102,7 @@ impl TokenStream { }; match token.kind { rustc_lexer::TokenKind::OpenParen => { - groups.push((proc_macro::Delimiter::Parenthesis, range, vec![])) + groups.push((rustc_proc_macro::Delimiter::Parenthesis, range, vec![])) } rustc_lexer::TokenKind::CloseParen if *open_delim != Delimiter::Parenthesis => { return if *open_delim == Delimiter::None { @@ -130,7 +130,7 @@ impl TokenStream { ); } rustc_lexer::TokenKind::OpenBrace => { - groups.push((proc_macro::Delimiter::Brace, range, vec![])) + groups.push((rustc_proc_macro::Delimiter::Brace, range, vec![])) } rustc_lexer::TokenKind::CloseBrace if *open_delim != Delimiter::Brace => { return if *open_delim == Delimiter::None { @@ -158,7 +158,7 @@ impl TokenStream { ); } rustc_lexer::TokenKind::OpenBracket => { - groups.push((proc_macro::Delimiter::Bracket, range, vec![])) + groups.push((rustc_proc_macro::Delimiter::Bracket, range, vec![])) } rustc_lexer::TokenKind::CloseBracket if *open_delim != Delimiter::Bracket => { return if *open_delim == Delimiter::None { @@ -460,10 +460,10 @@ fn display_token_tree( f, "{}", match delimiter { - proc_macro::Delimiter::Parenthesis => "(", - proc_macro::Delimiter::Brace => "{", - proc_macro::Delimiter::Bracket => "[", - proc_macro::Delimiter::None => "", + rustc_proc_macro::Delimiter::Parenthesis => "(", + rustc_proc_macro::Delimiter::Brace => "{", + rustc_proc_macro::Delimiter::Bracket => "[", + rustc_proc_macro::Delimiter::None => "", } )?; if let Some(stream) = stream { @@ -473,10 +473,10 @@ fn display_token_tree( f, "{}", match delimiter { - proc_macro::Delimiter::Parenthesis => ")", - proc_macro::Delimiter::Brace => "}", - proc_macro::Delimiter::Bracket => "]", - proc_macro::Delimiter::None => "", + rustc_proc_macro::Delimiter::Parenthesis => ")", + rustc_proc_macro::Delimiter::Brace => "}", + rustc_proc_macro::Delimiter::Bracket => "]", + rustc_proc_macro::Delimiter::None => "", } )?; } @@ -587,16 +587,16 @@ fn debug_token_tree( f, "GROUP {}{} {:#?} {:#?} {:#?}", match delimiter { - proc_macro::Delimiter::Parenthesis => "(", - proc_macro::Delimiter::Brace => "{", - proc_macro::Delimiter::Bracket => "[", - proc_macro::Delimiter::None => "$", + rustc_proc_macro::Delimiter::Parenthesis => "(", + rustc_proc_macro::Delimiter::Brace => "{", + rustc_proc_macro::Delimiter::Bracket => "[", + rustc_proc_macro::Delimiter::None => "$", }, match delimiter { - proc_macro::Delimiter::Parenthesis => ")", - proc_macro::Delimiter::Brace => "}", - proc_macro::Delimiter::Bracket => "]", - proc_macro::Delimiter::None => "$", + rustc_proc_macro::Delimiter::Parenthesis => ")", + rustc_proc_macro::Delimiter::Brace => "}", + rustc_proc_macro::Delimiter::Bracket => "]", + rustc_proc_macro::Delimiter::None => "$", }, span.open, span.close, diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index 73dc08dc2b57..a151bb6012e1 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -1,3 +1,4 @@ +//@ ignore-loongarch64 (handles dso_local differently) //@ ignore-powerpc64 (handles dso_local differently) //@ ignore-apple (handles dso_local differently) diff --git a/tests/codegen-llvm/issues/issue-138497-nonzero-remove-trailing-zeroes.rs b/tests/codegen-llvm/issues/issue-138497-nonzero-remove-trailing-zeroes.rs new file mode 100644 index 000000000000..77cdbaf2bfe5 --- /dev/null +++ b/tests/codegen-llvm/issues/issue-138497-nonzero-remove-trailing-zeroes.rs @@ -0,0 +1,17 @@ +//! This test checks that removing trailing zeroes from a `NonZero`, +//! then creating a new `NonZero` from the result does not panic. + +//@ min-llvm-version: 21 +//@ compile-flags: -O -Zmerge-functions=disabled +#![crate_type = "lib"] + +use std::num::NonZero; + +// CHECK-LABEL: @remove_trailing_zeros +#[no_mangle] +pub fn remove_trailing_zeros(x: NonZero) -> NonZero { + // CHECK: %[[TRAILING:[a-z0-9_-]+]] = {{.*}} call {{.*}} i8 @llvm.cttz.i8(i8 %x, i1 true) + // CHECK-NEXT: %[[RET:[a-z0-9_-]+]] = lshr exact i8 %x, %[[TRAILING]] + // CHECK-NEXT: ret i8 %[[RET]] + NonZero::new(x.get() >> x.trailing_zeros()).unwrap() +} diff --git a/tests/codegen-llvm/lib-optimizations/append-elements.rs b/tests/codegen-llvm/lib-optimizations/append-elements.rs new file mode 100644 index 000000000000..b8657104d665 --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/append-elements.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -O -Zmerge-functions=disabled +//@ needs-deterministic-layouts +//@ min-llvm-version: 21 +#![crate_type = "lib"] + +//! Check that a temporary intermediate allocations can eliminated and replaced +//! with memcpy forwarding. +//! This requires Vec code to be structured in a way that avoids phi nodes from the +//! zero-capacity length flowing into the memcpy arguments. + +// CHECK-LABEL: @vec_append_with_temp_alloc +// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]] +#[no_mangle] +pub fn vec_append_with_temp_alloc(dst: &mut Vec, src: &[u8]) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]] + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_vec(); + dst.extend(&temp); + // CHECK: ret +} + +// CHECK-LABEL: @string_append_with_temp_alloc +// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]] +#[no_mangle] +pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]] + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_string(); + dst.push_str(&temp); + // CHECK: ret +} diff --git a/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs index 9a50f7b8e3a5..36eb2dde7afb 100644 --- a/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs +++ b/tests/codegen-llvm/loongarch-abi/call-llvm-intrinsics.rs @@ -23,9 +23,7 @@ pub fn do_call() { unsafe { // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 - // CHECK: load float, ptr %{{.}}, align 4 - // CHECK: call float @llvm.sqrt.f32(float %{{.}} + // CHECK: call float @llvm.sqrt.f32(float 4.000000e+00) sqrt(4.0); } } diff --git a/tests/codegen-llvm/loongarch/direct-access-external-data.rs b/tests/codegen-llvm/loongarch/direct-access-external-data.rs new file mode 100644 index 000000000000..de495d7fe9a7 --- /dev/null +++ b/tests/codegen-llvm/loongarch/direct-access-external-data.rs @@ -0,0 +1,47 @@ +//@ only-loongarch64 + +//@ revisions: DEFAULT PIE DIRECT INDIRECT +//@ [DEFAULT] compile-flags: -C relocation-model=static +//@ [PIE] compile-flags: -C relocation-model=pie +//@ [DIRECT] compile-flags: -C relocation-model=pie -Z direct-access-external-data=yes +//@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no + +#![crate_type = "rlib"] +#![feature(linkage)] + +unsafe extern "C" { + // CHECK: @VAR = external + // DEFAULT-NOT: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i32 + safe static VAR: i32; + + // When "linkage" is used, we generate an indirection global. + // Check dso_local is still applied to the actual global. + // CHECK: @EXTERNAL = external + // DEFAULT-NOT: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "external"] + safe static EXTERNAL: *const u32; + + // CHECK: @WEAK = extern_weak + // DEFAULT-NOT: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "extern_weak"] + safe static WEAK: *const u32; +} + +#[no_mangle] +pub fn refer() { + core::hint::black_box(VAR); + core::hint::black_box(EXTERNAL); + core::hint::black_box(WEAK); +} diff --git a/tests/codegen-llvm/preserve-none.rs b/tests/codegen-llvm/preserve-none.rs new file mode 100644 index 000000000000..b45e49a466bf --- /dev/null +++ b/tests/codegen-llvm/preserve-none.rs @@ -0,0 +1,33 @@ +//@ add-minicore +//@ revisions: X86 AARCH64 UNSUPPORTED +//@ [X86] compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu +//@ [X86] needs-llvm-components: x86 +//@ [AARCH64] compile-flags: -C no-prepopulate-passes --target=aarch64-unknown-linux-gnu +//@ [AARCH64] needs-llvm-components: aarch64 +//@ [UNSUPPORTED] compile-flags: -C no-prepopulate-passes --target=i686-unknown-linux-gnu +//@ [UNSUPPORTED] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(rust_preserve_none_cc)] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; + +// X86: define{{( dso_local)?}} preserve_nonecc void @peach(i16 +// AARCH64: define{{( dso_local)?}} preserve_nonecc void @peach(i16 +// UNSUPPORTED: define{{( dso_local)?}} void @peach(i16 +#[no_mangle] +#[inline(never)] +pub extern "rust-preserve-none" fn peach(x: u16) { + loop {} +} + +// X86: call preserve_nonecc void @peach(i16 +// AARCH64: call preserve_nonecc void @peach(i16 +// UNSUPPORTED: call void @peach(i16 +pub fn quince(x: u16) { + if let 12345u16 = x { + peach(54321); + } +} diff --git a/tests/codegen-llvm/slice_cse_optimization.rs b/tests/codegen-llvm/slice_cse_optimization.rs new file mode 100644 index 000000000000..2b1851d8ae44 --- /dev/null +++ b/tests/codegen-llvm/slice_cse_optimization.rs @@ -0,0 +1,46 @@ +//! Various iterating method over slice correctly optimized using common subexpression elimination. +//! Checks function has memory(argmem: read) attribute. +//! Regression test for . +//@ compile-flags: -O + +#![crate_type = "lib"] +// CHECK-LABEL: @has_zero_iter +// CHECK-SAME: #[[ATTR:[0-9]+]] +#[inline(never)] +#[unsafe(no_mangle)] +pub fn has_zero_iter(xs: &[u8]) -> bool { + xs.iter().any(|&x| x == 0) +} + +// CHECK-LABEL: @has_zero_ptr +// CHECK-SAME: #[[ATTR]] +#[inline(never)] +#[unsafe(no_mangle)] +fn has_zero_ptr(xs: &[u8]) -> bool { + let range = xs.as_ptr_range(); + let mut start = range.start; + let end = range.end; + while start < end { + unsafe { + if *start == 0 { + return true; + } + start = start.add(1); + } + } + false +} +// CHECK-LABEL: @has_zero_for +// CHECK-SAME: #[[ATTR]] +#[inline(never)] +#[unsafe(no_mangle)] +fn has_zero_for(xs: &[u8]) -> bool { + for x in xs { + if *x == 0 { + return true; + } + } + false +} + +// CHECK: attributes #[[ATTR]] = { {{.*}}memory(argmem: read){{.*}} } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 9202814adec7..6ffadd4c51db 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { - scope 12 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { - scope 14 (inlined NonNull::<[T]>::cast::) { - scope 15 (inlined NonNull::<[T]>::as_ptr) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 18 (inlined ::deallocate) { - scope 19 (inlined std::alloc::Global::deallocate_impl) { - scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { let mut _9: *mut u8; - scope 21 (inlined Layout::size) { + scope 26 (inlined Layout::size) { } - scope 22 (inlined NonNull::::as_ptr) { + scope 27 (inlined NonNull::::as_ptr) { } - scope 23 (inlined std::alloc::dealloc) { + scope 28 (inlined std::alloc::dealloc) { let mut _10: usize; - scope 24 (inlined Layout::size) { + scope 29 (inlined Layout::size) { } - scope 25 (inlined Layout::align) { - scope 26 (inlined std::ptr::Alignment::as_usize) { + scope 30 (inlined Layout::align) { + scope 31 (inlined std::ptr::Alignment::as_usize) { } } } @@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 7 (inlined Layout::for_value_raw::<[T]>) { let mut _5: usize; - let mut _6: usize; + let mut _7: std::ptr::Alignment; scope 8 { - scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _7: std::ptr::Alignment; + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { } } scope 9 (inlined size_of_val_raw::<[T]>) { } - scope 10 (inlined align_of_val_raw::<[T]>) { + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) { + let _6: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[T]>) { + } } } } @@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { StorageLive(_4); _3 = copy _2 as *mut [T] (Transmute); _4 = copy _2 as *const [T] (Transmute); - StorageLive(_6); + StorageLive(_7); _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable]; } bb1: { + StorageLive(_6); _6 = const ::ALIGN; - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); StorageDead(_6); + _8 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_4); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 9202814adec7..6ffadd4c51db 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { - scope 12 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { - scope 14 (inlined NonNull::<[T]>::cast::) { - scope 15 (inlined NonNull::<[T]>::as_ptr) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 18 (inlined ::deallocate) { - scope 19 (inlined std::alloc::Global::deallocate_impl) { - scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { let mut _9: *mut u8; - scope 21 (inlined Layout::size) { + scope 26 (inlined Layout::size) { } - scope 22 (inlined NonNull::::as_ptr) { + scope 27 (inlined NonNull::::as_ptr) { } - scope 23 (inlined std::alloc::dealloc) { + scope 28 (inlined std::alloc::dealloc) { let mut _10: usize; - scope 24 (inlined Layout::size) { + scope 29 (inlined Layout::size) { } - scope 25 (inlined Layout::align) { - scope 26 (inlined std::ptr::Alignment::as_usize) { + scope 30 (inlined Layout::align) { + scope 31 (inlined std::ptr::Alignment::as_usize) { } } } @@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 7 (inlined Layout::for_value_raw::<[T]>) { let mut _5: usize; - let mut _6: usize; + let mut _7: std::ptr::Alignment; scope 8 { - scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _7: std::ptr::Alignment; + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { } } scope 9 (inlined size_of_val_raw::<[T]>) { } - scope 10 (inlined align_of_val_raw::<[T]>) { + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) { + let _6: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[T]>) { + } } } } @@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { StorageLive(_4); _3 = copy _2 as *mut [T] (Transmute); _4 = copy _2 as *const [T] (Transmute); - StorageLive(_6); + StorageLive(_7); _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable]; } bb1: { + StorageLive(_6); _6 = const ::ALIGN; - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); StorageDead(_6); + _8 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_4); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 9202814adec7..6ffadd4c51db 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { - scope 12 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { - scope 14 (inlined NonNull::<[T]>::cast::) { - scope 15 (inlined NonNull::<[T]>::as_ptr) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 18 (inlined ::deallocate) { - scope 19 (inlined std::alloc::Global::deallocate_impl) { - scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { let mut _9: *mut u8; - scope 21 (inlined Layout::size) { + scope 26 (inlined Layout::size) { } - scope 22 (inlined NonNull::::as_ptr) { + scope 27 (inlined NonNull::::as_ptr) { } - scope 23 (inlined std::alloc::dealloc) { + scope 28 (inlined std::alloc::dealloc) { let mut _10: usize; - scope 24 (inlined Layout::size) { + scope 29 (inlined Layout::size) { } - scope 25 (inlined Layout::align) { - scope 26 (inlined std::ptr::Alignment::as_usize) { + scope 30 (inlined Layout::align) { + scope 31 (inlined std::ptr::Alignment::as_usize) { } } } @@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 7 (inlined Layout::for_value_raw::<[T]>) { let mut _5: usize; - let mut _6: usize; + let mut _7: std::ptr::Alignment; scope 8 { - scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _7: std::ptr::Alignment; + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { } } scope 9 (inlined size_of_val_raw::<[T]>) { } - scope 10 (inlined align_of_val_raw::<[T]>) { + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) { + let _6: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[T]>) { + } } } } @@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { StorageLive(_4); _3 = copy _2 as *mut [T] (Transmute); _4 = copy _2 as *const [T] (Transmute); - StorageLive(_6); + StorageLive(_7); _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable]; } bb1: { + StorageLive(_6); _6 = const ::ALIGN; - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); StorageDead(_6); + _8 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_4); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 9202814adec7..6ffadd4c51db 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -12,32 +12,32 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { - scope 12 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { - scope 14 (inlined NonNull::<[T]>::cast::) { - scope 15 (inlined NonNull::<[T]>::as_ptr) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 18 (inlined ::deallocate) { - scope 19 (inlined std::alloc::Global::deallocate_impl) { - scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { let mut _9: *mut u8; - scope 21 (inlined Layout::size) { + scope 26 (inlined Layout::size) { } - scope 22 (inlined NonNull::::as_ptr) { + scope 27 (inlined NonNull::::as_ptr) { } - scope 23 (inlined std::alloc::dealloc) { + scope 28 (inlined std::alloc::dealloc) { let mut _10: usize; - scope 24 (inlined Layout::size) { + scope 29 (inlined Layout::size) { } - scope 25 (inlined Layout::align) { - scope 26 (inlined std::ptr::Alignment::as_usize) { + scope 30 (inlined Layout::align) { + scope 31 (inlined std::ptr::Alignment::as_usize) { } } } @@ -51,15 +51,25 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 7 (inlined Layout::for_value_raw::<[T]>) { let mut _5: usize; - let mut _6: usize; + let mut _7: std::ptr::Alignment; scope 8 { - scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _7: std::ptr::Alignment; + scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { } } scope 9 (inlined size_of_val_raw::<[T]>) { } - scope 10 (inlined align_of_val_raw::<[T]>) { + scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) { + let _6: usize; + scope 11 { + scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + } + scope 12 (inlined align_of_val_raw::<[T]>) { + } } } } @@ -72,17 +82,17 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { StorageLive(_4); _3 = copy _2 as *mut [T] (Transmute); _4 = copy _2 as *const [T] (Transmute); - StorageLive(_6); + StorageLive(_7); _5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable]; } bb1: { + StorageLive(_6); _6 = const ::ALIGN; - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); StorageDead(_6); + _8 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_4); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 83b10f8bd688..dddcffdd4843 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -11,7 +11,7 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]> // CHECK: [[ALIGN:_.+]] = const ::ALIGN; // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); - // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); + // CHECK: [[C:_.+]] = copy ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) diff --git a/tests/ui/abi/rust-preserve-none-cc.rs b/tests/ui/abi/rust-preserve-none-cc.rs new file mode 100644 index 000000000000..deacb926971c --- /dev/null +++ b/tests/ui/abi/rust-preserve-none-cc.rs @@ -0,0 +1,67 @@ +//@ run-pass +//@ needs-unwind + +#![feature(rust_preserve_none_cc)] + +struct CrateOf<'a> { + mcintosh: f64, + golden_delicious: u64, + jonagold: Option<&'a u64>, + rome: [u64; 12], +} + +#[inline(never)] +extern "rust-preserve-none" fn oven_explosion() { + panic!("bad time"); +} + +#[inline(never)] +fn bite_into(yummy: u64) -> u64 { + let did_it_actually = std::panic::catch_unwind(move || { + oven_explosion() + }); + assert!(did_it_actually.is_err()); + yummy - 25 +} + +#[inline(never)] +extern "rust-preserve-none" fn lotsa_apples( + honeycrisp: u64, + gala: u32, + fuji: f64, + granny_smith: &[u64], + pink_lady: (), + and_a: CrateOf<'static>, + cosmic_crisp: u64, + ambrosia: f64, + winesap: &[u64], +) -> (u64, f64, u64, u64) { + assert_eq!(honeycrisp, 220); + assert_eq!(gala, 140); + assert_eq!(fuji, 210.54201234); + assert_eq!(granny_smith, &[180, 210]); + assert_eq!(pink_lady, ()); + assert_eq!(and_a.mcintosh, 150.0); + assert_eq!(and_a.golden_delicious, 185); + assert_eq!(and_a.jonagold, None); // my scales can't weight these gargantuans. + assert_eq!(and_a.rome, [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]); + assert_eq!(cosmic_crisp, 270); + assert_eq!(ambrosia, 193.1); + assert_eq!(winesap, &[]); + ( + and_a.rome.iter().sum(), + fuji + ambrosia, + cosmic_crisp - honeycrisp, + bite_into(and_a.golden_delicious) + ) +} + +fn main() { + let pie = lotsa_apples(220, 140, 210.54201234, &[180, 210], (), CrateOf { + mcintosh: 150.0, + golden_delicious: 185, + jonagold: None, + rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202] + }, 270, 193.1, &[]); + assert_eq!(pie, (2292, 403.64201234, 50, 160)); +} diff --git a/tests/ui/coercion/closure-in-array.rs b/tests/ui/coercion/closure-in-array.rs new file mode 100644 index 000000000000..ca5c021c77a7 --- /dev/null +++ b/tests/ui/coercion/closure-in-array.rs @@ -0,0 +1,7 @@ +// Weakened closure sig inference by #140283. +fn foo usize, const N: usize>(x: [F; N]) {} + +fn main() { + foo([|s| s.len()]) + //~^ ERROR: type annotations needed +} diff --git a/tests/ui/coercion/closure-in-array.stderr b/tests/ui/coercion/closure-in-array.stderr new file mode 100644 index 000000000000..90cf590c09e7 --- /dev/null +++ b/tests/ui/coercion/closure-in-array.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/closure-in-array.rs:5:11 + | +LL | foo([|s| s.len()]) + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | foo([|s: /* Type */| s.len()]) + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/coercion/coerce-many-with-ty-var.rs b/tests/ui/coercion/coerce-many-with-ty-var.rs new file mode 100644 index 000000000000..cbd16f58ea5b --- /dev/null +++ b/tests/ui/coercion/coerce-many-with-ty-var.rs @@ -0,0 +1,36 @@ +//@ run-pass +// Check that least upper bound coercions don't resolve type variable merely based on the first +// coercion. Check issue #136420. + +fn foo() {} +fn bar() {} + +fn infer(_: T) {} + +fn infer_array_element(_: [T; 2]) {} + +fn main() { + // Previously the element type's ty var will be unified with `foo`. + let _: [_; 2] = [foo, bar]; + infer_array_element([foo, bar]); + + let _ = if false { + foo + } else { + bar + }; + infer(if false { + foo + } else { + bar + }); + + let _ = match false { + true => foo, + false => bar, + }; + infer(match false { + true => foo, + false => bar, + }); +} diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr index f332bc6a7a21..f34ac0ea306c 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr @@ -4,7 +4,7 @@ error[E0106]: missing lifetime specifier LL | dbg!(b); | ^^^^^^^ expected named lifetime parameter | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find function `a` in this scope --> $DIR/ice-line-bounds-issue-148732.rs:1:7 @@ -37,7 +37,7 @@ LL | dbg!(b); | ^^^^^^^ the trait `Debug` is not implemented for fn item `fn() {b}` | = help: use parentheses to call this function: `b()` - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs b/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs new file mode 100644 index 000000000000..e503e353104a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs @@ -0,0 +1,21 @@ +#![crate_type = "lib"] + +extern "rust-preserve-none" fn apple() {} //~ ERROR "rust-preserve-none" ABI is experimental + +trait T { + extern "rust-preserve-none" fn banana(); //~ ERROR "rust-preserve-none" ABI is experimental + extern "rust-preserve-none" fn citrus() {} //~ ERROR "rust-preserve-none" ABI is experimental +} + +struct S; +impl T for S { + extern "rust-preserve-none" fn banana() {} //~ ERROR "rust-preserve-none" ABI is experimental +} + +impl S { + extern "rust-preserve-none" fn durian() {} //~ ERROR "rust-preserve-none" ABI is experimental +} + +type Fig = extern "rust-preserve-none" fn(); //~ ERROR "rust-preserve-none" ABI is experimental + +extern "rust-preserve-none" {} //~ ERROR "rust-preserve-none" ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.stderr b/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.stderr new file mode 100644 index 000000000000..b9d00e317b1f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.stderr @@ -0,0 +1,73 @@ +error[E0658]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:3:8 + | +LL | extern "rust-preserve-none" fn apple() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:6:12 + | +LL | extern "rust-preserve-none" fn banana(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:7:12 + | +LL | extern "rust-preserve-none" fn citrus() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:12:12 + | +LL | extern "rust-preserve-none" fn banana() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:16:12 + | +LL | extern "rust-preserve-none" fn durian() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:19:19 + | +LL | type Fig = extern "rust-preserve-none" fn(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` 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]: the extern "rust-preserve-none" ABI is experimental and subject to change + --> $DIR/feature-gate-rust-preserve-none-cc.rs:21:8 + | +LL | extern "rust-preserve-none" {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151401 for more information + = help: add `#![feature(rust_preserve_none_cc)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs b/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs index 5b5843a8ddbb..570b559eb61a 100644 --- a/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs +++ b/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs @@ -1,5 +1,5 @@ //@ run-pass -#![allow(unused_variables)] +#![warn(unused)] #![deny(non_shorthand_field_patterns)] pub struct Value { pub value: A } @@ -13,5 +13,5 @@ macro_rules! pat { fn main() { let pat!(value) = Value { value: () }; - //~^ WARN value assigned to `value` is never read + //~^ WARN unused variable: `value` } diff --git a/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.stderr b/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.stderr index ba7d3515b0d8..3a68ec212b4a 100644 --- a/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.stderr +++ b/tests/ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.stderr @@ -1,11 +1,15 @@ -warning: value assigned to `value` is never read +warning: unused variable: `value` --> $DIR/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs:15:14 | LL | let pat!(value) = Value { value: () }; - | ^^^^^ + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_value` | - = help: maybe it is overwritten before being read? - = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default +note: the lint level is defined here + --> $DIR/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` warning: 1 warning emitted diff --git a/tests/ui/lint/unused/auxiliary/unused_assignment_proc_macro.rs b/tests/ui/lint/unused/auxiliary/unused_assignment_proc_macro.rs new file mode 100644 index 000000000000..41cfefbaff54 --- /dev/null +++ b/tests/ui/lint/unused/auxiliary/unused_assignment_proc_macro.rs @@ -0,0 +1,23 @@ +#![feature(proc_macro_quote)] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_derive(Drop)] +pub fn generate(ts: TokenStream) -> TokenStream { + let mut ts = ts.into_iter(); + let _pub = ts.next(); + let _struct = ts.next(); + let name = ts.next().unwrap(); + let TokenTree::Group(fields) = ts.next().unwrap() else { panic!() }; + let mut fields = fields.stream().into_iter(); + let field = fields.next().unwrap(); + + quote! { + impl Drop for $name { + fn drop(&mut self) { + let Self { $field } = self; + } + } + } +} diff --git a/tests/ui/lint/unused/unused_assignment.rs b/tests/ui/lint/unused/unused_assignment.rs new file mode 100644 index 000000000000..f7b8ec94bc3b --- /dev/null +++ b/tests/ui/lint/unused/unused_assignment.rs @@ -0,0 +1,21 @@ +// Unused assignments to an unused variable should trigger only the `unused_variables` lint and not +// also the `unused_assignments` lint. This test covers the situation where the span of the unused +// variable identifier comes from a different scope to the binding pattern - here, from a proc +// macro's input tokenstream (whereas the binding pattern is generated within the proc macro +// itself). +// +// Regression test for https://github.com/rust-lang/rust/issues/151514 +// +//@ check-pass +//@ proc-macro: unused_assignment_proc_macro.rs +#![warn(unused)] + +extern crate unused_assignment_proc_macro; +use unused_assignment_proc_macro::Drop; + +#[derive(Drop)] +pub struct S { + a: (), //~ WARN unused variable: `a` +} + +fn main() {} diff --git a/tests/ui/lint/unused/unused_assignment.stderr b/tests/ui/lint/unused/unused_assignment.stderr new file mode 100644 index 000000000000..1f0619ecf142 --- /dev/null +++ b/tests/ui/lint/unused/unused_assignment.stderr @@ -0,0 +1,15 @@ +warning: unused variable: `a` + --> $DIR/unused_assignment.rs:18:5 + | +LL | a: (), + | ^ help: try ignoring the field: `a: _` + | +note: the lint level is defined here + --> $DIR/unused_assignment.rs:11:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 1 warning emitted + diff --git a/tests/ui/mismatched_types/mismatched-types-issue-126222.stderr b/tests/ui/mismatched_types/mismatched-types-issue-126222.stderr index 2a8f9867abb8..6843cb65a8cd 100644 --- a/tests/ui/mismatched_types/mismatched-types-issue-126222.stderr +++ b/tests/ui/mismatched_types/mismatched-types-issue-126222.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | x => dbg!(x), | ^^^^^^^ expected `()`, found integer | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have meant to return this value | LL | x => return dbg!(x), @@ -16,7 +16,7 @@ error[E0308]: mismatched types LL | dbg!(x) | ^^^^^^^ expected `()`, found integer | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have meant to return this value | LL | return dbg!(x) @@ -28,7 +28,7 @@ error[E0308]: mismatched types LL | _ => dbg!(1) | ^^^^^^^ expected `()`, found integer | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have meant to return this value | LL | _ => return dbg!(1) @@ -40,7 +40,7 @@ error[E0308]: mismatched types LL | _ => {dbg!(1)} | ^^^^^^^ expected `()`, found integer | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have meant to return this value | LL | _ => {return dbg!(1)} diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 49d7cb4e0aad..45cb29d10ec2 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -5,7 +5,7 @@ error[E0277]: `Dummy` doesn't implement `Debug` | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy` | = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs index d766411e4f98..3b6f2a9b08f7 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs +++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs @@ -53,7 +53,6 @@ pub fn main() { } match (E::E { a: 10, e: C { c: 20 } }) { mut x @ E::E{ a, e: C { mut c } } => { - //~^ WARN value assigned to `a` is never read x = E::NotE; //~^ WARN value assigned to `x` is never read c += 30; diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.stderr b/tests/ui/pattern/bindings-after-at/bind-by-copy.stderr index d775b69ef0a5..d0128950ddda 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy.stderr +++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.stderr @@ -20,20 +20,12 @@ LL | y.d.c = 30; = help: maybe it is overwritten before being read? warning: value assigned to `x` is never read - --> $DIR/bind-by-copy.rs:57:13 + --> $DIR/bind-by-copy.rs:56:13 | LL | x = E::NotE; | ^^^^^^^^^^^ | = help: maybe it is overwritten before being read? -warning: value assigned to `a` is never read - --> $DIR/bind-by-copy.rs:55:23 - | -LL | mut x @ E::E{ a, e: C { mut c } } => { - | ^ - | - = help: maybe it is overwritten before being read? - -warning: 4 warnings emitted +warning: 3 warnings emitted diff --git a/tests/ui/print-request/print-calling-conventions.stdout b/tests/ui/print-request/print-calling-conventions.stdout index b8b939e1c04e..8366697d0fb0 100644 --- a/tests/ui/print-request/print-calling-conventions.stdout +++ b/tests/ui/print-request/print-calling-conventions.stdout @@ -21,6 +21,7 @@ riscv-interrupt-s rust-call rust-cold rust-invalid +rust-preserve-none stdcall stdcall-unwind system diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index f515cb62c7cd..fdf5115303ba 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -8,7 +8,7 @@ LL | let _ = dbg!(a); LL | let _ = dbg!(a); | ^^^^^^^ value used here after move | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider borrowing instead of transferring ownership | LL | let _ = dbg!(&a); diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 4e0ae9184150..2c4ce2676b07 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -5,7 +5,7 @@ LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug` | = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr index fd9d693525cc..0fab0f003375 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr @@ -1,4 +1,4 @@ -error: target feature `soft-float` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI +error: target feature `soft-float` cannot be enabled with `#[target_feature]`: use a soft-float target instead --> $DIR/abi-incompatible-target-feature-attribute.rs:17:32 | LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs index 0cdaf3358d25..c6370f01c47d 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs @@ -19,4 +19,5 @@ extern crate minicore; use minicore::*; //~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly -//~? WARN unstable feature specified for `-Ctarget-feature` +//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` +//[x86]~? WARN use a soft-float target instead diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr index 90a9665fb41b..a8395f2d4690 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr @@ -1,6 +1,7 @@ -warning: unstable feature specified for `-Ctarget-feature`: `soft-float` +warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: use a soft-float target instead | - = note: this feature is not stably supported; its behavior can change in the future + = note: 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 #116344 warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly | diff --git a/tests/ui/target-feature/x86-soft-float-cfg.rs b/tests/ui/target-feature/x86-soft-float-cfg.rs new file mode 100644 index 000000000000..8718338ca105 --- /dev/null +++ b/tests/ui/target-feature/x86-soft-float-cfg.rs @@ -0,0 +1,17 @@ +//! The soft-float target feature is *not* exposed as `cfg` on x86. +//@ revisions: soft hard +//@[hard] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@[hard] needs-llvm-components: x86 +//@[soft] compile-flags: --target=x86_64-unknown-none --crate-type=lib +//@[soft] needs-llvm-components: x86 +//@ check-pass +//@ ignore-backends: gcc +//@ add-minicore +#![feature(no_core)] +#![no_core] +#![allow(unexpected_cfgs)] + +// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this +// complains about the missing macro rather than showing the error... but that's good enough. +#[cfg(target_feature = "soft-float")] +compile_error!("the soft-float feature should NOT be exposed in `cfg`"); diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index b3791a2446cb..5666a5972f37 100644 --- a/tests/ui/thir-print/offset_of.stdout +++ b/tests/ui/thir-print/offset_of.stdout @@ -68,7 +68,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::concrete).10) - span: $DIR/offset_of.rs:37:5: 1440:57 (#0) + span: $DIR/offset_of.rs:37:5: 1445:57 (#0) } } Stmt { @@ -117,7 +117,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::concrete).20) - span: $DIR/offset_of.rs:38:5: 1440:57 (#0) + span: $DIR/offset_of.rs:38:5: 1445:57 (#0) } } Stmt { @@ -166,7 +166,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::concrete).30) - span: $DIR/offset_of.rs:39:5: 1440:57 (#0) + span: $DIR/offset_of.rs:39:5: 1445:57 (#0) } } Stmt { @@ -215,7 +215,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::concrete).40) - span: $DIR/offset_of.rs:40:5: 1440:57 (#0) + span: $DIR/offset_of.rs:40:5: 1445:57 (#0) } } Stmt { @@ -264,7 +264,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::concrete).50) - span: $DIR/offset_of.rs:41:5: 1440:57 (#0) + span: $DIR/offset_of.rs:41:5: 1445:57 (#0) } } ] @@ -864,7 +864,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::generic).12) - span: $DIR/offset_of.rs:45:5: 1440:57 (#0) + span: $DIR/offset_of.rs:45:5: 1445:57 (#0) } } Stmt { @@ -913,7 +913,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::generic).24) - span: $DIR/offset_of.rs:46:5: 1440:57 (#0) + span: $DIR/offset_of.rs:46:5: 1445:57 (#0) } } Stmt { @@ -962,7 +962,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::generic).36) - span: $DIR/offset_of.rs:47:5: 1440:57 (#0) + span: $DIR/offset_of.rs:47:5: 1445:57 (#0) } } Stmt { @@ -1011,7 +1011,7 @@ body: ) else_block: None hir_id: HirId(DefId(offset_of::generic).48) - span: $DIR/offset_of.rs:48:5: 1440:57 (#0) + span: $DIR/offset_of.rs:48:5: 1445:57 (#0) } } ] diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr index 31acc5bb10ec..0907489f8e8a 100644 --- a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr +++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | b"abc".iter().for_each(|x| dbg!(x)); | ^^^^^^^ expected `()`, found `&u8` | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/closure-ty-mismatch-issue-128561.rs:8:9 diff --git a/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr index 59e56f672374..972c2ced0037 100644 --- a/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr +++ b/tests/ui/typeck/suggestions/suggest-clone-in-macro-issue-139253.stderr @@ -26,7 +26,7 @@ error[E0308]: mismatched types LL | let c: S = dbg!(field); | ^^^^^^^^^^^ expected `S`, found `&S` | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using clone here | LL | let c: S = dbg!(field).clone(); @@ -38,7 +38,7 @@ error[E0308]: mismatched types LL | let c: S = dbg!(dbg!(field)); | ^^^^^^^^^^^^^^^^^ expected `S`, found `&S` | - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::macros::dbg_internal` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider using clone here | LL | let c: S = dbg!(dbg!(field)).clone();