Skip to content

Commit 0a3fd24

Browse files
committed
Support attribute inheritance in delegation
1 parent f520900 commit 0a3fd24

File tree

6 files changed

+305
-26
lines changed

6 files changed

+305
-26
lines changed

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 133 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,41 @@ 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 { reason, .. }) => *reason,
86+
_ => None,
87+
};
88+
89+
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
90+
},
91+
flag: DelegationFnSigAttrs::MUST_USE,
92+
},
93+
},
94+
AttributeAdditionInfo {
95+
equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))),
96+
kind: AttributeAdditionKind::Default {
97+
factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)),
98+
},
99+
},
100+
];
101+
65102
impl<'hir> LoweringContext<'_, 'hir> {
66103
fn is_method(&self, def_id: DefId, span: Span) -> bool {
67104
match self.tcx.def_kind(def_id) {
@@ -88,7 +125,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
88125
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
89126
match sig_id {
90127
Ok(sig_id) => {
91-
self.add_inline_attribute_if_needed(span);
128+
self.add_attributes_if_needed(span, sig_id);
92129

93130
let is_method = self.is_method(sig_id, span);
94131
let (param_count, c_variadic) = self.param_count(sig_id);
@@ -103,29 +140,100 @@ impl<'hir> LoweringContext<'_, 'hir> {
103140
}
104141
}
105142

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(..))))
143+
fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) {
144+
let new_attributes = self.create_new_attributes(
145+
ATTRIBUTES_ADDITIONS,
146+
span,
147+
sig_id,
148+
self.attrs.get(&PARENT_ID),
149+
);
150+
151+
if new_attributes.is_empty() {
152+
return;
153+
}
154+
155+
let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) {
156+
Some(existing_attrs) => self.arena.alloc_from_iter(
157+
existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()),
158+
),
159+
None => self.arena.alloc_from_iter(new_attributes.into_iter()),
160+
};
161+
162+
self.attrs.insert(PARENT_ID, new_arena_allocated_attributes);
163+
}
164+
165+
fn create_new_attributes(
166+
&self,
167+
candidate_additions: &[AttributeAdditionInfo],
168+
span: Span,
169+
sig_id: DefId,
170+
existing_attrs: Option<&&[hir::Attribute]>,
171+
) -> Vec<hir::Attribute> {
172+
let local_original_attributes = self.parse_local_original_attributes(sig_id);
173+
174+
candidate_additions
175+
.iter()
176+
.filter_map(|addition_info| {
177+
if let Some(existing_attrs) = existing_attrs
178+
&& existing_attrs
179+
.iter()
180+
.any(|existing_attr| (addition_info.equals)(existing_attr))
117181
{
118-
return;
182+
return None;
119183
}
120184

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-
};
185+
match addition_info.kind {
186+
AttributeAdditionKind::Default { factory } => Some(factory(span)),
187+
AttributeAdditionKind::Inherit { flag, factory } => {
188+
let original_attribute = match sig_id.as_local() {
189+
Some(local_id) => self
190+
.resolver
191+
.delegation_fn_sigs
192+
.get(&local_id)
193+
.is_some_and(|sig| sig.attrs_flags.contains(flag))
194+
.then(|| {
195+
local_original_attributes
196+
.as_ref()
197+
.map(|attrs| {
198+
attrs
199+
.iter()
200+
.find(|base_attr| (addition_info.equals)(base_attr))
201+
})
202+
.flatten()
203+
})
204+
.flatten(),
205+
None => self
206+
.tcx
207+
.get_all_attrs(sig_id)
208+
.iter()
209+
.find(|base_attr| (addition_info.equals)(base_attr)),
210+
};
127211

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

131239
fn get_delegation_sig_id(
@@ -220,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
220328
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
221329
// and here we need the hir attributes.
222330
let default_safety =
223-
if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
331+
if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
332+
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
333+
{
224334
hir::Safety::Unsafe
225335
} else {
226336
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)