diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 8d3c10fd770a6..ca2753ea2fd98 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -172,6 +172,8 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug { fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; fn is_unit(this: TyAndLayout<'a, Self>) -> bool; fn is_transparent(this: TyAndLayout<'a, Self>) -> bool; + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool; } impl<'a, Ty> TyAndLayout<'a, Ty> { @@ -269,6 +271,30 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } + /// If this method returns `true`, then this type should always have a `PassMode` of + /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a + /// non-Rustic ABI (this is true for structs annotated with the + /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute). + /// + /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike + /// C any changes the caller makes to the passed value will not be reflected in the callee, so + /// the attribute is only useful for types where observing the value in the caller after the + /// function call isn't allowed (a.k.a. `va_list`). + /// + /// This function handles transparent types automatically. + pub fn pass_indirectly_in_non_rustic_abis(mut self, cx: &C) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + while self.is_transparent() + && let Some((_, field)) = self.non_1zst_field(cx) + { + self = field; + } + + Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self) + } + /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. pub fn non_1zst_field(&self, cx: &C) -> Option<(FieldIdx, Self)> diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de44c8755a078..05b25da8043ad 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -88,14 +88,17 @@ bitflags! { const IS_C = 1 << 0; const IS_SIMD = 1 << 1; const IS_TRANSPARENT = 1 << 2; - // Internal only for now. If true, don't reorder fields. - // On its own it does not prevent ABI optimizations. + /// Internal only for now. If true, don't reorder fields. + /// On its own it does not prevent ABI optimizations. const IS_LINEAR = 1 << 3; - // If true, the type's crate has opted into layout randomization. - // Other flags can still inhibit reordering and thus randomization. - // The seed stored in `ReprOptions.field_shuffle_seed`. + /// If true, the type's crate has opted into layout randomization. + /// Other flags can still inhibit reordering and thus randomization. + /// The seed stored in `ReprOptions.field_shuffle_seed`. const RANDOMIZE_LAYOUT = 1 << 4; - // Any of these flags being set prevent field reordering optimisation. + /// If true, the type is always passed indirectly by non-Rustic ABIs. + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5; + /// Any of these flags being set prevent field reordering optimisation. const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() | ReprFlags::IS_LINEAR.bits(); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index f09b02251e4d0..1270f8759d1bd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -676,3 +676,12 @@ impl SingleAttributeParser for SanitizeParser { Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span }) } } + +pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser; + +impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser { + const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 15904fd7d3348..9844b7554fada 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,8 +20,9 @@ use crate::attributes::allow_unstable::{ use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, - NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser, - TargetFeatureParser, TrackCallerParser, UsedParser, + NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, + RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, + TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ @@ -241,6 +242,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index e23c7eebeca1e..db746242ac05c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -150,8 +150,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } } - PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { - if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL + PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => { + if local == ty::CAPTURE_STRUCT_LOCAL && proj_base.is_empty() && !self.upvars.is_empty() { @@ -165,10 +165,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ", as `Fn` closures cannot mutate their captured variables".to_string() } } else { - let source = self.borrowed_content_source(PlaceRef { - local: the_place_err.local, - projection: proj_base, - }); + let source = + self.borrowed_content_source(PlaceRef { local, projection: proj_base }); let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); opt_source = Some(source); if let Some(desc) = self.describe_place(access_place.as_ref()) { @@ -532,6 +530,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() => { + self.point_at_binding_outside_closure(&mut err, local, access_place); self.expected_fn_found_fn_mut_call(&mut err, span, act); } @@ -950,6 +949,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + /// When modifying a binding from inside of an `Fn` closure, point at the binding definition. + fn point_at_binding_outside_closure( + &self, + err: &mut Diag<'_>, + local: Local, + access_place: Place<'tcx>, + ) { + let place = access_place.as_ref(); + for (index, elem) in place.projection.into_iter().enumerate() { + if let ProjectionElem::Deref = elem { + if index == 0 { + if self.body.local_decls[local].is_ref_for_guard() { + continue; + } + if let LocalInfo::StaticRef { .. } = *self.body.local_decls[local].local_info() + { + continue; + } + } + if let Some(field) = self.is_upvar_field_projection(PlaceRef { + local, + projection: place.projection.split_at(index + 1).0, + }) { + let var_index = field.index(); + let upvar = self.upvars[var_index]; + if let Some(hir_id) = upvar.info.capture_kind_expr_id { + let node = self.infcx.tcx.hir_node(hir_id); + if let hir::Node::Expr(expr) = node + && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::def::Res::Local(hir_id) = path.res + && let hir::Node::Pat(pat) = self.infcx.tcx.hir_node(hir_id) + { + let name = upvar.to_string(self.infcx.tcx); + err.span_label( + pat.span, + format!("`{name}` declared here, outside the closure"), + ); + break; + } + } + } + } + } + } /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) { err.span_label(sp, format!("cannot {act}")); @@ -962,6 +1005,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let def_id = tcx.hir_enclosing_body_owner(fn_call_id); let mut look_at_return = true; + err.span_label(closure_span, "in this closure"); // If the HIR node is a function or method call, get the DefId // of the callee function or method, the span, and args of the call expr let get_call_details = || { @@ -1032,7 +1076,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(span) = arg { err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); err.span_label(call_span, "expects `Fn` instead of `FnMut`"); - err.span_label(closure_span, "in this closure"); look_at_return = false; } } @@ -1059,7 +1102,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { sig.decl.output.span(), "change this to return `FnMut` instead of `Fn`", ); - err.span_label(closure_span, "in this closure"); } _ => {} } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 209b8efa2c3b3..ac20f9c64fa1a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -229,7 +229,7 @@ fn instrument_function_attr<'ll>( } fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { - if !sess.opts.unstable_opts.no_jump_tables { + if sess.opts.cg.jump_tables { return None; } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 2c472801aa044..5dcb5df55720c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -657,6 +657,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"), WarnFollowing, EncodeCrossCrate::No ), + // See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details. + rustc_attr!( + rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, + "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis." + ), // Limits: ungated!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 1bb87673d52d2..a5f7debe1787b 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -679,6 +679,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]` + RustcPassIndirectlyInNonRusticAbis(Span), + /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`. RustcSimdMonomorphizeLaneLimit(Limit), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 11c54b0ac1da0..d59fccb3f1a0b 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -91,6 +91,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeStart(..) => Yes, RustcMain => No, RustcObjectLifetimeDefault => No, + RustcPassIndirectlyInNonRusticAbis(..) => No, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, ShouldPanic { .. } => No, diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index eb630fc801863..0d0a1f6b76a29 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -3,9 +3,9 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(debug_closure_helpers))] #![feature(associated_type_defaults)] #![feature(closure_track_caller)] -#![feature(debug_closure_helpers)] #![feature(exhaustive_patterns)] #![feature(never_type)] #![feature(variant_count)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 6659aff711107..56c0f4e7cee48 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,10 +59,10 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(debug_closure_helpers))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(debug_closure_helpers)] #![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index be33db21d1df6..6c08b37dec083 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -620,6 +620,7 @@ fn test_codegen_options_tracking_hash() { tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); tracked!(instrument_coverage, InstrumentCoverage::Yes); + tracked!(jump_tables, false); tracked!(link_dead_code, Some(true)); tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(llvm_args, vec![String::from("1"), String::from("2")]); @@ -831,7 +832,6 @@ fn test_unstable_options_tracking_hash() { tracked!(mutable_noalias, false); tracked!(next_solver, NextSolverConfig { coherence: true, globally: true }); tracked!(no_generate_arange_section, true); - tracked!(no_jump_tables, true); tracked!(no_link, true); tracked!(no_profiler_runtime, true); tracked!(no_trait_vptr, true); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d3468499b4b3a..83de7d3892314 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2875,6 +2875,71 @@ enum AsmLabelKind { Binary, } +/// Checks if a potential label is actually a Hexagon register span notation. +/// +/// Hexagon assembly uses register span notation like `r1:0`, `V5:4.w`, `p1:0` etc. +/// These follow the pattern: `[letter][digit(s)]:[digit(s)][optional_suffix]` +/// +/// Returns `true` if the string matches a valid Hexagon register span pattern. +pub fn is_hexagon_register_span(possible_label: &str) -> bool { + // Extract the full register span from the context + if let Some(colon_idx) = possible_label.find(':') { + let after_colon = &possible_label[colon_idx + 1..]; + is_hexagon_register_span_impl(&possible_label[..colon_idx], after_colon) + } else { + false + } +} + +/// Helper function for use within the lint when we have statement context. +fn is_hexagon_register_span_context( + possible_label: &str, + statement: &str, + colon_idx: usize, +) -> bool { + // Extract what comes after the colon in the statement + let after_colon_start = colon_idx + 1; + if after_colon_start >= statement.len() { + return false; + } + + // Get the part after the colon, up to the next whitespace or special character + let after_colon_full = &statement[after_colon_start..]; + let after_colon = after_colon_full + .chars() + .take_while(|&c| c.is_ascii_alphanumeric() || c == '.') + .collect::(); + + is_hexagon_register_span_impl(possible_label, &after_colon) +} + +/// Core implementation for checking hexagon register spans. +fn is_hexagon_register_span_impl(before_colon: &str, after_colon: &str) -> bool { + if before_colon.len() < 1 || after_colon.is_empty() { + return false; + } + + let mut chars = before_colon.chars(); + let start = chars.next().unwrap(); + + // Must start with a letter (r, V, p, etc.) + if !start.is_ascii_alphabetic() { + return false; + } + + let rest = &before_colon[1..]; + + // Check if the part after the first letter is all digits and non-empty + if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_digit()) { + return false; + } + + // Check if after colon starts with digits (may have suffix like .w, .h) + let digits_after = after_colon.chars().take_while(|c| c.is_ascii_digit()).collect::(); + + !digits_after.is_empty() +} + impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { @@ -2957,6 +3022,14 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { break 'label_loop; } + // Check for Hexagon register span notation (e.g., "r1:0", "V5:4", "V3:2.w") + // This is valid Hexagon assembly syntax, not a label + if matches!(cx.tcx.sess.asm_arch, Some(InlineAsmArch::Hexagon)) + && is_hexagon_register_span_context(possible_label, statement, idx) + { + break 'label_loop; + } + for c in chars { // Inside a template format arg, any character is permitted for the // purposes of label detection because we assume that it can be diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs index f49301b0215db..b3c91583914a1 100644 --- a/compiler/rustc_lint/src/tests.rs +++ b/compiler/rustc_lint/src/tests.rs @@ -2,6 +2,7 @@ use rustc_span::{Symbol, create_default_session_globals_then}; +use crate::builtin::is_hexagon_register_span; use crate::levels::parse_lint_and_tool_name; #[test] @@ -27,3 +28,29 @@ fn parse_lint_multiple_path() { ) }); } + +#[test] +fn test_hexagon_register_span_patterns() { + // Valid Hexagon register span patterns + assert!(is_hexagon_register_span("r1:0")); + assert!(is_hexagon_register_span("r15:14")); + assert!(is_hexagon_register_span("V5:4")); + assert!(is_hexagon_register_span("V3:2")); + assert!(is_hexagon_register_span("V5:4.w")); + assert!(is_hexagon_register_span("V3:2.h")); + assert!(is_hexagon_register_span("r99:98")); + assert!(is_hexagon_register_span("V123:122.whatever")); + + // Invalid patterns - these should be treated as potential labels + assert!(!is_hexagon_register_span("label1")); + assert!(!is_hexagon_register_span("foo:")); + assert!(!is_hexagon_register_span(":0")); + assert!(!is_hexagon_register_span("r:0")); // missing digits before colon + assert!(!is_hexagon_register_span("r1:")); // missing digits after colon + assert!(!is_hexagon_register_span("r1:a")); // non-digit after colon + assert!(!is_hexagon_register_span("1:0")); // starts with digit, not letter + assert!(!is_hexagon_register_span("r1")); // no colon + assert!(!is_hexagon_register_span("r")); // too short + assert!(!is_hexagon_register_span("")); // empty + assert!(!is_hexagon_register_span("ra:0")); // letter in first digit group +} diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index eefb913a33fa4..7763507143f4b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -3,7 +3,7 @@ use std::{cmp, fmt}; use rustc_abi::{ AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo, - PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; use rustc_error_messages::DiagMessage; @@ -1173,6 +1173,11 @@ where fn is_transparent(this: TyAndLayout<'tcx>) -> bool { matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent()) } + + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS)) + } } /// Calculates whether a function's ABI can unwind or not. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2b9079da1830b..77c5e46e5e4cc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1573,6 +1573,14 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::IS_LINEAR); } + // See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details. + if find_attr!( + self.get_all_attrs(did), + AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) + ) { + flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS); + } + ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c214104d60670..5944a1e8da5d1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -284,6 +284,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::DebuggerVisualizer(..) | AttributeKind::RustcMain + | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) | AttributeKind::PinV2(..), ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { @@ -1770,6 +1771,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: target.to_string(), }); } + // Error on `#[repr(transparent)]` in combination with + // `#[rustc_pass_indirectly_in_non_rustic_abis]` + if is_transparent + && let Some(&pass_indirectly_span) = + find_attr!(attrs, AttributeKind::RustcPassIndirectlyInNonRusticAbis(span) => span) + { + self.dcx().emit_err(errors::TransparentIncompatible { + hint_spans: vec![span, pass_indirectly_span], + target: target.to_string(), + }); + } if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::ReprConflicting { hint_spans }); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b89aec7d22a91..c9d73adf31d49 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2093,6 +2093,8 @@ options! { "instrument the generated code to support LLVM source-based code coverage reports \ (note, the compiler build config must include `profiler = true`); \ implies `-C symbol-mangling-version=v0`"), + jump_tables: bool = (true, parse_bool, [TRACKED], + "allow jump table and lookup table generation from switch case lowering (default: yes)"), link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED], "a single extra argument to append to the linker invocation (can be used several times)"), link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], @@ -2475,8 +2477,6 @@ options! { "omit DWARF address ranges that give faster lookups"), no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED], "disable the compatibility version of the `implied_bounds_ty` query"), - no_jump_tables: bool = (false, parse_no_value, [TRACKED], - "disable the jump tables and lookup tables that can be generated from a switch case lowering"), no_leak_check: bool = (false, parse_no_value, [UNTRACKED], "disable the 'leak check' for subtyping; unsound, but useful for tests"), no_link: bool = (false, parse_no_value, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 02bae6fec785f..86b6bb16835b9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1944,6 +1944,7 @@ symbols! { rustc_partition_codegened, rustc_partition_reused, rustc_pass_by_value, + rustc_pass_indirectly_in_non_rustic_abis, rustc_peek, rustc_peek_liveness, rustc_peek_maybe_init, diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 5c23e7036b043..b86d0baeb942e 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -114,6 +114,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { if kind == AbiKind::DarwinPCS { // On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits, diff --git a/compiler/rustc_target/src/callconv/amdgpu.rs b/compiler/rustc_target/src/callconv/amdgpu.rs index 3ec6d0b3da20b..98ab3ce8eb746 100644 --- a/compiler/rustc_target/src/callconv/amdgpu.rs +++ b/compiler/rustc_target/src/callconv/amdgpu.rs @@ -10,11 +10,15 @@ where ret.extend_integer_width_to(32); } -fn classify_arg<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index abc9a404e2ea4..4c1ff27aac509 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -65,6 +65,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; diff --git a/compiler/rustc_target/src/callconv/avr.rs b/compiler/rustc_target/src/callconv/avr.rs index 0d690eff68dcf..0646d3c8ea1a4 100644 --- a/compiler/rustc_target/src/callconv/avr.rs +++ b/compiler/rustc_target/src/callconv/avr.rs @@ -30,6 +30,8 @@ //! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount //! of compiler frontend specific calling convention logic implemented here. +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { @@ -38,13 +40,23 @@ fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg_ty(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() { arg.make_indirect(); } } -pub(crate) fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } @@ -54,6 +66,6 @@ pub(crate) fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { continue; } - classify_arg_ty(arg); + classify_arg_ty(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/bpf.rs b/compiler/rustc_target/src/callconv/bpf.rs index ec5c1c2cf6860..3624f406704e9 100644 --- a/compiler/rustc_target/src/callconv/bpf.rs +++ b/compiler/rustc_target/src/callconv/bpf.rs @@ -1,4 +1,6 @@ // see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -9,7 +11,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -17,7 +26,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -26,7 +38,7 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/csky.rs b/compiler/rustc_target/src/callconv/csky.rs index cf289e639eac4..95741f137feab 100644 --- a/compiler/rustc_target/src/callconv/csky.rs +++ b/compiler/rustc_target/src/callconv/csky.rs @@ -4,6 +4,8 @@ // Reference: Clang CSKY lowering code // https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162 +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; fn classify_ret(arg: &mut ArgAbi<'_, Ty>) { @@ -27,11 +29,18 @@ fn classify_ret(arg: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !arg.layout.is_sized() { // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } // For argument type, the first 4*XLen parts of aggregate will be passed // in registers, and the rest will be passed in stack. // So we can coerce to integers directly and let backend handle it correctly. @@ -47,7 +56,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -56,6 +68,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/hexagon.rs b/compiler/rustc_target/src/callconv/hexagon.rs index d4f6dd0a5b4d3..e08e6daa7405a 100644 --- a/compiler/rustc_target/src/callconv/hexagon.rs +++ b/compiler/rustc_target/src/callconv/hexagon.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -8,7 +10,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -16,7 +25,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -25,6 +37,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index bc3c9601fa3d3..bbea841b41069 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -287,6 +287,11 @@ fn classify_arg<'a, Ty, C>( // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *avail_gprs = (*avail_gprs).saturating_sub(1); + return; + } if !is_vararg { match should_use_fp_conv(cx, &arg.layout, xlen, flen) { Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { diff --git a/compiler/rustc_target/src/callconv/m68k.rs b/compiler/rustc_target/src/callconv/m68k.rs index 0b637e1e27a5b..f4668b4afbd20 100644 --- a/compiler/rustc_target/src/callconv/m68k.rs +++ b/compiler/rustc_target/src/callconv/m68k.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -8,11 +10,18 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !arg.layout.is_sized() { // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() { arg.pass_by_stack_offset(None); } else { @@ -20,7 +29,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -29,6 +41,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 8ffd7bd177849..d2572cc035c1c 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -1,4 +1,4 @@ -use rustc_abi::{HasDataLayout, Size}; +use rustc_abi::{HasDataLayout, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; @@ -14,18 +14,26 @@ where } } -fn classify_arg(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_sized() { + // FIXME: Update offset? // Not touching this... return; } let dl = cx.data_layout(); - let size = arg.layout.size; let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *offset = offset.align_to(align) + dl.pointer_size().align_to(align); + return; + } + + let size = arg.layout.size; if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); @@ -36,8 +44,9 @@ where *offset = offset.align_to(align) + size.align_to(align); } -pub(crate) fn compute_abi_info(cx: &C, fn_abi: &mut FnAbi<'_, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { let mut offset = Size::ZERO; diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 8386a15933c98..313ad6ddce800 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -82,6 +82,10 @@ where extend_integer_width_mips(arg, 64); return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } let dl = cx.data_layout(); let size = arg.layout.size; diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index a33c246c88c67..5411e8f8176b0 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -677,30 +677,30 @@ impl<'a, Ty> FnAbi<'a, Ty> { } "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), - "avr" => avr::compute_abi_info(self), + "avr" => avr::compute_abi_info(cx, self), "loongarch32" | "loongarch64" => loongarch::compute_abi_info(cx, self), - "m68k" => m68k::compute_abi_info(self), - "csky" => csky::compute_abi_info(self), + "m68k" => m68k::compute_abi_info(cx, self), + "csky" => csky::compute_abi_info(cx, self), "mips" | "mips32r6" => mips::compute_abi_info(cx, self), "mips64" | "mips64r6" => mips64::compute_abi_info(cx, self), "powerpc" => powerpc::compute_abi_info(cx, self), "powerpc64" => powerpc64::compute_abi_info(cx, self), "s390x" => s390x::compute_abi_info(cx, self), - "msp430" => msp430::compute_abi_info(self), + "msp430" => msp430::compute_abi_info(cx, self), "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { - nvptx64::compute_abi_info(self) + nvptx64::compute_abi_info(cx, self) } } - "hexagon" => hexagon::compute_abi_info(self), + "hexagon" => hexagon::compute_abi_info(cx, self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" | "wasm64" => wasm::compute_abi_info(cx, self), - "bpf" => bpf::compute_abi_info(self), + "bpf" => bpf::compute_abi_info(cx, self), arch => panic!("no lowering implemented for {arch}"), } } diff --git a/compiler/rustc_target/src/callconv/msp430.rs b/compiler/rustc_target/src/callconv/msp430.rs index 3b53d183ddcda..7d2336346beb5 100644 --- a/compiler/rustc_target/src/callconv/msp430.rs +++ b/compiler/rustc_target/src/callconv/msp430.rs @@ -1,6 +1,8 @@ // Reference: MSP430 Embedded Application Binary Interface // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; // 3.5 Structures or Unions Passed and Returned by Reference @@ -17,7 +19,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { arg.make_indirect(); } else { @@ -25,7 +34,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -34,6 +46,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index dc32dd87a7e76..a19b89c0132f8 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -11,7 +11,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.is_sized() { classify_aggregate(arg) } else if arg.layout.size.bits() < 32 && arg.layout.is_sized() { @@ -81,7 +88,10 @@ where } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -90,7 +100,7 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/powerpc.rs b/compiler/rustc_target/src/callconv/powerpc.rs index 2f6129626b812..67066672eca3f 100644 --- a/compiler/rustc_target/src/callconv/powerpc.rs +++ b/compiler/rustc_target/src/callconv/powerpc.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; use crate::spec::HasTargetSpec; @@ -9,7 +11,10 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C: HasTargetSpec>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if arg.is_ignore() { // powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs. if cx.target_spec().os == "linux" @@ -20,14 +25,17 @@ fn classify_arg(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) { } return; } - if arg.layout.is_aggregate() { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) || arg.layout.is_aggregate() { arg.make_indirect(); } else { arg.extend_integer_width_to(32); } } -pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index be1d13816eff7..380b280fbc644 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -52,6 +52,10 @@ where // Not touching this... return; } + if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 16de3fe070dd4..c4310bf6ccfb0 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -290,9 +290,15 @@ fn classify_arg<'a, Ty, C>( Ty: TyAbiInterface<'a, C> + Copy, { if !arg.layout.is_sized() { + // FIXME: Update avail_gprs? // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *avail_gprs = (*avail_gprs).saturating_sub(1); + return; + } if !is_vararg { match should_use_fp_conv(cx, &arg.layout, xlen, flen) { Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index d2ae404b23b8b..c2f2b47690cab 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -37,6 +37,10 @@ where } return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } let size = arg.layout.size; if size.bits() <= 128 { diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 8ffd7bd177849..d424214aa497e 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -1,4 +1,4 @@ -use rustc_abi::{HasDataLayout, Size}; +use rustc_abi::{HasDataLayout, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; @@ -14,15 +14,22 @@ where } } -fn classify_arg(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_sized() { + // FIXME: Update offset? // Not touching this... return; } let dl = cx.data_layout(); + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *offset += dl.pointer_size(); + return; + } let size = arg.layout.size; let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); @@ -36,8 +43,9 @@ where *offset = offset.align_to(align) + size.align_to(align); } -pub(crate) fn compute_abi_info(cx: &C, fn_abi: &mut FnAbi<'_, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { let mut offset = Size::ZERO; diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 62c8ed1dc21b1..911eaaf08f825 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -140,6 +140,10 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index a308f378ee871..5be8cd5d88f26 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs @@ -52,6 +52,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } arg.extend_integer_width_to(32); if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) { arg.make_indirect(); diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 918b71c80c4f0..93dc60dc1593e 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -64,6 +64,11 @@ where continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } + let t = cx.target_spec(); let align_4 = Align::from_bytes(4).unwrap(); let align_16 = Align::from_bytes(16).unwrap(); diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index d8db7ed6e4c0f..04eecbfbc8dd6 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -183,9 +183,15 @@ where let mut x86_64_arg_or_ret = |arg: &mut ArgAbi<'a, Ty>, is_arg: bool| { if !arg.layout.is_sized() { + // FIXME: Update int_regs? // Not touching this... return; } + if is_arg && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + int_regs = int_regs.saturating_sub(1); + arg.make_indirect(); + return; + } let mut cls_or_mem = classify_arg(cx, arg); if is_arg { diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs index 554a7368848b5..824e7cc098a46 100644 --- a/compiler/rustc_target/src/callconv/x86_win32.rs +++ b/compiler/rustc_target/src/callconv/x86_win32.rs @@ -46,6 +46,11 @@ pub(crate) fn compute_abi_info<'a, Ty, C>( continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 // See https://reviews.llvm.org/D72114 for Clang behavior diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 8f8597ea662a8..85ee59eabc7c4 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,11 +1,14 @@ -use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size}; +use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg}; use crate::spec::{HasTargetSpec, RustcAbi}; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing -pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| { match a.layout.backend_repr { BackendRepr::Memory { sized: false } => {} @@ -59,6 +62,10 @@ pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<' arg.make_indirect_from_ignore(); continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } fixup(arg, false); } // FIXME: We should likely also do something about ZST return types, similar to above. diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index 561ee98787dee..4dc9fad650636 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -15,7 +15,7 @@ const NUM_RET_GPRS: u64 = 4; const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32; const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32; -fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>) +fn classify_ret_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, { @@ -26,7 +26,7 @@ where // The rules for return and argument types are the same, // so defer to `classify_arg_ty`. let mut arg_gprs_left = NUM_RET_GPRS; - classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE); + classify_arg_ty(cx, arg, &mut arg_gprs_left, true); // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisible reference match arg.mode { super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => { @@ -36,12 +36,24 @@ where } } -fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64) -where +fn classify_arg_ty<'a, Ty, C>( + cx: &C, + arg: &mut ArgAbi<'a, Ty>, + arg_gprs_left: &mut u64, + is_ret: bool, +) where Ty: TyAbiInterface<'a, C> + Copy, { assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow"); + let max_size = if is_ret { MAX_RET_IN_REGS_SIZE } else { MAX_ARG_IN_REGS_SIZE }; + + if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + *arg_gprs_left = arg_gprs_left.saturating_sub(1); + arg.make_indirect(); + return; + } + // Ignore empty structs/unions. if arg.layout.is_zst() { return; @@ -95,13 +107,13 @@ where } } -pub(crate) fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { if !fn_abi.ret.is_ignore() { - classify_ret_ty(&mut fn_abi.ret); + classify_ret_ty(cx, &mut fn_abi.ret); } let mut arg_gprs_left = NUM_ARG_GPRS; @@ -110,7 +122,7 @@ where if arg.is_ignore() { continue; } - classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE); + classify_arg_ty(cx, arg, &mut arg_gprs_left, false); } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 8c6a77cba8ba7..f664bbb874d67 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,9 +9,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(debug_closure_helpers))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(debug_closure_helpers)] #![feature(iter_intersperse)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0f09e548f0e2b..f98f161e80938 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::iter; use rustc_abi::Primitive::Pointer; @@ -388,6 +389,12 @@ fn fn_abi_sanity_check<'tcx>( if let PassMode::Indirect { on_stack, .. } = arg.mode { assert!(!on_stack, "rust abi shouldn't use on_stack"); } + } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + assert_matches!( + arg.mode, + PassMode::Indirect { on_stack: false, .. }, + "the {spec_abi} ABI does not implement `#[rustc_pass_indirectly_in_non_rustic_abis]`" + ); } match &arg.mode { diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 82eaf7d87244d..4d6fe220a09ad 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -602,7 +602,7 @@ pub use core::fmt::{DebugAsHex, FormattingOptions, Sign}; pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Formatter, Result, Write}; -#[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] pub use core::fmt::{FromFn, from_fn}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{LowerExp, UpperExp}; diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 46ccf330d1c22..3c9587d383e30 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -299,3 +299,15 @@ impl<'f> Drop for VaListImpl<'f> { // This works for now, since `va_end` is a no-op on all current LLVM targets. } } + +// Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current +// target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`. +const _: () = { + #[repr(C)] + #[rustc_pass_indirectly_in_non_rustic_abis] + struct Type(usize); + + const extern "C" fn c(_: Type) {} + + c(Type(0)) +}; diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 665b05b12ec07..4ea6c6ba8fb9c 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -1210,13 +1210,12 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { } } -/// Creates a type whose [`fmt::Debug`] and [`fmt::Display`] impls are provided with the function -/// `f`. +/// Creates a type whose [`fmt::Debug`] and [`fmt::Display`] impls are +/// forwarded to the provided closure. /// /// # Examples /// /// ``` -/// #![feature(debug_closure_helpers)] /// use std::fmt; /// /// let value = 'a'; @@ -1227,21 +1226,19 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// assert_eq!(format!("{}", wrapped), "'a'"); /// assert_eq!(format!("{:?}", wrapped), "'a'"); /// ``` -#[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] #[must_use = "returns a type implementing Debug and Display, which do not have any effects unless they are used"] pub fn from_fn) -> fmt::Result>(f: F) -> FromFn { FromFn(f) } -/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function. +/// Implements [`fmt::Debug`] and [`fmt::Display`] via the provided closure. /// /// Created with [`from_fn`]. -#[unstable(feature = "debug_closure_helpers", issue = "117729")] -pub struct FromFn(F) -where - F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result; +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] +pub struct FromFn(F); -#[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for FromFn where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result, @@ -1251,7 +1248,7 @@ where } } -#[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] impl fmt::Display for FromFn where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0f255e57fe585..502ca4aefe10d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -39,7 +39,7 @@ pub use num_buffer::{NumBuffer, NumBufferTrait}; #[stable(feature = "debug_builders", since = "1.2.0")] pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; -#[unstable(feature = "debug_closure_helpers", issue = "117729")] +#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")] pub use self::builders::{FromFn, from_fn}; /// The type returned by formatter methods. diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 97eb9ec7dc5b0..c22a9da0385b5 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -584,6 +584,28 @@ impl Waker { pub fn vtable(&self) -> &'static RawWakerVTable { self.waker.vtable } + + /// Constructs a `Waker` from a function pointer. + #[inline] + #[must_use] + #[unstable(feature = "waker_from_fn_ptr", issue = "148457")] + pub const fn from_fn_ptr(f: fn()) -> Self { + // SAFETY: Unsafe is used for transmutes, pointer came from `fn()` so it + // is sound to transmute it back to `fn()`. + static VTABLE: RawWakerVTable = unsafe { + RawWakerVTable::new( + |this| RawWaker::new(this, &VTABLE), + |this| transmute::<*const (), fn()>(this)(), + |this| transmute::<*const (), fn()>(this)(), + |_| {}, + ) + }; + let raw = RawWaker::new(f as *const (), &VTABLE); + + // SAFETY: `clone` is just a copy, `drop` is a no-op while `wake` and + // `wake_by_ref` just call the function pointer. + unsafe { Self::from_raw(raw) } + } } #[stable(feature = "futures_api", since = "1.36.0")] @@ -879,6 +901,28 @@ impl LocalWaker { pub fn vtable(&self) -> &'static RawWakerVTable { self.waker.vtable } + + /// Constructs a `LocalWaker` from a function pointer. + #[inline] + #[must_use] + #[unstable(feature = "waker_from_fn_ptr", issue = "148457")] + pub const fn from_fn_ptr(f: fn()) -> Self { + // SAFETY: Unsafe is used for transmutes, pointer came from `fn()` so it + // is sound to transmute it back to `fn()`. + static VTABLE: RawWakerVTable = unsafe { + RawWakerVTable::new( + |this| RawWaker::new(this, &VTABLE), + |this| transmute::<*const (), fn()>(this)(), + |this| transmute::<*const (), fn()>(this)(), + |_| {}, + ) + }; + let raw = RawWaker::new(f as *const (), &VTABLE); + + // SAFETY: `clone` is just a copy, `drop` is a no-op while `wake` and + // `wake_by_ref` just call the function pointer. + unsafe { Self::from_raw(raw) } + } } #[unstable(feature = "local_waker", issue = "118959")] impl Clone for LocalWaker { diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 004f6d413a1f3..d76e3e576f330 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -82,12 +82,11 @@ impl TcpStream { } pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result { - // FIXME: UEFI does support vectored write, so implement that. - crate::io::default_write_vectored(|b| self.write(b), buf) + self.inner.write_vectored(buf, self.write_timeout()?) } pub fn is_write_vectored(&self) -> bool { - false + true } pub fn peer_addr(&self) -> io::Result { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index aac97007bbfe5..16283e64fb35a 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -1,5 +1,5 @@ use super::tcp4; -use crate::io; +use crate::io::{self, IoSlice}; use crate::net::SocketAddr; use crate::ptr::NonNull; use crate::sys::{helpers, unsupported}; @@ -28,6 +28,16 @@ impl Tcp { } } + pub(crate) fn write_vectored( + &self, + buf: &[IoSlice<'_>], + timeout: Option, + ) -> io::Result { + match self { + Self::V4(client) => client.write_vectored(buf, timeout), + } + } + pub(crate) fn read(&self, buf: &mut [u8], timeout: Option) -> io::Result { match self { Self::V4(client) => client.read(buf, timeout), diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index 75862ff247b4f..ba0424454d738 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -1,7 +1,7 @@ use r_efi::efi::{self, Status}; use r_efi::protocols::tcp4; -use crate::io; +use crate::io::{self, IoSlice}; use crate::net::SocketAddrV4; use crate::ptr::NonNull; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -108,11 +108,7 @@ impl Tcp4 { } pub(crate) fn write(&self, buf: &[u8], timeout: Option) -> io::Result { - let evt = unsafe { self.create_evt() }?; - let completion_token = - tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); - let fragment = tcp4::FragmentData { fragment_length: data_len, fragment_buffer: buf.as_ptr().cast::().cast_mut(), @@ -125,14 +121,63 @@ impl Tcp4 { fragment_table: [fragment], }; - let protocol = self.protocol.as_ptr(); - let mut token = tcp4::IoToken { - completion_token, - packet: tcp4::IoTokenPacket { - tx_data: (&raw mut tx_data).cast::>(), - }, + self.write_inner((&raw mut tx_data).cast(), timeout).map(|_| data_len as usize) + } + + pub(crate) fn write_vectored( + &self, + buf: &[IoSlice<'_>], + timeout: Option, + ) -> io::Result { + let mut data_length = 0u32; + let mut fragment_count = 0u32; + + // Calculate how many IoSlice in buf can be transmitted. + for i in buf { + // IoSlice length is always <= u32::MAX in UEFI. + match data_length + .checked_add(u32::try_from(i.as_slice().len()).expect("value is stored as a u32")) + { + Some(x) => data_length = x, + None => break, + } + fragment_count += 1; + } + + let tx_data_size = size_of::>() + + size_of::() * (fragment_count as usize); + let mut tx_data = helpers::UefiBox::::new(tx_data_size)?; + tx_data.write(tcp4::TransmitData { + push: r_efi::efi::Boolean::FALSE, + urgent: r_efi::efi::Boolean::FALSE, + data_length, + fragment_count, + fragment_table: [], + }); + unsafe { + // SAFETY: IoSlice and FragmentData are guaranteed to have same layout. + crate::ptr::copy_nonoverlapping( + buf.as_ptr().cast(), + (*tx_data.as_mut_ptr()).fragment_table.as_mut_ptr(), + fragment_count as usize, + ); }; + self.write_inner(tx_data.as_mut_ptr(), timeout).map(|_| data_length as usize) + } + + fn write_inner( + &self, + tx_data: *mut tcp4::TransmitData, + timeout: Option, + ) -> io::Result<()> { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { completion_token, packet: tcp4::IoTokenPacket { tx_data } }; + let r = unsafe { ((*protocol).transmit)(protocol, &mut token) }; if r.is_error() { return Err(io::Error::from_raw_os_error(r.as_usize())); @@ -143,7 +188,7 @@ impl Tcp4 { if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) } else { - Ok(data_len as usize) + Ok(()) } } diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index c0d69c3e0029a..852e0d6b051bd 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -12,6 +12,7 @@ use r_efi::efi::{self, Guid}; use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell}; +use crate::alloc::Layout; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; use crate::marker::PhantomData; @@ -769,3 +770,39 @@ pub(crate) const fn ipv4_to_r_efi(addr: crate::net::Ipv4Addr) -> efi::Ipv4Addres pub(crate) const fn ipv4_from_r_efi(ip: efi::Ipv4Address) -> crate::net::Ipv4Addr { crate::net::Ipv4Addr::new(ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]) } + +/// This type is intended for use with ZSTs. Since such types are unsized, a reference to such types +/// is not valid in Rust. Thus, only pointers should be used when interacting with such types. +pub(crate) struct UefiBox { + inner: NonNull, + size: usize, +} + +impl UefiBox { + pub(crate) fn new(len: usize) -> io::Result { + assert!(len >= size_of::()); + // UEFI always expects types to be 8 byte aligned. + let layout = Layout::from_size_align(len, 8).unwrap(); + let ptr = unsafe { crate::alloc::alloc(layout) }; + + match NonNull::new(ptr.cast()) { + Some(inner) => Ok(Self { inner, size: len }), + None => Err(io::Error::new(io::ErrorKind::OutOfMemory, "Allocation failed")), + } + } + + pub(crate) fn write(&mut self, data: T) { + unsafe { self.inner.write(data) } + } + + pub(crate) fn as_mut_ptr(&mut self) -> *mut T { + self.inner.as_ptr().cast() + } +} + +impl Drop for UefiBox { + fn drop(&mut self) { + let layout = Layout::from_size_align(self.size, 8).unwrap(); + unsafe { crate::alloc::dealloc(self.inner.as_ptr().cast(), layout) }; + } +} diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index b7d7151b171d5..e7f86e10f55a5 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,8 @@ set -euo pipefail -LINUX_VERSION=v6.17-rc5 +# https://github.com/rust-lang/rust/pull/145974 +LINUX_VERSION=842cfd8e5aff3157cb25481b2900b49c188d628a # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/doc/book b/src/doc/book index af415fc6c8a68..f660f341887c8 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit af415fc6c8a6823dfb4595074f27d5a3e9e2fe49 +Subproject commit f660f341887c8bbcd6c24fbfdf5d2a262f523965 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index e2ed891f00361..5c621253d8f2a 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit e2ed891f00361efc26616d82590b1c85d7a8920e +Subproject commit 5c621253d8f2a5a4adb64a6365905db67dffe3a2 diff --git a/src/doc/reference b/src/doc/reference index 752eab01cebdd..e122eefff3fef 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 752eab01cebdd6a2d90b53087298844c251859a1 +Subproject commit e122eefff3fef362eb7e0c08fb7ffbf5f9461905 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 2c9b490d70e53..160e6bbca70b0 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 2c9b490d70e535cf166bf17feba59e594579843f +Subproject commit 160e6bbca70b0c01aa4de88d19db7fc5ff8447c3 diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index f2cf1d447aa5a..f0f991ed0c909 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -209,6 +209,27 @@ Note that while the `-C instrument-coverage` option is stable, the profile data format produced by the resulting instrumentation may change, and may not work with coverage tools other than those built and shipped with the compiler. +## jump-tables + +This option is used to allow or prevent the LLVM codegen backend from creating +jump tables when lowering switches from Rust code. + +* `y`, `yes`, `on`, `true` or no value: allow jump tables (the default). +* `n`, `no`, `off` or `false`: disable jump tables. + +To prevent jump tables being created from Rust code, a target must ensure +all crates are compiled with jump tables disabled. + +Note, in many cases the Rust toolchain is distributed with precompiled +crates, such as the core and std crates, which could possibly include +jump tables. Furthermore, this option does not guarantee a target will +be free of jump tables. They could arise from external dependencies, +inline asm, or other complicated interactions when using crates which +are compiled with jump table support. + +Disabling jump tables can be used to help provide protection against +jump-oriented-programming (JOP) attacks. + ## link-arg This flag lets you append a single extra argument to the linker invocation. diff --git a/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md deleted file mode 100644 index f096c20f4bd54..0000000000000 --- a/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md +++ /dev/null @@ -1,19 +0,0 @@ -# `no-jump-tables` - -The tracking issue for this feature is [#116592](https://github.com/rust-lang/rust/issues/116592) - ---- - -This option enables the `-fno-jump-tables` flag for LLVM, which makes the -codegen backend avoid generating jump tables when lowering switches. - -This option adds the LLVM `no-jump-tables=true` attribute to every function. - -The option can be used to help provide protection against -jump-oriented-programming (JOP) attacks, such as with the linux kernel's [IBT]. - -```sh -RUSTFLAGS="-Zno-jump-tables" cargo +nightly build -Z build-std -``` - -[IBT]: https://www.phoronix.com/news/Linux-IBT-By-Default-Tip diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 31860884c6d3e..24087c4c4f580 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(debug_closure_helpers))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/" @@ -8,7 +9,6 @@ #![feature(assert_matches)] #![feature(box_into_inner)] #![feature(box_patterns)] -#![feature(debug_closure_helpers)] #![feature(file_buffered)] #![feature(formatting_options)] #![feature(if_let_guard)] diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 44bf9611064ae..1474df146f9ce 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -190,6 +190,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-aarch64", "only-aarch64-apple-darwin", "only-aarch64-unknown-linux-gnu", + "only-aarch64-unknown-uefi", "only-apple", "only-arm", "only-arm64ec", diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index dfca2cda9a0f8..f03dde6257d76 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -68,14 +68,20 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/std/src/io/error.rs", // Repr unpacked needed for UEFI ]; -pub fn check(path: &Path, tidy_ctx: TidyCtx) { - let mut check = tidy_ctx.start_check(CheckId::new("pal").path(path)); +pub fn check(library_path: &Path, tidy_ctx: TidyCtx) { + let mut check = tidy_ctx.start_check(CheckId::new("pal").path(library_path)); + + let root_path = library_path.parent().unwrap(); + // Let's double-check that this is the root path by making sure it has `x.py`. + assert!(root_path.join("x.py").is_file()); // Sanity check that the complex parsing here works. let mut saw_target_arch = false; let mut saw_cfg_bang = false; - walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| { + walk(library_path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| { let file = entry.path(); + // We don't want the absolute path to matter, so make it relative. + let file = file.strip_prefix(root_path).unwrap(); let filestr = file.to_string_lossy().replace("\\", "/"); if !filestr.ends_with(".rs") { return; diff --git a/tests/assembly-llvm/x86_64-no-jump-tables.rs b/tests/assembly-llvm/x86_64-no-jump-tables.rs index bb10042d8f629..e469aee7ed945 100644 --- a/tests/assembly-llvm/x86_64-no-jump-tables.rs +++ b/tests/assembly-llvm/x86_64-no-jump-tables.rs @@ -1,10 +1,10 @@ -// Test that jump tables are (not) emitted when the `-Zno-jump-tables` +// Test that jump tables are (not) emitted when the `-Cjump-tables=no` // flag is (not) set. //@ revisions: unset set //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 -//@ [set] compile-flags: -Zno-jump-tables +//@ [set] compile-flags: -Cjump-tables=no //@ only-x86_64 //@ ignore-sgx diff --git a/tests/codegen-llvm/no-jump-tables.rs b/tests/codegen-llvm/no-jump-tables.rs index 8f607e38350de..ff79c43dfc9c6 100644 --- a/tests/codegen-llvm/no-jump-tables.rs +++ b/tests/codegen-llvm/no-jump-tables.rs @@ -1,11 +1,12 @@ // Test that the `no-jump-tables` function attribute are (not) emitted when -// the `-Zno-jump-tables` flag is (not) set. +// the `-Cjump-tables=no` flag is (not) set. //@ add-minicore -//@ revisions: unset set +//@ revisions: unset set_no set_yes //@ needs-llvm-components: x86 //@ compile-flags: --target x86_64-unknown-linux-gnu -//@ [set] compile-flags: -Zno-jump-tables +//@ [set_no] compile-flags: -Cjump-tables=no +//@ [set_yes] compile-flags: -Cjump-tables=yes #![crate_type = "lib"] #![feature(no_core, lang_items)] @@ -19,5 +20,6 @@ pub fn foo() { // CHECK: @foo() unnamed_addr #0 // unset-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } - // set: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } + // set_yes-NOT: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } + // set_no: attributes #0 = { {{.*}}"no-jump-tables"="true"{{.*}} } } diff --git a/tests/ui/abi/pass-indirectly-attr.rs b/tests/ui/abi/pass-indirectly-attr.rs new file mode 100644 index 0000000000000..79d6629f9eb44 --- /dev/null +++ b/tests/ui/abi/pass-indirectly-attr.rs @@ -0,0 +1,38 @@ +//@ add-core-stubs +//@ check-fail +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" +//@ ignore-backends: gcc + +#![feature(rustc_attrs)] +#![crate_type = "lib"] +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +#[rustc_pass_indirectly_in_non_rustic_abis] +pub struct Type(u8); + +#[rustc_abi(debug)] +pub extern "C" fn extern_c(_: Type) {} +//~^ ERROR fn_abi_of(extern_c) = FnAbi { +//~| ERROR mode: Indirect +//~| ERROR on_stack: false, +//~| ERROR conv: C, + +#[rustc_abi(debug)] +pub extern "Rust" fn extern_rust(_: Type) {} +//~^ ERROR fn_abi_of(extern_rust) = FnAbi { +//~| ERROR mode: Cast +//~| ERROR conv: Rust + +#[repr(transparent)] +struct Inner(u64); + +#[rustc_pass_indirectly_in_non_rustic_abis] +//~^ ERROR transparent struct cannot have other repr hints +#[repr(transparent)] +struct Wrapper(Inner); diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr new file mode 100644 index 0000000000000..a93982dacfa1b --- /dev/null +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -0,0 +1,194 @@ +error[E0692]: transparent struct cannot have other repr hints + --> $DIR/pass-indirectly-attr.rs:35:1 + | +LL | #[rustc_pass_indirectly_in_non_rustic_abis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct Wrapper(Inner); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(extern_c) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: Type, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: CapturesAddress | NoAlias | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(1 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-indirectly-attr.rs:20:1 + | +LL | pub extern "C" fn extern_c(_: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(extern_rust) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: Type, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Cast { + pad_i32: false, + cast: CastTarget { + prefix: [ + None, + None, + None, + None, + None, + None, + None, + None, + ], + rest_offset: None, + rest: Uniform { + unit: Reg { + kind: Integer, + size: Size(1 bytes), + }, + total: Size(1 bytes), + is_consecutive: false, + }, + attrs: ArgAttributes { + regular: , + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + }, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: false, + } + --> $DIR/pass-indirectly-attr.rs:27:1 + | +LL | pub extern "Rust" fn extern_rust(_: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0692`. diff --git a/tests/ui/asm/hexagon-register-pairs.rs b/tests/ui/asm/hexagon-register-pairs.rs new file mode 100644 index 0000000000000..f0f77738ac835 --- /dev/null +++ b/tests/ui/asm/hexagon-register-pairs.rs @@ -0,0 +1,35 @@ +//@ add-core-stubs +//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b +//@ needs-llvm-components: hexagon +//@ ignore-backends: gcc + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn test_register_spans() { + unsafe { + // These are valid Hexagon register span notations, not labels + // Should NOT trigger the named labels lint + + // General register pairs + asm!("r1:0 = memd(r29+#0)", lateout("r0") _, lateout("r1") _); + asm!("r3:2 = combine(#1, #0)", lateout("r2") _, lateout("r3") _); + asm!("r15:14 = memd(r30+#8)", lateout("r14") _, lateout("r15") _); + asm!("memd(r29+#0) = r5:4", in("r4") 0u32, in("r5") 0u32); + + // These patterns look like register spans but test different edge cases + // All should NOT trigger the lint as they match valid hexagon register syntax patterns + asm!("V5:4 = vaddw(v1:0, v1:0)", options(nostack)); // Uppercase V register pair + asm!("v1:0.w = vsub(v1:0.w,v1:0.w):sat", options(nostack)); // Lowercase v with suffix + + // Mixed with actual labels should still trigger for the labels + asm!("label1: r7:6 = combine(#2, #3)"); //~ ERROR avoid using named labels + + // Regular labels should still trigger + asm!("hexagon_label: nop"); //~ ERROR avoid using named labels + } +} diff --git a/tests/ui/asm/hexagon-register-pairs.stderr b/tests/ui/asm/hexagon-register-pairs.stderr new file mode 100644 index 0000000000000..6de55c34a8bc2 --- /dev/null +++ b/tests/ui/asm/hexagon-register-pairs.stderr @@ -0,0 +1,21 @@ +error: avoid using named labels in inline assembly + --> $DIR/hexagon-register-pairs.rs:30:15 + | +LL | asm!("label1: r7:6 = combine(#2, #3)"); + | ^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + = note: `#[deny(named_asm_labels)]` on by default + +error: avoid using named labels in inline assembly + --> $DIR/hexagon-register-pairs.rs:33:15 + | +LL | asm!("hexagon_label: nop"); + | ^^^^^^^^^^^^^ + | + = help: only local labels of the form `:` should be used in inline asm + = note: see the asm section of Rust By Example for more information + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 95f314214cc65..dd0f4da5dd32b 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -25,6 +25,8 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F LL | fn needs_async_fn(_: impl AsyncFn()) {} | -------------- change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = 1; + | ----- `x` declared here, outside the closure LL | needs_async_fn(async || { | -------------- ^^^^^^^^ | | | diff --git a/tests/ui/attributes/pass-indirectly.rs b/tests/ui/attributes/pass-indirectly.rs new file mode 100644 index 0000000000000..0eacffbf01fbe --- /dev/null +++ b/tests/ui/attributes/pass-indirectly.rs @@ -0,0 +1,15 @@ +//@ check-fail + +#![feature(rustc_attrs)] +#![crate_type = "lib"] + +#[rustc_pass_indirectly_in_non_rustic_abis] +//~^ ERROR: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions +fn not_a_struct() {} + +#[repr(C)] +#[rustc_pass_indirectly_in_non_rustic_abis] +struct YesAStruct { + foo: u8, + bar: u16, +} diff --git a/tests/ui/attributes/pass-indirectly.stderr b/tests/ui/attributes/pass-indirectly.stderr new file mode 100644 index 0000000000000..2011f3d928f69 --- /dev/null +++ b/tests/ui/attributes/pass-indirectly.stderr @@ -0,0 +1,10 @@ +error: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions + --> $DIR/pass-indirectly.rs:6:1 + | +LL | #[rustc_pass_indirectly_in_non_rustic_abis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_pass_indirectly_in_non_rustic_abis]` can only be applied to structs + +error: aborting due to 1 previous error + diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr index a0eaf1f163b02..4e40ebf738e3b 100644 --- a/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -4,6 +4,8 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closu LL | fn to_fn>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = 0; + | ----- `x` declared here, outside the closure LL | let _f = to_fn(|| x = 42); | ----- -- ^^^^^^ cannot assign | | | @@ -16,6 +18,8 @@ error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `F LL | fn to_fn>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut y = 0; + | ----- `y` declared here, outside the closure LL | let _g = to_fn(|| set(&mut y)); | ----- -- ^^^^^^ cannot borrow as mutable | | | @@ -28,6 +32,9 @@ error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closu LL | fn to_fn>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut z = 0; + | ----- `z` declared here, outside the closure +... LL | to_fn(|| z = 42); | ----- -- ^^^^^^ cannot assign | | | diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr index f81a8c99376f0..c4b97950727ac 100644 --- a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr +++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -40,6 +40,8 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F LL | fn make_fn(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = 0; + | ----- `x` declared here, outside the closure LL | let f = make_fn(|| { | ------- -- in this closure | | diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr index 3cab3ccb993c9..7307e1f2a86b2 100644 --- a/tests/ui/borrowck/mutability-errors.stderr +++ b/tests/ui/borrowck/mutability-errors.stderr @@ -139,7 +139,9 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closu | LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` -... +LL | +LL | fn ref_closure(mut x: (i32,)) { + | ----- `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | @@ -152,7 +154,9 @@ error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captu | LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` -... +LL | +LL | fn ref_closure(mut x: (i32,)) { + | ----- `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | @@ -166,7 +170,9 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F | LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` -... +LL | +LL | fn ref_closure(mut x: (i32,)) { + | ----- `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | @@ -180,7 +186,9 @@ error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate the | LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` -... +LL | +LL | fn ref_closure(mut x: (i32,)) { + | ----- `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | diff --git a/tests/ui/closures/aliasability-violation-with-closure-21600.stderr b/tests/ui/closures/aliasability-violation-with-closure-21600.stderr index 2d2397a2141d9..2f4135b12fa5a 100644 --- a/tests/ui/closures/aliasability-violation-with-closure-21600.stderr +++ b/tests/ui/closures/aliasability-violation-with-closure-21600.stderr @@ -4,6 +4,9 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F LL | fn call_it(f: F) where F: Fn() { f(); } | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = A; + | ----- `x` declared here, outside the closure +... LL | call_it(|| x.gen_mut()); | ------- -- ^ cannot borrow as mutable | | | @@ -16,6 +19,8 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F LL | fn call_it(f: F) where F: Fn() { f(); } | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = A; + | ----- `x` declared here, outside the closure LL | call_it(|| { | ------- -- in this closure | | diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr index e0cce8c4b3143..f419f7c1b44d3 100644 --- a/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr @@ -4,6 +4,8 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closu LL | fn assoc_func(&self, _f: impl Fn()) -> usize { | --------- change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = (); + | ----- `x` declared here, outside the closure LL | s.assoc_func(|| x = ()); | --------------^^^^^^- | | | | @@ -17,6 +19,9 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closu LL | fn func(_f: impl Fn()) -> usize { | --------- change this to accept `FnMut` instead of `Fn` ... +LL | let mut x = (); + | ----- `x` declared here, outside the closure +... LL | func(|| x = ()) | ---- -- ^^^^^^ cannot assign | | | diff --git a/tests/ui/nll/closure-captures.stderr b/tests/ui/nll/closure-captures.stderr index 828974c517e60..80ac033351aaa 100644 --- a/tests/ui/nll/closure-captures.stderr +++ b/tests/ui/nll/closure-captures.stderr @@ -47,7 +47,9 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F | LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` -... +LL | +LL | fn two_closures_ref_mut(mut x: i32) { + | ----- `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | @@ -89,6 +91,8 @@ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `F LL | fn fn_ref(f: F) -> F { f } | - change this to accept `FnMut` instead of `Fn` ... +LL | fn two_closures_ref(x: i32) { + | - `x` declared here, outside the closure LL | fn_ref(|| { | ------ -- in this closure | | diff --git a/tests/ui/stack-probes/aarch64-unknown-uefi-chkstk-98254.rs b/tests/ui/stack-probes/aarch64-unknown-uefi-chkstk-98254.rs new file mode 100644 index 0000000000000..36273d5a5e3f0 --- /dev/null +++ b/tests/ui/stack-probes/aarch64-unknown-uefi-chkstk-98254.rs @@ -0,0 +1,16 @@ +//! Regression test for #98254, missing `__chkstk` symbol on `aarch64-unknown-uefi`. +//@ build-pass +//@ only-aarch64-unknown-uefi +//@ compile-flags: -Cpanic=abort +//@ compile-flags: -Clinker=rust-lld +#![no_std] +#![no_main] +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[export_name = "efi_main"] +fn main() { + let b = [0; 1024]; +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr index cbe42861d5ee2..f82faeea516f8 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -4,6 +4,8 @@ error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` LL | fn call(f: F) where F : Fn() { | - change this to accept `FnMut` instead of `Fn` ... +LL | let mut counter = 0; + | ----------- `counter` declared here, outside the closure LL | call(|| { | ---- -- in this closure | |