Skip to content

Commit 8d603ef

Browse files
committed
Auto merge of #147231 - CrooseGit:dev/reucru01/extend_rustc_force_inline, r=saethlin
Extending `#[rustc_force_inline]` to be applicable to inherent methods `#[rustc_force_inline]` is an internal-only attribute similar to `#[inline(always)]` but which emits an error if inlining cannot occur. rustc_force_inline uses the MIR inliner to do this and has limitations on where it can be applied to ensure that an error is always emitted if inlining can't happen (e.g. it can't be applied to trait methods because calls to those can't always be resolved). `#[rustc_force_inline]` is motivated by AArch64 pointer authentication intrinsics where it is vital for the security properties of these intrinsics that they do not exist in standalone functions that could be used as gadgets in an exploit (if they could, then you could sign whatever pointers you want, for example, which is bad, but if you force inlining, then you can't jump to a reusable function containing only these instructions). Since its initial implementation, `#[rustc_force_inline]` could only be applied to free functions. This can be relaxed to also allow inherent methods while still preserving the desired properties. In a work-in-progress patch for manual pointer authentication intrinsics, it is useful to introduce types with inherent methods that would need to be force inlined. r? `@saethlin`
2 parents 5c7ae0c + 5bf5e71 commit 8d603ef

20 files changed

+346
-25
lines changed

compiler/rustc_attr_parsing/src/attributes/inline.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
7272
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
7373
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
7474
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
75-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
75+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
76+
Allow(Target::Fn),
77+
Allow(Target::Method(MethodKind::Inherent)),
78+
]);
79+
7680
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
7781

7882
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller::{closure#0}` before ForceInline
2+
+ // MIR for `caller::{closure#0}` after ForceInline
3+
4+
fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () {
5+
let mut _0: ();
6+
let _2: ();
7+
+ scope 1 (inlined Foo::callee_forced) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_2);
12+
- _2 = Foo::callee_forced() -> [return: bb1, unwind unreachable];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_2);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller::{closure#0}` before ForceInline
2+
+ // MIR for `caller::{closure#0}` after ForceInline
3+
4+
fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () {
5+
let mut _0: ();
6+
let _2: ();
7+
+ scope 1 (inlined Foo::callee_forced) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_2);
12+
- _2 = Foo::callee_forced() -> [return: bb1, unwind continue];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_2);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
2+
//@ compile-flags: -Copt-level=0 --crate-type=lib
3+
#![feature(rustc_attrs)]
4+
5+
struct Foo {}
6+
7+
impl Foo {
8+
#[rustc_force_inline]
9+
pub fn callee_forced() {}
10+
}
11+
12+
// EMIT_MIR forced_closure_inherent.caller-{closure#0}.ForceInline.diff
13+
pub fn caller() {
14+
(|| {
15+
Foo::callee_forced();
16+
// CHECK-LABEL: fn caller::{closure#0}(
17+
// CHECK: (inlined Foo::callee_forced)
18+
})();
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller` before ForceInline
2+
+ // MIR for `caller` after ForceInline
3+
4+
fn caller() -> () {
5+
let mut _0: ();
6+
let _1: ();
7+
+ scope 1 (inlined Foo::bar) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_1);
12+
- _1 = Foo::bar() -> [return: bb1, unwind unreachable];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_1);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller` before ForceInline
2+
+ // MIR for `caller` after ForceInline
3+
4+
fn caller() -> () {
5+
let mut _0: ();
6+
let _1: ();
7+
+ scope 1 (inlined Foo::bar) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_1);
12+
- _1 = Foo::bar() -> [return: bb1, unwind continue];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_1);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
2+
//@ compile-flags: -Copt-level=0 --crate-type=lib
3+
#![feature(rustc_attrs)]
4+
5+
struct Foo;
6+
7+
impl Foo {
8+
#[rustc_force_inline]
9+
fn bar() {}
10+
}
11+
12+
// EMIT_MIR forced_inherent.caller.ForceInline.diff
13+
fn caller() {
14+
Foo::bar();
15+
// CHECK-LABEL: fn caller(
16+
// CHECK: (inlined Foo::bar)
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller` before ForceInline
2+
+ // MIR for `caller` after ForceInline
3+
4+
fn caller() -> () {
5+
let mut _0: ();
6+
let _1: ();
7+
+ scope 1 (inlined Foo::bar) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_1);
12+
- _1 = Foo::bar() -> [return: bb1, unwind unreachable];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_1);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `caller` before ForceInline
2+
+ // MIR for `caller` after ForceInline
3+
4+
fn caller() -> () {
5+
let mut _0: ();
6+
let _1: ();
7+
+ scope 1 (inlined Foo::bar) {
8+
+ }
9+
10+
bb0: {
11+
StorageLive(_1);
12+
- _1 = Foo::bar() -> [return: bb1, unwind continue];
13+
- }
14+
-
15+
- bb1: {
16+
StorageDead(_1);
17+
_0 = const ();
18+
return;
19+
}
20+
}
21+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
2+
//@ compile-flags: -Copt-level=0 --crate-type=lib
3+
#![feature(rustc_attrs)]
4+
5+
struct Foo;
6+
7+
impl Foo {
8+
#[rustc_force_inline]
9+
fn bar() {}
10+
}
11+
12+
trait Tr {
13+
fn bar();
14+
}
15+
16+
impl Tr for Foo {
17+
fn bar() {}
18+
}
19+
20+
// EMIT_MIR forced_inherent_ambiguous.caller.ForceInline.diff
21+
fn caller() {
22+
Foo::bar();
23+
// CHECK-LABEL: fn caller(
24+
// CHECK: (inlined Foo::bar)
25+
}

0 commit comments

Comments
 (0)