Updated code for changes to RFC, added additional error handling, added
tests
This commit is contained in:
parent
9b0ae75ecc
commit
7c56398e91
18 changed files with 312 additions and 79 deletions
|
@ -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),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -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)
|
||||||
),
|
),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 = { {{.*}} }
|
|
|
@ -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{{.*}} }
|
|
@ -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{{.*}} }
|
|
@ -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{{.*}} }
|
|
@ -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() {}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
//@ compile-flags: -Z patchable-function-entry=1,2
|
||||||
|
fn main() {}
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue