diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 5bbaeda18df3..063fa12d3896 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -717,3 +717,100 @@ impl NoArgsAttributeParser for EiiForeignItemParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem; } + +pub(crate) struct PatchableFunctionEntryParser; + +impl SingleAttributeParser for PatchableFunctionEntryParser { + const PATH: &[Symbol] = &[sym::patchable_function_entry]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(meta_item_list) = args.list() else { + cx.expected_list(cx.attr_span, args); + return None; + }; + + let mut prefix = None; + let mut entry = None; + + if meta_item_list.len() == 0 { + cx.expected_list(meta_item_list.span, args); + return None; + } + + let mut errored = false; + + for item in meta_item_list.mixed() { + let Some(meta_item) = item.meta_item() else { + errored = true; + cx.expected_name_value(item.span(), None); + continue; + }; + + let Some(name_value_lit) = meta_item.args().name_value() else { + errored = true; + cx.expected_name_value(item.span(), None); + continue; + }; + + let attrib_to_write = match meta_item.ident().map(|ident| ident.name) { + Some(sym::prefix_nops) => { + // Duplicate prefixes are not allowed + if prefix.is_some() { + errored = true; + cx.duplicate_key(meta_item.path().span(), sym::prefix_nops); + continue; + } + &mut prefix + } + Some(sym::entry_nops) => { + // Duplicate entries are not allowed + if entry.is_some() { + errored = true; + cx.duplicate_key(meta_item.path().span(), sym::entry_nops); + continue; + } + &mut entry + } + _ => { + errored = true; + cx.expected_specific_argument( + meta_item.path().span(), + &[sym::prefix_nops, sym::entry_nops], + ); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else { + errored = true; + cx.expected_integer_literal(name_value_lit.value_span); + continue; + }; + + let Ok(val) = val.get().try_into() else { + errored = true; + cx.expected_integer_literal_in_range( + name_value_lit.value_span, + u8::MIN as isize, + u8::MAX as isize, + ); + continue; + }; + + *attrib_to_write = Some(val); + } + + if errored { + None + } else { + Some(AttributeKind::PatchableFunctionEntry { + prefix: prefix.unwrap_or(0), + entry: entry.unwrap_or(0), + }) + } + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0c882fee01c8..7bcc1f3448e5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -23,8 +23,8 @@ use crate::attributes::cfi_encoding::CfiEncodingParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, - RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, - ThreadLocalParser, TrackCallerParser, UsedParser, + PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, + TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ @@ -223,6 +223,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, @@ -504,6 +505,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral) } + pub(crate) fn expected_integer_literal_in_range( + &self, + span: Span, + lower_bound: isize, + upper_bound: isize, + ) -> ErrorGuaranteed { + self.emit_parse_error( + span, + AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound }, + ) + } + pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed { let span = match args { ArgParser::NoArgs => span, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 85e7891b1e64..f9748542beb9 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -525,6 +525,10 @@ pub(crate) enum AttributeParseErrorReason<'a> { byte_string: Option, }, ExpectedIntegerLiteral, + ExpectedIntegerLiteralInRange { + lower_bound: isize, + upper_bound: isize, + }, ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, @@ -596,6 +600,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedIntegerLiteral => { diag.span_label(self.span, "expected an integer literal here"); } + AttributeParseErrorReason::ExpectedIntegerLiteralInRange { + lower_bound, + upper_bound, + } => { + diag.span_label( + self.span, + format!( + "expected an integer literal in the range of {lower_bound}..={upper_bound}" + ), + ); + } AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 4875f309cca5..a49f411a7df6 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -48,8 +48,6 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err codegen_ssa_error_writing_def_file = error writing .DEF file: {$error} -codegen_ssa_expected_name_value_pair = expected name value pair - codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} @@ -90,9 +88,6 @@ codegen_ssa_incorrect_cgu_reuse_type = codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. -codegen_ssa_invalid_literal_value = invalid literal value - .label = value must be an integer between `0` and `255` - codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}` @@ -225,9 +220,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't -codegen_ssa_out_of_range_integer = integer value out of range - .label = value must be between `0` and `255` - codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} .note = {$output} @@ -357,9 +349,6 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} codegen_ssa_unable_to_write_debugger_visualizer = unable to write debugger visualizer file `{$path}`: {$error} -codegen_ssa_unexpected_parameter_name = unexpected parameter name - .label = expected `{$prefix_nops}` or `{$entry_nops}` - codegen_ssa_unknown_archive_kind = don't know how to build archive of type: {$kind} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e35d884b6711..296c96ce4ae6 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -47,59 +47,6 @@ fn try_fn_sig<'tcx>( } } -// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr -fn parse_patchable_function_entry( - tcx: TyCtxt<'_>, - attr: &Attribute, -) -> Option { - 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().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let Some(name_value_lit) = meta_item.name_value_literal() else { - tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let attrib_to_write = match meta_item.name() { - Some(sym::prefix_nops) => &mut prefix, - Some(sym::entry_nops) => &mut entry, - _ => { - tcx.dcx().emit_err(errors::UnexpectedParameterName { - span: item.span(), - prefix_nops: sym::prefix_nops, - entry_nops: sym::entry_nops, - }); - continue; - } - }; - - let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { - tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span }); - continue; - }; - - let Ok(val) = val.get().try_into() else { - tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span }); - 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))) - }) -} - /// Spans that are collected when processing built-in attributes, /// that are useful for emitting diagnostics later. #[derive(Default)] @@ -353,6 +300,10 @@ fn process_builtin_attrs( AttributeKind::RustcOffloadKernel => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL } + AttributeKind::PatchableFunctionEntry { prefix, entry } => { + codegen_fn_attrs.patchable_function_entry = + Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry)); + } _ => {} } } @@ -362,10 +313,6 @@ fn process_builtin_attrs( }; match name { - sym::patchable_function_entry => { - codegen_fn_attrs.patchable_function_entry = - parse_patchable_function_entry(tcx, attr); - } _ => {} } } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 39727685aec1..6a97de4c2b13 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -136,39 +136,6 @@ pub(crate) struct RequiresRustAbi { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_name_value_pair)] -pub(crate) struct ExpectedNameValuePair { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unexpected_parameter_name)] -pub(crate) struct UnexpectedParameterName { - #[primary_span] - #[label] - pub span: Span, - pub prefix_nops: Symbol, - pub entry_nops: Symbol, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_literal_value)] -pub(crate) struct InvalidLiteralValue { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_out_of_range_integer)] -pub(crate) struct OutOfRangeInteger { - #[primary_span] - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_copy_path_buf)] pub(crate) struct CopyPathBuf { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 314f36d6132d..6e84d60f062f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -879,6 +879,9 @@ pub enum AttributeKind { /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint). PassByValue(Span), + /// Represents `#[patchable_function_entry]` + PatchableFunctionEntry { prefix: u8, entry: u8 }, + /// Represents `#[path]` Path(Symbol, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index b55a5d0e29e1..1c13cef64fea 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -88,6 +88,7 @@ impl AttributeKind { Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, + PatchableFunctionEntry { .. } => Yes, Path(..) => No, PatternComplexityLimit { .. } => No, PinV2(..) => Yes, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 806f5c4d3ed9..c2ad644688fc 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -171,7 +171,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); -print_disp!(u16, u128, usize, bool, NonZero, Limit); +print_disp!(u8, u16, u128, usize, bool, NonZero, Limit); print_debug!( Symbol, Ident, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8074ae429892..3ddf51f6c9b1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -324,6 +324,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcReallocator | AttributeKind::RustcNounwind | AttributeKind::RustcOffloadKernel + | AttributeKind::PatchableFunctionEntry { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -349,7 +350,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::deny | sym::forbid // need to be fixed - | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) // internal | sym::prelude_import diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 3d51731df792..f817a0b0d91b 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -26,12 +26,6 @@ error[E0463]: can't find crate for `wloop` LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate -error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:114:1 - | -LL | #[patchable_function_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:184:1 | @@ -444,6 +438,15 @@ LL | #[instruction_set] | = note: for more information, visit +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/malformed-attrs.rs:114:1 + | +LL | #[patchable_function_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + error[E0565]: malformed `coroutine` attribute input --> $DIR/malformed-attrs.rs:117:5 | diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs index 1e376c9ff3c1..5cbeccf1b0e4 100644 --- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs @@ -1,17 +1,26 @@ #![feature(patchable_function_entry)] fn main() {} -#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)]//~error: integer value out of range +#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)] +//~^ ERROR malformed pub fn too_high_pnops() {} -#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)]//~error: invalid literal value +#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)] +//~^ ERROR malformed pub fn non_int_nop() {} -#[patchable_function_entry]//~error: malformed `patchable_function_entry` attribute input +#[patchable_function_entry] +//~^ ERROR malformed `patchable_function_entry` attribute input pub fn malformed_attribute() {} -#[patchable_function_entry(prefix_nops = 10, something = 0)]//~error: unexpected parameter name +#[patchable_function_entry(prefix_nops = 10, something = 0)] +//~^ ERROR malformed pub fn unexpected_parameter_name() {} -#[patchable_function_entry()]//~error: must specify at least one parameter +#[patchable_function_entry()] +//~^ ERROR malformed pub fn no_parameters_given() {} + +#[patchable_function_entry(prefix_nops = 255, prefix_nops = 255)] +//~^ ERROR malformed +pub fn duplicate_parameter() {} diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr index 9357a86c4153..43fc0c0518af 100644 --- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr @@ -1,32 +1,58 @@ -error: malformed `patchable_function_entry` attribute input - --> $DIR/patchable-function-entry-attribute.rs:10:1 - | -LL | #[patchable_function_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` - -error: integer value out of range - --> $DIR/patchable-function-entry-attribute.rs:4:42 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:4:1 | LL | #[patchable_function_entry(prefix_nops = 256, entry_nops = 0)] - | ^^^ value must be between `0` and `255` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^^^^^^^^^^^^^^^^ + | | | + | | expected an integer literal in the range of 0..=255 + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: invalid literal value - --> $DIR/patchable-function-entry-attribute.rs:7:42 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:8:1 | LL | #[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)] - | ^^^^^^^^^^^^^ value must be an integer between `0` and `255` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^^^^^^^^^^^^^^^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: unexpected parameter name - --> $DIR/patchable-function-entry-attribute.rs:13:46 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:12:1 | -LL | #[patchable_function_entry(prefix_nops = 10, something = 0)] - | ^^^^^^^^^^^^^ expected `prefix_nops` or `entry_nops` +LL | #[patchable_function_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: must specify at least one parameter +error[E0539]: malformed `patchable_function_entry` attribute input --> $DIR/patchable-function-entry-attribute.rs:16:1 | +LL | #[patchable_function_entry(prefix_nops = 10, something = 0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^ + | | | + | | valid arguments are `prefix_nops` or `entry_nops` + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:20:1 + | LL | #[patchable_function_entry()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^--^ + | | | + | | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: aborting due to 5 previous errors +error[E0538]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:24:1 + | +LL | #[patchable_function_entry(prefix_nops = 255, prefix_nops = 255)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^ + | | | + | | found `prefix_nops` used as a key more than once + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0538, E0539. +For more information about an error, try `rustc --explain E0538`.