diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index e6e88eff2d5bc..0e7db7c9503cb 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -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, diff --git a/tests/pretty/delegation_inline_attribute.pp b/tests/pretty/delegation_inline_attribute.pp new file mode 100644 index 0000000000000..4b3b2aa8f80a2 --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.pp @@ -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() { } diff --git a/tests/pretty/delegation_inline_attribute.rs b/tests/pretty/delegation_inline_attribute.rs new file mode 100644 index 0000000000000..0716cfc51f5d9 --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.rs @@ -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() { +} diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index f8ad02f2fccce..b5f7a14eb2fc0 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -12,6 +12,7 @@ fn b(e: C) { } trait G { + #[attr = Inline(Hint)] fn b(arg0: _) -> _ { b({ }) } } @@ -19,6 +20,7 @@ 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); }; }