Add inline attribute to generated delegation function if needed

This commit is contained in:
aerooneqq 2025-12-08 19:56:47 +03:00
parent 1d6c526bb0
commit 8cf942d89f
4 changed files with 228 additions and 0 deletions

View file

@ -44,6 +44,7 @@ use hir::{BodyId, HirId};
use rustc_abi::ExternAbi;
use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
@ -87,6 +88,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
match sig_id {
Ok(sig_id) => {
self.add_inline_attribute_if_needed(span);
let is_method = self.is_method(sig_id, span);
let (param_count, c_variadic) = self.param_count(sig_id);
let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span);
@ -100,6 +103,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn add_inline_attribute_if_needed(&mut self, span: Span) {
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
let create_inline_attr_slice =
|| [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))];
let new_attributes = match self.attrs.get(&PARENT_ID) {
Some(attrs) => {
// Check if reuse already specifies any inline attribute, if so, do nothing
if attrs
.iter()
.any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))))
{
return;
}
self.arena.alloc_from_iter(
attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()),
)
}
None => self.arena.alloc_from_iter(create_inline_attr_slice()),
};
self.attrs.insert(PARENT_ID, new_attributes);
}
fn get_delegation_sig_id(
&self,
item_id: NodeId,

View file

@ -0,0 +1,94 @@
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:delegation_inline_attribute.pp
#![allow(incomplete_features)]
#![feature(fn_delegation)]
#[attr = MacroUse {arguments: UseAll}]
extern crate std;
#[prelude_import]
use ::std::prelude::rust_2015::*;
mod to_reuse {
fn foo(x: usize) -> usize { x }
}
// Check that #[inline(hint)] is added to foo reuse
#[attr = Inline(Hint)]
fn bar(arg0: _) -> _ { to_reuse::foo(self + 1) }
trait Trait {
fn foo(&self) { }
fn foo1(&self) { }
fn foo2(&self) { }
fn foo3(&self) { }
fn foo4(&self) { }
}
impl Trait for u8 { }
struct S(u8);
mod to_import {
fn check(arg: &'_ u8) -> &'_ u8 { arg }
}
impl Trait for S {
// Check that #[inline(hint)] is added to foo reuse
#[attr = Inline(Hint)]
fn foo(self: _)
->
_ {
{
// Check that #[inline(hint)] is added to foo0 reuse inside another reuse
#[attr = Inline(Hint)]
fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) }
// Check that #[inline(hint)] is added when other attributes present in inner reuse
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
#[attr = MustUse]
#[attr = Cold]
#[attr = Inline(Hint)]
fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) }
// Check that #[inline(never)] is preserved in inner reuse
#[attr = Inline(Never)]
fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) }
// Check that #[inline(always)] is preserved in inner reuse
#[attr = Inline(Always)]
fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) }
// Check that #[inline(never)] is preserved when there are other attributes in inner reuse
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
#[attr = Inline(Never)]
#[attr = MustUse]
#[attr = Cold]
fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) }
}.foo()
}
// Check that #[inline(hint)] is added when there are other attributes present in trait reuse
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
#[attr = MustUse]
#[attr = Cold]
#[attr = Inline(Hint)]
fn foo1(self: _) -> _ { self.0.foo1() }
// Check that #[inline(never)] is preserved in trait reuse
#[attr = Inline(Never)]
fn foo2(self: _) -> _ { self.0.foo2() }
// Check that #[inline(always)] is preserved in trait reuse
#[attr = Inline(Always)]
fn foo3(self: _) -> _ { self.0.foo3() }
// Check that #[inline(never)] is preserved when there are other attributes in trait reuse
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
#[attr = Inline(Never)]
#[attr = MustUse]
#[attr = Cold]
fn foo4(self: _) -> _ { self.0.foo4() }
}
fn main() { }

View file

@ -0,0 +1,104 @@
//@ pretty-compare-only
//@ pretty-mode:hir
//@ pp-exact:delegation_inline_attribute.pp
#![allow(incomplete_features)]
#![feature(fn_delegation)]
mod to_reuse {
pub fn foo(x: usize) -> usize {
x
}
}
// Check that #[inline(hint)] is added to foo reuse
reuse to_reuse::foo as bar {
self + 1
}
trait Trait {
fn foo(&self) {}
fn foo1(&self) {}
fn foo2(&self) {}
fn foo3(&self) {}
fn foo4(&self) {}
}
impl Trait for u8 {}
struct S(u8);
mod to_import {
pub fn check(arg: &u8) -> &u8 { arg }
}
impl Trait for S {
// Check that #[inline(hint)] is added to foo reuse
reuse Trait::foo {
// Check that #[inline(hint)] is added to foo0 reuse inside another reuse
reuse to_reuse::foo as foo0 {
self + 1
}
// Check that #[inline(hint)] is added when other attributes present in inner reuse
#[cold]
#[must_use]
#[deprecated]
reuse to_reuse::foo as foo1 {
self / 2
}
// Check that #[inline(never)] is preserved in inner reuse
#[inline(never)]
reuse to_reuse::foo as foo2 {
self / 2
}
// Check that #[inline(always)] is preserved in inner reuse
#[inline(always)]
reuse to_reuse::foo as foo3 {
self / 2
}
// Check that #[inline(never)] is preserved when there are other attributes in inner reuse
#[cold]
#[must_use]
#[inline(never)]
#[deprecated]
reuse to_reuse::foo as foo4 {
self / 2
}
}
// Check that #[inline(hint)] is added when there are other attributes present in trait reuse
#[cold]
#[must_use]
#[deprecated]
reuse Trait::foo1 {
self.0
}
// Check that #[inline(never)] is preserved in trait reuse
#[inline(never)]
reuse Trait::foo2 {
self.0
}
// Check that #[inline(always)] is preserved in trait reuse
#[inline(always)]
reuse Trait::foo3 {
self.0
}
// Check that #[inline(never)] is preserved when there are other attributes in trait reuse
#[cold]
#[must_use]
#[inline(never)]
#[deprecated]
reuse Trait::foo4 {
self.0
}
}
fn main() {
}

View file

@ -12,6 +12,7 @@ use ::std::prelude::rust_2015::*;
fn b<C>(e: C) { }
trait G {
#[attr = Inline(Hint)]
fn b(arg0: _) -> _ { b({ }) }
}
@ -19,6 +20,7 @@ mod m {
fn add(a: u32, b: u32) -> u32 { a + b }
}
#[attr = Inline(Hint)]
fn add(arg0: _, arg1: _) -> _ { m::add(arg0, arg1) }
fn main() { { let _ = add(1, 2); }; }