Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 47 additions & 197 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,15 @@ use hir::{BodyId, HirId};
use rustc_abi::ExternAbi;
use rustc_ast as ast;
use rustc_ast::*;
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs};
use rustc_middle::ty::Asyncness;
use rustc_span::symbol::kw;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
use rustc_span::{Ident, Span, Symbol};
use smallvec::SmallVec;

use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
Expand All @@ -80,7 +79,7 @@ struct AttrAdditionInfo {

enum AttrAdditionKind {
Default { factory: fn(Span) -> hir::Attribute },
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
}

const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
Expand All @@ -97,7 +96,6 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[

hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
},
flag: DelegationFnSigAttrs::MUST_USE,
},
},
AttrAdditionInfo {
Expand All @@ -108,43 +106,11 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
},
];

type DelegationIdsVec = SmallVec<[DefId; 1]>;

// As delegations can now refer to another delegation, we have a delegation path
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
struct DelegationIds {
path: DelegationIdsVec,
}

impl DelegationIds {
fn new(path: DelegationIdsVec) -> Self {
assert!(!path.is_empty());
Self { path }
}

// Id of the first function in (non)local crate that is being reused
fn root_function_id(&self) -> DefId {
*self.path.last().expect("Ids vector can't be empty")
}

// Id of the first definition which is being reused,
// can be either function, in this case `root_id == delegee_id`, or other delegation
fn delegee_id(&self) -> DefId {
*self.path.first().expect("Ids vector can't be empty")
}
}

impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
fn is_method(&self, def_id: DefId, span: Span) -> bool {
match self.tcx.def_kind(def_id) {
DefKind::Fn => false,
DefKind::AssocFn => match def_id.as_local() {
Some(local_def_id) => {
self.resolver.delegation_fn_sig(local_def_id).is_some_and(|sig| sig.has_self)
}
None => self.tcx.associated_item(def_id).is_method(),
},
DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}
}
Expand All @@ -157,10 +123,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);

// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
let ids = if let Some(delegation_info) =
let sig_id = if let Some(delegation_info) =
self.resolver.delegation_info(self.local_def_id(item_id))
{
self.get_delegation_ids(delegation_info.resolution_node, span)
self.get_sig_id(delegation_info.resolution_node, span)
} else {
return self.generate_delegation_error(
self.dcx().span_delayed_bug(
Expand All @@ -172,28 +138,16 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
);
};

match ids {
Ok(ids) => {
self.add_attrs_if_needed(span, &ids);

let delegee_id = ids.delegee_id();
let root_function_id = ids.root_function_id();
match sig_id {
Ok(sig_id) => {
self.add_attrs_if_needed(span, sig_id);

// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
// if the original function is not a method (without `self`), then it can not be added
// during chain of reuses, so we use `root_function_id` here
let is_method = self.is_method(root_function_id, span);
let is_method = self.is_method(sig_id, span);

// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
// we need a function to extract this information
let (param_count, c_variadic) = self.param_count(root_function_id);
let (param_count, c_variadic) = self.param_count(sig_id);

let mut generics = self.lower_delegation_generics(
delegation,
ids.root_function_id(),
item_id,
span,
);
let mut generics =
self.lower_delegation_generics(delegation, sig_id, item_id, span);

let body_id = self.lower_delegation_body(
delegation,
Expand All @@ -204,20 +158,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
span,
);

// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
// inheritance, and we want this id to point on a delegee, not on the original
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
let decl = self.lower_delegation_decl(
delegee_id,
param_count,
c_variadic,
span,
&generics,
);
let decl =
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);

// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
// from the root function that started delegation
let sig = self.lower_delegation_sig(root_function_id, decl, span);
let sig = self.lower_delegation_sig(sig_id, decl, span);
let ident = self.lower_ident(delegation.ident);

let generics = self.arena.alloc(hir::Generics {
Expand All @@ -236,9 +180,9 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
}
}

fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
let new_attrs =
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));

if new_attrs.is_empty() {
return;
Expand All @@ -258,15 +202,9 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
&self,
candidate_additions: &[AttrAdditionInfo],
span: Span,
ids: &DelegationIds,
sig_id: DefId,
existing_attrs: Option<&&[hir::Attribute]>,
) -> Vec<hir::Attribute> {
let defs_orig_attrs = ids
.path
.iter()
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
.collect::<Vec<_>>();

candidate_additions
.iter()
.filter_map(|addition_info| {
Expand All @@ -280,83 +218,22 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {

match addition_info.kind {
AttrAdditionKind::Default { factory } => Some(factory(span)),
AttrAdditionKind::Inherit { flag, factory } => {
for (def_id, orig_attrs) in &defs_orig_attrs {
let original_attr = match def_id.as_local() {
Some(local_id) => self
.get_attrs(local_id)
.flags
.contains(flag)
.then(|| {
orig_attrs
.as_ref()
.map(|attrs| {
attrs.iter().find(|base_attr| {
(addition_info.equals)(base_attr)
})
})
.flatten()
})
.flatten(),
None =>
{
#[allow(deprecated)]
self.tcx
.get_all_attrs(*def_id)
.iter()
.find(|base_attr| (addition_info.equals)(base_attr))
}
};

if let Some(original_attr) = original_attr {
return Some(factory(span, original_attr));
}
}

None
AttrAdditionKind::Inherit { factory, .. } =>
{
#[allow(deprecated)]
self.tcx
.get_all_attrs(sig_id)
.iter()
.find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
}
}
})
.collect::<Vec<_>>()
}

fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
if let Some(local_id) = def_id.as_local() {
let attrs = &self.get_attrs(local_id).to_inherit;

if !attrs.is_empty() {
return Some(AttributeParser::parse_limited_all(
self.tcx.sess,
attrs,
None,
hir::Target::Fn,
DUMMY_SP,
DUMMY_NODE_ID,
Some(self.tcx.features()),
ShouldEmit::Nothing,
));
}
}

None
}

fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
// local_id can correspond either to a function or other delegation
if let Some(fn_sig) = self.resolver.delegation_fn_sig(local_id) {
&fn_sig.attrs
} else {
&self.resolver.delegation_info(local_id).expect("processing delegation").attrs
}
}

fn get_delegation_ids(
&self,
mut node_id: NodeId,
span: Span,
) -> Result<DelegationIds, ErrorGuaranteed> {
fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
let mut visited: FxHashSet<NodeId> = Default::default();
let mut path: DelegationIdsVec = Default::default();
let mut path: SmallVec<[DefId; 1]> = Default::default();

loop {
visited.insert(node_id);
Expand Down Expand Up @@ -389,7 +266,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
});
}
} else {
return Ok(DelegationIds::new(path));
return Ok(path[0]);
}
}
}
Expand All @@ -400,15 +277,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {

// Function parameter count, including C variadic `...` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
if let Some(local_sig_id) = def_id.as_local() {
match self.resolver.delegation_fn_sig(local_sig_id) {
Some(sig) => (sig.param_count, sig.c_variadic),
None => (0, false),
}
} else {
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
}
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
}

fn lower_delegation_decl(
Expand Down Expand Up @@ -455,41 +325,21 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
decl: &'hir hir::FnDecl<'hir>,
span: Span,
) -> hir::FnSig<'hir> {
let header = if let Some(local_sig_id) = sig_id.as_local() {
match self.resolver.delegation_fn_sig(local_sig_id) {
Some(sig) => {
let parent = self.tcx.parent(sig_id);
// HACK: we override the default safety instead of generating attributes from the ether.
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
// and here we need the hir attributes.
let default_safety =
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
{
hir::Safety::Unsafe
} else {
hir::Safety::Safe
};
self.lower_fn_header(sig.header, default_safety, &[])
}
None => self.generate_header_error(),
}
} else {
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
let asyncness = match self.tcx.asyncness(sig_id) {
Asyncness::Yes => hir::IsAsync::Async(span),
Asyncness::No => hir::IsAsync::NotAsync,
};
hir::FnHeader {
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures
} else {
hir::HeaderSafety::Normal(sig.safety)
},
constness: self.tcx.constness(sig_id),
asyncness,
abi: sig.abi,
}
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
let asyncness = match self.tcx.asyncness(sig_id) {
Asyncness::Yes => hir::IsAsync::Async(span),
Asyncness::No => hir::IsAsync::NotAsync,
};

let header = hir::FnHeader {
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures
} else {
hir::HeaderSafety::Normal(sig.safety)
},
constness: self.tcx.constness(sig_id),
asyncness,
abi: sig.abi,
};

hir::FnSig { decl, header, span }
Expand Down
Loading
Loading