Updated code for changes to RFC, added additional error handling, added

tests
This commit is contained in:
Florian Schmiderer 2024-05-02 23:19:02 +02:00
parent 9b0ae75ecc
commit 7c56398e91
18 changed files with 312 additions and 79 deletions

View file

@ -1,5 +1,6 @@
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::packed::Pu128;
use rustc_errors::{codes::*, struct_span_code_err}; use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
@ -467,24 +468,55 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
} }
sym::patchable_function_entry => { sym::patchable_function_entry => {
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
let mut prefix = 0; let mut prefix = None;
let mut entry = 0; let mut entry = None;
for item in l { for item in l {
if let Some((sym, lit)) = item.name_value_literal() { let Some(meta_item) = item.meta_item() else {
let val = match lit.kind { tcx.dcx().span_err(item.span(), "Expected name value pair.");
// FIXME emit error if too many nops requested continue;
rustc_ast::LitKind::Int(i, _) => i as u8, };
_ => continue,
}; let Some(name_value_lit) = meta_item.name_value_literal() else {
match sym { tcx.dcx().span_err(item.span(), "Expected name value pair.");
sym::prefix => prefix = val, continue;
sym::entry => entry = val, };
// FIXME possibly emit error here?
_ => continue, let attrib_to_write = match meta_item.name_or_empty() {
sym::prefix_nops => &mut prefix,
sym::entry_nops => &mut entry,
_ => {
tcx.dcx().span_err(
item.span(),
format!(
"Unexpected parameter name. Allowed names: {}, {}",
sym::prefix_nops,
sym::entry_nops
),
);
continue;
} }
} };
let rustc_ast::LitKind::Int(Pu128(val @ 0..=255), _) = name_value_lit.kind
else {
tcx.dcx().span_err(
name_value_lit.span,
"Expected integer value between 0 and 255.",
);
continue;
};
*attrib_to_write = Some(val.try_into().unwrap());
} }
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix, entry))
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),
))
}) })
} }
_ => {} _ => {}

View file

@ -584,12 +584,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
pointee, Normal, template!(Word), ErrorFollowing, pointee, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee) EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee)
), ),
// FIXME RFC // RFC 3543
// `#[patchable_function_entry(prefix(n), entry(n))]` // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
gated!( gated!(
patchable_function_entry, Normal, template!(List: "prefix(n), entry(n)"), ErrorPreceding, patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding,
experimental!(patchable_function_entry) EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
), ),
// ========================================================================== // ==========================================================================

View file

@ -566,8 +566,7 @@ declare_features! (
/// Allows using `#[optimize(X)]`. /// Allows using `#[optimize(X)]`.
(unstable, optimize_attribute, "1.34.0", Some(54882)), (unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows specifying nop padding on functions for dynamic patching. /// Allows specifying nop padding on functions for dynamic patching.
// FIXME this needs an RFC # (unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(123115)),
(unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(9999)),
/// Allows postfix match `expr.match { ... }` /// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "1.79.0", Some(121618)), (unstable, postfix_match, "1.79.0", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.

View file

@ -8,8 +8,8 @@ use rustc_session::config::{
ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold,
Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail,
LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey,
PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip,
SymbolManglingVersion, WasiExecModel, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
}; };
use rustc_session::lint::Level; use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath; use rustc_session::search_paths::SearchPath;
@ -813,7 +813,10 @@ fn test_unstable_options_tracking_hash() {
tracked!(packed_bundled_libs, true); tracked!(packed_bundled_libs, true);
tracked!(panic_abort_tests, true); tracked!(panic_abort_tests, true);
tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(panic_in_drop, PanicStrategy::Abort);
tracked!(patchable_function_entry, PatchableFunctionEntry::from_nop_count_and_offset(3, 4)); tracked!(
patchable_function_entry,
PatchableFunctionEntry::from_total_and_prefix_nops(10, 5).expect("total >= prefix")
);
tracked!(plt, Some(true)); tracked!(plt, Some(true));
tracked!(polonius, Polonius::Legacy); tracked!(polonius, Polonius::Legacy);
tracked!(precise_enum_drop_elaboration, false); tracked!(precise_enum_drop_elaboration, false);

View file

@ -2963,8 +2963,9 @@ pub(crate) mod dep_tracking {
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn,
InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks,
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
WasiExecModel,
}; };
use crate::lint; use crate::lint;
use crate::utils::NativeLib; use crate::utils::NativeLib;
@ -3260,11 +3261,14 @@ pub struct PatchableFunctionEntry {
} }
impl PatchableFunctionEntry { impl PatchableFunctionEntry {
pub fn from_nop_count_and_offset(nop_count: u8, offset: u8) -> Option<PatchableFunctionEntry> { pub fn from_total_and_prefix_nops(
if nop_count < offset { total_nops: u8,
prefix_nops: u8,
) -> Option<PatchableFunctionEntry> {
if total_nops < prefix_nops {
None None
} else { } else {
Some(Self { prefix: offset, entry: nop_count - offset }) Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
} }
} }
pub fn prefix(&self) -> u8 { pub fn prefix(&self) -> u8 {

View file

@ -379,8 +379,7 @@ mod desc {
pub const parse_passes: &str = "a space-separated list of passes, or `all`"; 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_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
pub const parse_patchable_function_entry: &str = 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)";
"nop_count,entry_offset or nop_count (defaulting entry_offset=0)";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_oom_strategy: &str = "either `panic` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
@ -725,7 +724,6 @@ mod parse {
true true
} }
pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool { pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
match v { match v {
// OnBrokenPipe::Default can't be explicitly specified // OnBrokenPipe::Default can't be explicitly specified
@ -741,20 +739,22 @@ mod parse {
slot: &mut PatchableFunctionEntry, slot: &mut PatchableFunctionEntry,
v: Option<&str>, v: Option<&str>,
) -> bool { ) -> bool {
let mut nop_count = 0; let mut total_nops = 0;
let mut offset = 0; let mut prefix_nops = 0;
if !parse_number(&mut nop_count, v) { if !parse_number(&mut total_nops, v) {
let parts = v.and_then(|v| v.split_once(',')).unzip(); let parts = v.and_then(|v| v.split_once(',')).unzip();
if !parse_number(&mut nop_count, parts.0) { if !parse_number(&mut total_nops, parts.0) {
return false; return false;
} }
if !parse_number(&mut offset, parts.1) { if !parse_number(&mut prefix_nops, parts.1) {
return false; return false;
} }
} }
if let Some(pfe) = PatchableFunctionEntry::from_nop_count_and_offset(nop_count, offset) { if let Some(pfe) =
PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops)
{
*slot = pfe; *slot = pfe;
return true; return true;
} }

View file

@ -768,7 +768,7 @@ symbols! {
enable, enable,
encode, encode,
end, end,
entry, entry_nops,
enumerate_method, enumerate_method,
env, env,
env_CFG_RELEASE: env!("CFG_RELEASE"), env_CFG_RELEASE: env!("CFG_RELEASE"),
@ -1423,7 +1423,7 @@ symbols! {
prefetch_read_instruction, prefetch_read_instruction,
prefetch_write_data, prefetch_write_data,
prefetch_write_instruction, prefetch_write_instruction,
prefix, prefix_nops,
preg, preg,
prelude, prelude,
prelude_import, prelude_import,

View file

@ -2,14 +2,14 @@
-------------------- --------------------
The `-Z patchable-function-entry=M,N` or `-Z patchable-function-entry=M` The `-Z patchable-function-entry=total_nops,prefix_nops` or `-Z patchable-function-entry=total_nops`
compiler flag enables nop padding of function entries with M nops, with compiler flag enables nop padding of function entries with 'total_nops' nops, with
an offset for the entry of the function at N nops. In the second form, an offset for the entry of the function at 'prefix_nops' nops. In the second form,
N defaults to 0. 'prefix_nops' defaults to 0.
As an illustrative example, `-Z patchable-function-entry=3,2` would produce: As an illustrative example, `-Z patchable-function-entry=3,2` would produce:
``` ```text
nop nop
nop nop
function_label: function_label:
@ -18,7 +18,7 @@ nop
``` ```
This flag is used for hotpatching, especially in the Linux kernel. The flag This flag is used for hotpatching, especially in the Linux kernel. The flag
arguments are modeled after hte `-fpatchable-function-entry` flag as defined arguments are modeled after the `-fpatchable-function-entry` flag as defined
for both [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fpatchable-function-entry) for both [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fpatchable-function-entry)
and [gcc](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fpatchable-function-entry) and [gcc](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fpatchable-function-entry)
and is intended to provide the same effect. and is intended to provide the same effect.

View file

@ -1,28 +0,0 @@
#![feature(patchable_function_entry)]
// compile-flags: -Z patchable-function-entry=15,10
#![crate_type = "lib"]
// This should have the default, as set by the compile flags
#[no_mangle]
pub fn foo() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix(1), entry(2))]
pub fn bar() {}
// If we override an attribute to 0 or unset, the attribute should go away
#[no_mangle]
#[patchable_function_entry(entry(0))]
pub fn baz() {}
// CHECK: @foo() unnamed_addr #0
// CHECK: @bar() unnamed_addr #1
// CHECK: @baz() unnamed_addr #2
// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} }
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #2 = { {{.*}} }

View file

@ -0,0 +1,64 @@
//@ compile-flags: -Z patchable-function-entry=15,10
#![feature(patchable_function_entry)]
#![crate_type = "lib"]
// This should have the default, as set by the compile flags
#[no_mangle]
pub fn fun0() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
pub fn fun1() {}
// If we override an attribute to 0 or unset, the attribute should go away
#[no_mangle]
#[patchable_function_entry(entry_nops = 0)]
pub fn fun2() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)]
pub fn fun3() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)]
pub fn fun4() {}
// The attribute should override patchable-function-entry to 3 and
// patchable-function-prefix to the default of 0, clearing it entirely
#[no_mangle]
#[patchable_function_entry(entry_nops = 3)]
pub fn fun5() {}
// The attribute should override patchable-function-prefix to 4
// and patchable-function-entry to the default of 0, clearing it entirely
#[no_mangle]
#[patchable_function_entry(prefix_nops = 4)]
pub fn fun6() {}
// CHECK: @fun0() unnamed_addr #0
// CHECK: @fun1() unnamed_addr #1
// CHECK: @fun2() unnamed_addr #2
// CHECK: @fun3() unnamed_addr #3
// CHECK: @fun4() unnamed_addr #4
// CHECK: @fun5() unnamed_addr #5
// CHECK: @fun6() unnamed_addr #6
// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} }
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #2 = { {{.*}} }
// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} }
// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} }
// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} }

View file

@ -0,0 +1,39 @@
#![feature(patchable_function_entry)]
#![crate_type = "lib"]
// No patchable function entry should be set
#[no_mangle]
pub fn fun0() {}
// The attribute should work even without compiler flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
pub fn fun1() {}
// The attribute should work even without compiler flags
// and only set patchable-function-entry to 3.
#[no_mangle]
#[patchable_function_entry(entry_nops = 3)]
pub fn fun2() {}
// The attribute should work even without compiler flags
// and only set patchable-function-prefix to 4.
#[no_mangle]
#[patchable_function_entry(prefix_nops = 4)]
pub fn fun3() {}
// CHECK: @fun0() unnamed_addr #0
// CHECK: @fun1() unnamed_addr #1
// CHECK: @fun2() unnamed_addr #2
// CHECK: @fun3() unnamed_addr #3
// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-entry{{.*}} }
// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
// CHECK: attributes #2 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #3 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
// CHECK-NOT: attributes #3 = { {{.*}}patchable-function-entry{{.*}} }

View file

@ -0,0 +1,66 @@
//@ compile-flags: -Z patchable-function-entry=15
#![feature(patchable_function_entry)]
#![crate_type = "lib"]
// This should have the default, as set by the compile flags
#[no_mangle]
pub fn fun0() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 1, entry_nops = 2)]
pub fn fun1() {}
// If we override an attribute to 0 or unset, the attribute should go away
#[no_mangle]
#[patchable_function_entry(entry_nops = 0)]
pub fn fun2() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 20, entry_nops = 1)]
pub fn fun3() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix_nops = 2, entry_nops = 19)]
pub fn fun4() {}
// The attribute should override patchable-function-entry to 3
// and patchable-function-prefix to the default of 0, clearing it entirely
#[no_mangle]
#[patchable_function_entry(entry_nops = 3)]
pub fn fun5() {}
// The attribute should override patchable-function-prefix to 4
// and patchable-function-entry to the default of 0, clearing it entirely
#[no_mangle]
#[patchable_function_entry(prefix_nops = 4)]
pub fn fun6() {}
// CHECK: @fun0() unnamed_addr #0
// CHECK: @fun1() unnamed_addr #1
// CHECK: @fun2() unnamed_addr #2
// CHECK: @fun3() unnamed_addr #3
// CHECK: @fun4() unnamed_addr #4
// CHECK: @fun5() unnamed_addr #5
// CHECK: @fun6() unnamed_addr #6
// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="15" {{.*}} }
// CHECK-NOT: attributes #0 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #2 = { {{.*}} }
// CHECK: attributes #3 = { {{.*}}"patchable-function-entry"="1"{{.*}}"patchable-function-prefix"="20" {{.*}} }
// CHECK: attributes #4 = { {{.*}}"patchable-function-entry"="19"{{.*}}"patchable-function-prefix"="2" {{.*}} }
// CHECK: attributes #5 = { {{.*}}"patchable-function-entry"="3"{{.*}} }
// CHECK-NOT: attributes #5 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #6 = { {{.*}}"patchable-function-prefix"="4"{{.*}} }
// CHECK-NOT: attributes #6 = { {{.*}}patchable-function-entry{{.*}} }

View file

@ -1,3 +1,3 @@
#[patchable_function_entry(entry(1), prefix(1))] #[patchable_function_entry(prefix_nops = 1, entry_nops = 1)]
//~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature //~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature
fn main() {} fn main() {}

View file

@ -1,11 +1,12 @@
error[E0658]: the `#[patchable_function_entry]` attribute is an experimental feature error[E0658]: the `#[patchable_function_entry]` attribute is an experimental feature
--> $DIR/feature-gate-patchable-function-entry.rs:1:1 --> $DIR/feature-gate-patchable-function-entry.rs:1:1
| |
LL | #[patchable_function_entry(entry(1), prefix(1))] LL | #[patchable_function_entry(prefix_nops = 1, entry_nops = 1)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: see issue #9999 <https://github.com/rust-lang/rust/issues/9999> for more information = note: see issue #123115 <https://github.com/rust-lang/rust/issues/123115> for more information
= help: add `#![feature(patchable_function_entry)]` to the crate attributes to enable = help: add `#![feature(patchable_function_entry)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -0,0 +1,17 @@
#![feature(patchable_function_entry)]
fn main() {}
#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)]//~error: Expected integer value between 0 and 255.
pub fn too_high_pnops() {}
#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)]//~error: Expected integer value between 0 and 255.
pub fn non_int_nop() {}
#[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. Allowed names: prefix_nops, entry_nops
pub fn unexpected_parameter_name() {}
#[patchable_function_entry()]//~error: Must specify at least one parameter.
pub fn no_parameters_given() {}

View file

@ -0,0 +1,32 @@
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: Expected integer value between 0 and 255.
--> $DIR/patchable-function-entry-attribute.rs:4:42
|
LL | #[patchable_function_entry(prefix_nops = 256, entry_nops = 0)]
| ^^^
error: Expected integer value between 0 and 255.
--> $DIR/patchable-function-entry-attribute.rs:7:42
|
LL | #[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)]
| ^^^^^^^^^^^^^
error: Unexpected parameter name. Allowed names: prefix_nops, entry_nops
--> $DIR/patchable-function-entry-attribute.rs:13:46
|
LL | #[patchable_function_entry(prefix_nops = 10, something = 0)]
| ^^^^^^^^^^^^^
error: Must specify at least one parameter.
--> $DIR/patchable-function-entry-attribute.rs:16:1
|
LL | #[patchable_function_entry()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors

View file

@ -0,0 +1,2 @@
//@ compile-flags: -Z patchable-function-entry=1,2
fn main() {}

View file

@ -0,0 +1,2 @@
error: incorrect value `1,2` for unstable option `patchable-function-entry` - either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops) was expected