diff options
| author | bors <bors@rust-lang.org> | 2024-06-28 07:25:28 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-06-28 07:25:28 +0000 |
| commit | 99f77a2eda555b50b518f74823ab636a20efb87f (patch) | |
| tree | 8dd11cc66cae04d768306ccb8e6c7e625e25104d /compiler | |
| parent | 42add88d2275b95c98e512ab680436ede691e853 (diff) | |
| parent | 89a0cfe72afe047c699df3810e1ce5e4d9cb98b4 (diff) | |
| download | rust-99f77a2eda555b50b518f74823ab636a20efb87f.tar.gz rust-99f77a2eda555b50b518f74823ab636a20efb87f.zip | |
Auto merge of #127076 - matthiaskrgr:rollup-l01gm36, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #124741 (patchable-function-entry: Add unstable compiler flag and attribute) - #126470 (make cargo submodule optional) - #126956 (core: avoid `extern type`s in formatting infrastructure) - #126970 (Simplify `str::clone_into`) - #127022 (Support fetching `Attribute` of items.) - #127058 (Tighten `fn_decl_span` for async blocks) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
22 files changed, 331 insertions, 25 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4a3ce0e0c30..f5e79c04d78 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1454,7 +1454,10 @@ pub enum ExprKind { Block(P<Block>, Option<Label>), /// An `async` block (`async move { ... }`), /// or a `gen` block (`gen move { ... }`) - Gen(CaptureBy, P<Block>, GenBlockKind), + /// + /// The span is the "decl", which is the header before the body `{ }` + /// including the `asyng`/`gen` keywords and possibly `move`. + Gen(CaptureBy, P<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P<Expr>, Span), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a81c335aa23..27e781a5a63 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1528,8 +1528,9 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(label, |label| vis.visit_label(label)); vis.visit_block(blk); } - ExprKind::Gen(_capture_by, body, _kind) => { + ExprKind::Gen(_capture_by, body, _kind, decl_span) => { vis.visit_block(body); + vis.visit_span(decl_span); } ExprKind::Await(expr, await_kw_span) => { vis.visit_expr(expr); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0f3c30048ce..26cb04d4d47 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1122,7 +1122,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V visit_opt!(visitor, visit_label, opt_label); try_visit!(visitor.visit_block(block)); } - ExprKind::Gen(_capt, body, _kind) => try_visit!(visitor.visit_block(body)), + ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 79cff0fbcd2..624bca525b9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -227,7 +227,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), }, - ExprKind::Gen(capture_clause, block, genblock_kind) => { + ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { GenBlockKind::Async => hir::CoroutineDesugaring::Async, GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, @@ -237,6 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *capture_clause, e.id, None, + *decl_span, e.span, desugaring_kind, hir::CoroutineSource::Block, @@ -616,6 +617,7 @@ impl<'hir> LoweringContext<'_, 'hir> { capture_clause: CaptureBy, closure_node_id: NodeId, return_ty: Option<hir::FnRetTy<'hir>>, + fn_decl_span: Span, span: Span, desugaring_kind: hir::CoroutineDesugaring, coroutine_source: hir::CoroutineSource, @@ -692,7 +694,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params: &[], fn_decl, body, - fn_decl_span: self.lower_span(span), + fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: None, kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, @@ -1083,6 +1085,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( &inner_decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Closure, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4c7e8c24d32..74e04eff4f3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -211,6 +211,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // declaration (decl), not the return types. let coroutine_kind = header.coroutine_kind; let body_id = this.lower_maybe_coroutine_body( + *fn_sig_span, span, hir_id, decl, @@ -799,6 +800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -915,6 +917,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -1111,6 +1114,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `gen {}` block as appropriate. fn lower_maybe_coroutine_body( &mut self, + fn_decl_span: Span, span: Span, fn_id: hir::HirId, decl: &FnDecl, @@ -1124,6 +1128,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, |this| this.lower_block_expr(body), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Fn, @@ -1145,6 +1150,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, decl: &FnDecl, lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + fn_decl_span: Span, body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, @@ -1315,13 +1321,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); - let span = if let FnRetTy::Default(span) = decl.output - && matches!(coroutine_source, rustc_hir::CoroutineSource::Closure) - { - body_span.with_lo(span.lo()) - } else { - body_span - }; let coroutine_expr = self.make_desugared_coroutine_expr( // The default capture mode here is by-ref. Later on during upvar analysis, // we will force the captured arguments to by-move, but for async closures, @@ -1330,7 +1329,8 @@ impl<'hir> LoweringContext<'_, 'hir> { CaptureBy::Ref, closure_id, None, - span, + fn_decl_span, + body_span, desugaring_kind, coroutine_source, mkbody, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f2f6594e686..3d1f43a3766 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -540,7 +540,7 @@ impl<'a> State<'a> { self.ibox(0); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::Gen(capture_clause, blk, kind) => { + ast::ExprKind::Gen(capture_clause, blk, kind, _decl_span) => { self.word_nbsp(kind.modifier()); self.print_capture_clause(*capture_clause); // cbox/ibox in analogy to the `ExprKind::Block` arm above diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a98cb6f0f76..c664891dad5 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -298,7 +298,7 @@ impl<'cx, 'a> Context<'cx, 'a> { // sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test. ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 48693895da1..cd82894af18 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; @@ -53,6 +53,34 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll } } +#[inline] +fn patchable_function_entry_attrs<'ll>( + cx: &CodegenCx<'ll, '_>, + attr: Option<PatchableFunctionEntry>, +) -> SmallVec<[&'ll Attribute; 2]> { + let mut attrs = SmallVec::new(); + let patchable_spec = attr.unwrap_or_else(|| { + PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry) + }); + let entry = patchable_spec.entry(); + let prefix = patchable_spec.prefix(); + if entry > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-entry", + &format!("{}", entry), + )); + } + if prefix > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-prefix", + &format!("{}", prefix), + )); + } + attrs +} + /// Get LLVM sanitize attributes. #[inline] pub fn sanitize_attrs<'ll>( @@ -421,6 +449,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( llvm::set_alignment(llfn, align); } to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d224695d1f2..56a893738df 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,11 +1,13 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::{codes::*, struct_span_code_err}; +use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::{ + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, +}; use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; @@ -447,6 +449,80 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { None }; } + sym::patchable_function_entry => { + codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { + let mut prefix = None; + let mut entry = None; + for item in l { + let Some(meta_item) = item.meta_item() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + let Some(name_value_lit) = meta_item.name_value_literal() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + fn emit_error_with_label( + tcx: TyCtxt<'_>, + span: Span, + error: impl Into<DiagMessage>, + label: impl Into<SubdiagMessage>, + ) { + let mut err: rustc_errors::Diag<'_, _> = + tcx.dcx().struct_span_err(span, error); + err.span_label(span, label); + err.emit(); + } + + let attrib_to_write = match meta_item.name_or_empty() { + sym::prefix_nops => &mut prefix, + sym::entry_nops => &mut entry, + _ => { + emit_error_with_label( + tcx, + item.span(), + "unexpected parameter name", + format!("expected {} or {}", sym::prefix_nops, sym::entry_nops), + ); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { + emit_error_with_label( + tcx, + name_value_lit.span, + "invalid literal value", + "value must be an integer between `0` and `255`", + ); + continue; + }; + + let Ok(val) = val.get().try_into() else { + emit_error_with_label( + tcx, + name_value_lit.span, + "integer value out of range", + "value must be between `0` and `255`", + ); + continue; + }; + + *attrib_to_write = Some(val); + } + + if let (None, None) = (prefix, entry) { + tcx.dcx().span_err(attr.span, "must specify at least one parameter"); + } + + Some(PatchableFunctionEntry::from_prefix_and_entry( + prefix.unwrap_or(0), + entry.unwrap_or(0), + )) + }) + } _ => {} } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 32a047a9363..f884f996927 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -585,6 +585,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee) ), + // RFC 3543 + // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + gated!( + patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding, + EncodeCrossCrate::Yes, experimental!(patchable_function_entry) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f4e20328814..ad6f7da8937 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -563,6 +563,8 @@ declare_features! ( (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), + /// Allows specifying nop padding on functions for dynamic patching. + (unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(123115)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6ffc518097e..02322c9b282 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,8 +8,8 @@ use rustc_session::config::{ ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, - PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, - SymbolManglingVersion, WasiExecModel, + PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, + SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -813,6 +813,11 @@ fn test_unstable_options_tracking_hash() { tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); + tracked!( + patchable_function_entry, + PatchableFunctionEntry::from_total_and_prefix_nops(10, 5) + .expect("total must be greater than or equal to prefix") + ); tracked!(plt, Some(true)); tracked!(polonius, Polonius::Legacy); tracked!(precise_enum_drop_elaboration, false); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index c8f0d0795a3..3ddf889b63a 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -45,6 +45,32 @@ pub struct CodegenFnAttrs { /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be /// aligned to. pub alignment: Option<Align>, + /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around + /// the function entry. + pub patchable_function_entry: Option<PatchableFunctionEntry>, +} + +#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct PatchableFunctionEntry { + /// Nops to prepend to the function + prefix: u8, + /// Nops after entry, but before body + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self { + Self { prefix: config.prefix(), entry: config.entry() } + } + pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self { + Self { prefix, entry } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } } #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] @@ -121,6 +147,7 @@ impl CodegenFnAttrs { no_sanitize: SanitizerSet::empty(), instruction_set: None, alignment: None, + patchable_function_entry: None, } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0c70884fee..3cdc20b6c65 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3432,8 +3432,9 @@ impl<'a> Parser<'a> { } } let capture_clause = self.parse_capture_clause()?; + let decl_span = lo.to(self.prev_token.span); let (attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ExprKind::Gen(capture_clause, body, kind); + let kind = ExprKind::Gen(capture_clause, body, kind, decl_span); Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } @@ -4022,7 +4023,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Match(_, _, _) | ExprKind::Closure(_) | ExprKind::Block(_, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::TryBlock(_) | ExprKind::Underscore | ExprKind::Path(_, _) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1bca5602a4e..80619c59cc3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -334,7 +334,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { None => closure_def, } } - ExprKind::Gen(_, _, _) => { + ExprKind::Gen(_, _, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2d38ad37133..41c99f7edee 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2965,8 +2965,9 @@ pub(crate) mod dep_tracking { CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, - SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, + SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -3073,6 +3074,7 @@ pub(crate) mod dep_tracking { OomStrategy, LanguageIdentifier, NextSolverConfig, + PatchableFunctionEntry, Polonius, InliningThreshold, FunctionReturn, @@ -3250,6 +3252,35 @@ impl DumpMonoStatsFormat { } } +/// `-Z patchable-function-entry` representation - how many nops to put before and after function +/// entry. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub struct PatchableFunctionEntry { + /// Nops before the entry + prefix: u8, + /// Nops after the entry + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_total_and_prefix_nops( + total_nops: u8, + prefix_nops: u8, + ) -> Option<PatchableFunctionEntry> { + if total_nops < prefix_nops { + None + } else { + Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops }) + } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } +} + /// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy, /// or future prototype. #[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a10adeb6d1..80f7ca544f3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -379,6 +379,7 @@ mod desc { pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; + pub const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; @@ -734,6 +735,32 @@ mod parse { true } + pub(crate) fn parse_patchable_function_entry( + slot: &mut PatchableFunctionEntry, + v: Option<&str>, + ) -> bool { + let mut total_nops = 0; + let mut prefix_nops = 0; + + if !parse_number(&mut total_nops, v) { + let parts = v.and_then(|v| v.split_once(',')).unzip(); + if !parse_number(&mut total_nops, parts.0) { + return false; + } + if !parse_number(&mut prefix_nops, parts.1) { + return false; + } + } + + if let Some(pfe) = + PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops) + { + *slot = pfe; + return true; + } + false + } + pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool { match v { Some("panic") => *slot = OomStrategy::Panic, @@ -1859,6 +1886,8 @@ options! { "panic strategy for panics in drops"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link (default: no)"), + patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED], + "nop padding at function entry"), plt: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 1e0a60bc371..1230667ee91 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index dde5e30c3d0..e23f4289e98 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -228,6 +228,46 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } + fn get_attrs_by_path( + &self, + def_id: stable_mir::DefId, + attr: &[stable_mir::Symbol], + ) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let attr_name: Vec<_> = + attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect(); + tcx.get_attrs_by_path(did, &attr_name) + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + + fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let filter_fn = move |a: &&rustc_ast::ast::Attribute| { + matches!(a.kind, rustc_ast::ast::AttrKind::Normal(_)) + }; + let attrs_iter = if let Some(did) = did.as_local() { + tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + } else { + tcx.item_attrs(did).iter().filter(filter_fn) + }; + attrs_iter + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + fn span_to_string(&self, span: stable_mir::ty::Span) -> String { let tables = self.0.borrow(); tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6d4a8c29bc9..3b6147c4c0f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -768,6 +768,7 @@ symbols! { enable, encode, end, + entry_nops, enumerate_method, env, env_CFG_RELEASE: env!("CFG_RELEASE"), @@ -1383,6 +1384,7 @@ symbols! { passes, pat, pat_param, + patchable_function_entry, path, pattern_complexity, pattern_parentheses, @@ -1421,6 +1423,7 @@ symbols! { prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction, + prefix_nops, preg, prelude, prelude_import, diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 44dbf549c1a..5f2d9b96c73 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; +use crate::crate_def::Attribute; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::{BinOp, Body, Place, UnOp}; @@ -55,6 +56,15 @@ pub trait Context { /// Returns the name of given `DefId` fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>; + + /// Get all attributes of a definition. + fn get_all_attrs(&self, def_id: DefId) -> Vec<Attribute>; + /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 67752a5e629..d9b987c28a2 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -50,6 +50,21 @@ pub trait CrateDef { let def_id = self.def_id(); with(|cx| cx.span_of_an_item(def_id)) } + + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn attrs_by_path(&self, attr: &[Symbol]) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_attrs_by_path(def_id, attr)) + } + + /// Return all attributes of this definition. + fn all_attrs(&self) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_all_attrs(def_id)) + } } /// A trait that can be used to retrieve a definition's type. @@ -69,6 +84,28 @@ pub trait CrateDefType: CrateDef { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Attribute { + value: String, + span: Span, +} + +impl Attribute { + pub fn new(value: String, span: Span) -> Attribute { + Attribute { value, span } + } + + /// Get the span of this attribute. + pub fn span(&self) -> Span { + self.span + } + + /// Get the string representation of this attribute. + pub fn as_str(&self) -> &str { + &self.value + } +} + macro_rules! crate_def { ( $(#[$attr:meta])* $vis:vis $name:ident $(;)? |
