Skip to content

Commit fda4cae

Browse files
Auto merge of #149843 - aerooneqq:inherit-attributes-in-delegation, r=<try>
Inherit attributes in delegation
2 parents 2a3a62d + c5c8bbd commit fda4cae

File tree

6 files changed

+308
-26
lines changed

6 files changed

+308
-26
lines changed

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 136 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ use hir::def::{DefKind, PartialRes, Res};
4343
use hir::{BodyId, HirId};
4444
use rustc_abi::ExternAbi;
4545
use rustc_ast::*;
46+
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
4647
use rustc_errors::ErrorGuaranteed;
48+
use rustc_hir::Target;
4749
use rustc_hir::attrs::{AttributeKind, InlineAttr};
4850
use rustc_hir::def_id::DefId;
4951
use rustc_middle::span_bug;
50-
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
52+
use rustc_middle::ty::{Asyncness, DelegationFnSigAttrs, ResolverAstLowering};
5153
use rustc_span::symbol::kw;
52-
use rustc_span::{Ident, Span, Symbol};
54+
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
5355
use {rustc_ast as ast, rustc_hir as hir};
5456

5557
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
@@ -62,6 +64,44 @@ pub(crate) struct DelegationResults<'hir> {
6264
pub generics: &'hir hir::Generics<'hir>,
6365
}
6466

67+
struct AttributeAdditionInfo {
68+
pub equals: fn(&hir::Attribute) -> bool,
69+
pub kind: AttributeAdditionKind,
70+
}
71+
72+
enum AttributeAdditionKind {
73+
Default { factory: fn(Span) -> hir::Attribute },
74+
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
75+
}
76+
77+
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
78+
79+
static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[
80+
AttributeAdditionInfo {
81+
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })),
82+
kind: AttributeAdditionKind::Inherit {
83+
factory: |span, original_attribute| {
84+
let reason = match original_attribute {
85+
hir::Attribute::Parsed(AttributeKind::MustUse {
86+
span: _,
87+
reason: Some(reason),
88+
}) => Some(reason.clone()),
89+
_ => None,
90+
};
91+
92+
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
93+
},
94+
flag: DelegationFnSigAttrs::MUST_USE,
95+
},
96+
},
97+
AttributeAdditionInfo {
98+
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
99+
kind: AttributeAdditionKind::Default {
100+
factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
101+
},
102+
},
103+
];
104+
65105
impl<'hir> LoweringContext<'_, 'hir> {
66106
fn is_method(&self, def_id: DefId, span: Span) -> bool {
67107
match self.tcx.def_kind(def_id) {
@@ -88,7 +128,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
88128
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
89129
match sig_id {
90130
Ok(sig_id) => {
91-
self.add_inline_attribute_if_needed(span);
131+
self.add_attributes_if_needed(span, sig_id);
92132

93133
let is_method = self.is_method(sig_id, span);
94134
let (param_count, c_variadic) = self.param_count(sig_id);
@@ -103,29 +143,100 @@ impl<'hir> LoweringContext<'_, 'hir> {
103143
}
104144
}
105145

106-
fn add_inline_attribute_if_needed(&mut self, span: Span) {
107-
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
108-
let create_inline_attr_slice =
109-
|| [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))];
110-
111-
let new_attributes = match self.attrs.get(&PARENT_ID) {
112-
Some(attrs) => {
113-
// Check if reuse already specifies any inline attribute, if so, do nothing
114-
if attrs
115-
.iter()
116-
.any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))))
146+
fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) {
147+
let new_attributes = self.create_new_attributes(
148+
ATTRIBUTES_ADDITIONS,
149+
span,
150+
sig_id,
151+
self.attrs.get(&PARENT_ID),
152+
);
153+
154+
if new_attributes.is_empty() {
155+
return;
156+
}
157+
158+
let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) {
159+
Some(existing_attrs) => self.arena.alloc_from_iter(
160+
existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()),
161+
),
162+
None => self.arena.alloc_from_iter(new_attributes.into_iter()),
163+
};
164+
165+
self.attrs.insert(PARENT_ID, new_arena_allocated_attributes);
166+
}
167+
168+
fn create_new_attributes(
169+
&self,
170+
candidate_additions: &[AttributeAdditionInfo],
171+
span: Span,
172+
sig_id: DefId,
173+
existing_attrs: Option<&&[hir::Attribute]>,
174+
) -> Vec<hir::Attribute> {
175+
let local_original_attributes = self.parse_local_original_attributes(sig_id);
176+
177+
candidate_additions
178+
.iter()
179+
.filter_map(|addition_info| {
180+
if let Some(existing_attrs) = existing_attrs
181+
&& existing_attrs
182+
.iter()
183+
.any(|existing_attr| (addition_info.equals)(existing_attr))
117184
{
118-
return;
185+
return None;
119186
}
120187

121-
self.arena.alloc_from_iter(
122-
attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()),
123-
)
124-
}
125-
None => self.arena.alloc_from_iter(create_inline_attr_slice()),
126-
};
188+
match addition_info.kind {
189+
AttributeAdditionKind::Default { factory } => Some(factory(span)),
190+
AttributeAdditionKind::Inherit { flag, factory } => {
191+
let original_attribute = match sig_id.as_local() {
192+
Some(local_id) => self
193+
.resolver
194+
.delegation_fn_sigs
195+
.get(&local_id)
196+
.is_some_and(|sig| sig.attrs_flags.contains(flag))
197+
.then(|| {
198+
local_original_attributes
199+
.as_ref()
200+
.map(|attrs| {
201+
attrs
202+
.iter()
203+
.find(|base_attr| (addition_info.equals)(base_attr))
204+
})
205+
.flatten()
206+
})
207+
.flatten(),
208+
None => self
209+
.tcx
210+
.get_all_attrs(sig_id)
211+
.iter()
212+
.find(|base_attr| (addition_info.equals)(base_attr)),
213+
};
127214

128-
self.attrs.insert(PARENT_ID, new_attributes);
215+
original_attribute.map(|a| factory(span, a))
216+
}
217+
}
218+
})
219+
.collect::<Vec<_>>()
220+
}
221+
222+
fn parse_local_original_attributes(&self, sig_id: DefId) -> Option<Vec<hir::Attribute>> {
223+
if let Some(local_id) = sig_id.as_local()
224+
&& let Some(info) = self.resolver.delegation_fn_sigs.get(&local_id)
225+
&& !info.to_inherit_attrs.is_empty()
226+
{
227+
Some(AttributeParser::parse_limited_all(
228+
self.tcx.sess,
229+
info.to_inherit_attrs.as_slice(),
230+
None,
231+
Target::Fn,
232+
DUMMY_SP,
233+
DUMMY_NODE_ID,
234+
Some(self.tcx.features()),
235+
ShouldEmit::Nothing,
236+
))
237+
} else {
238+
None
239+
}
129240
}
130241

131242
fn get_delegation_sig_id(
@@ -220,7 +331,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
220331
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
221332
// and here we need the hir attributes.
222333
let default_safety =
223-
if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
334+
if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
335+
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
336+
{
224337
hir::Safety::Unsafe
225338
} else {
226339
hir::Safety::Safe

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *};
2525
pub use generics::*;
2626
pub use intrinsic::IntrinsicDef;
2727
use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
28+
use rustc_ast::AttrVec;
2829
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
2930
use rustc_ast::node_id::NodeMap;
3031
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
@@ -221,13 +222,24 @@ pub struct ResolverAstLowering {
221222
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
222223
}
223224

225+
bitflags::bitflags! {
226+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
227+
pub struct DelegationFnSigAttrs: u8 {
228+
const TARGET_FEATURE = 1 << 0;
229+
const MUST_USE = 1 << 1;
230+
}
231+
}
232+
233+
pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE;
234+
224235
#[derive(Debug)]
225236
pub struct DelegationFnSig {
226237
pub header: ast::FnHeader,
227238
pub param_count: usize,
228239
pub has_self: bool,
229240
pub c_variadic: bool,
230-
pub target_feature: bool,
241+
pub attrs_flags: DelegationFnSigAttrs,
242+
pub to_inherit_attrs: AttrVec,
231243
}
232244

233245
#[derive(Clone, Copy, Debug, HashStable)]

compiler/rustc_resolve/src/late.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par
2828
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
2929
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
3030
use rustc_middle::middle::resolve_bound_vars::Set1;
31-
use rustc_middle::ty::{AssocTag, DelegationFnSig, Visibility};
31+
use rustc_middle::ty::{
32+
AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs, Visibility,
33+
};
3234
use rustc_middle::{bug, span_bug};
3335
use rustc_session::config::{CrateType, ResolveDocLinks};
3436
use rustc_session::lint;
@@ -5294,13 +5296,37 @@ impl ItemInfoCollector<'_, '_, '_> {
52945296
id: NodeId,
52955297
attrs: &[Attribute],
52965298
) {
5299+
static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[
5300+
(sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE),
5301+
(sym::must_use, DelegationFnSigAttrs::MUST_USE),
5302+
];
5303+
5304+
let mut to_inherit_attrs = AttrVec::new();
5305+
let mut attrs_flags = DelegationFnSigAttrs::empty();
5306+
5307+
'attrs_loop: for attr in attrs {
5308+
for &(name, flag) in NAMES_TO_FLAGS {
5309+
if attr.has_name(name) {
5310+
attrs_flags.set(flag, true);
5311+
5312+
if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() {
5313+
to_inherit_attrs.push(attr.clone());
5314+
}
5315+
5316+
continue 'attrs_loop;
5317+
}
5318+
}
5319+
}
5320+
52975321
let sig = DelegationFnSig {
52985322
header,
52995323
param_count: decl.inputs.len(),
53005324
has_self: decl.has_self(),
53015325
c_variadic: decl.c_variadic(),
5302-
target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)),
5326+
attrs_flags,
5327+
to_inherit_attrs,
53035328
};
5329+
53045330
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
53055331
}
53065332
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ edition:2021
2+
3+
#[must_use]
4+
#[cold]
5+
pub unsafe fn unsafe_fn_extern() -> usize { 1 }
6+
7+
#[must_use = "extern_fn_extern: some reason"]
8+
#[deprecated]
9+
pub extern "C" fn extern_fn_extern() -> usize { 1 }
10+
11+
pub const fn const_fn_extern() -> usize { 1 }
12+
13+
#[must_use]
14+
pub async fn async_fn_extern() { }
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//@ edition:2021
2+
//@ aux-crate:to_reuse_functions=to-reuse-functions.rs
3+
//@ pretty-mode:hir
4+
//@ pretty-compare-only
5+
//@ pp-exact:delegation-inherit-attributes.pp
6+
7+
#![allow(incomplete_features)]
8+
#![feature(fn_delegation)]
9+
#[attr = MacroUse {arguments: UseAll}]
10+
extern crate std;
11+
#[prelude_import]
12+
use std::prelude::rust_2021::*;
13+
14+
extern crate to_reuse_functions;
15+
16+
mod to_reuse {
17+
#[attr = MustUse {reason: "foo: some reason"}]
18+
#[attr = Cold]
19+
fn foo(x: usize) -> usize { x }
20+
21+
#[attr = MustUse]
22+
#[attr = Cold]
23+
fn foo_no_reason(x: usize) -> usize { x }
24+
25+
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
26+
#[attr = Cold]
27+
fn bar(x: usize) -> usize { x }
28+
}
29+
30+
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
31+
#[attr = MustUse {reason: "foo: some reason"}]
32+
#[attr = Inline(Hint)]
33+
fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) }
34+
35+
#[attr = MustUse]
36+
#[attr = Inline(Hint)]
37+
fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) }
38+
39+
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
40+
#[attr = MustUse {reason: "some reason"}]
41+
#[attr = Inline(Hint)]
42+
fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) }
43+
44+
#[attr = Inline(Hint)]
45+
fn bar(arg0: _) -> _ { to_reuse::bar(arg0) }
46+
47+
#[attr = MustUse]
48+
#[attr = Inline(Hint)]
49+
unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() }
50+
#[attr = MustUse {reason: "extern_fn_extern: some reason"}]
51+
#[attr = Inline(Hint)]
52+
extern "C" fn extern_fn_extern()
53+
-> _ { to_reuse_functions::extern_fn_extern() }
54+
#[attr = Inline(Hint)]
55+
const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() }
56+
#[attr = MustUse {reason: "some reason"}]
57+
#[attr = Inline(Hint)]
58+
async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() }
59+
60+
61+
fn main() { }

0 commit comments

Comments
 (0)