Skip to content

Commit 303d29a

Browse files
committed
Do not always generate first delegation argument
1 parent b954122 commit 303d29a

21 files changed

Lines changed: 354 additions & 110 deletions

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3909,7 +3909,7 @@ pub struct Delegation {
39093909
pub rename: Option<Ident>,
39103910
pub body: Option<Box<Block>>,
39113911
/// The item was expanded from a glob delegation item.
3912-
pub from_glob: bool,
3912+
pub from_glob_or_list: bool,
39133913
}
39143914

39153915
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,6 @@ macro_rules! common_visitor_and_walkers {
428428
ConstItem,
429429
ConstItemRhsKind,
430430
Defaultness,
431-
Delegation,
432431
DelegationMac,
433432
DelegationSuffixes,
434433
DelimArgs,
@@ -573,6 +572,7 @@ macro_rules! common_visitor_and_walkers {
573572
fn visit_fn_decl(FnDecl);
574573
fn visit_fn_header(FnHeader);
575574
fn visit_fn_ret_ty(FnRetTy);
575+
fn visit_delegation(Delegation);
576576
//fn visit_foreign_item(ForeignItem);
577577
fn visit_foreign_mod(ForeignMod);
578578
fn visit_format_args(FormatArgs);

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,16 @@ use rustc_hir::attrs::{AttributeKind, InlineAttr};
5050
use rustc_hir::def_id::DefId;
5151
use rustc_hir::{self as hir, FnDeclFlags};
5252
use rustc_middle::span_bug;
53-
use rustc_middle::ty::Asyncness;
53+
use rustc_middle::ty::{Asyncness, TyCtxt};
5454
use rustc_span::symbol::kw;
5555
use rustc_span::{Ident, Span, Symbol};
5656
use smallvec::SmallVec;
5757

5858
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
59-
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
59+
use crate::errors::{
60+
CycleInDelegationSignatureResolution, DelegationBlockSpecifiedWhenNoParams,
61+
UnresolvedDelegationCallee,
62+
};
6063
use crate::{
6164
AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
6265
ParamMode, ResolverAstLoweringExt,
@@ -105,6 +108,12 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
105108
},
106109
];
107110

111+
// Function parameter count, including C variadic `...` if present.
112+
pub(crate) fn param_count(tcx: TyCtxt<'_>, def_id: DefId) -> (usize, bool /*c_variadic*/) {
113+
let sig = tcx.fn_sig(def_id).skip_binder().skip_binder();
114+
(sig.inputs().len() + usize::from(sig.c_variadic()), sig.c_variadic())
115+
}
116+
108117
impl<'hir> LoweringContext<'_, 'hir> {
109118
fn is_method(&self, def_id: DefId, span: Span) -> bool {
110119
match self.tcx.def_kind(def_id) {
@@ -140,13 +149,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
140149

141150
let is_method = self.is_method(sig_id, span);
142151

143-
let (param_count, c_variadic) = self.param_count(sig_id);
152+
let (param_count, c_variadic) = param_count(self.tcx, sig_id);
144153

145154
let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method);
146155

147156
let body_id = self.lower_delegation_body(
148157
delegation,
149-
is_method,
158+
sig_id,
150159
param_count,
151160
&mut generics,
152161
span,
@@ -267,12 +276,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
267276
self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
268277
}
269278

270-
// Function parameter count, including C variadic `...` if present.
271-
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
272-
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
273-
(sig.inputs().len() + usize::from(sig.c_variadic()), sig.c_variadic())
274-
}
275-
276279
fn lower_delegation_decl(
277280
&mut self,
278281
sig_id: DefId,
@@ -396,7 +399,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
396399
fn lower_delegation_body(
397400
&mut self,
398401
delegation: &Delegation,
399-
is_method: bool,
402+
sig_id: DefId,
400403
param_count: usize,
401404
generics: &mut GenericsGenerationResults<'hir>,
402405
span: Span,
@@ -406,13 +409,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
406409
self.lower_body(|this| {
407410
let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
408411
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
412+
let is_method = this.is_method(sig_id, span);
409413

410414
for idx in 0..param_count {
411415
let (param, pat_node_id) = this.generate_param(is_method, idx, span);
412416
parameters.push(param);
413417

418+
// Should be in sync with conditions in `lower_delayed_owner::is_dead_code`.
419+
let generate_block = is_method
420+
|| matches!(this.tcx.def_kind(sig_id), DefKind::Fn)
421+
|| !delegation.from_glob_or_list;
422+
423+
// Generate block only if we are method and from glob or list OR we are not from glob or list.
414424
let arg = if let Some(block) = block
415425
&& idx == 0
426+
&& generate_block
416427
{
417428
let mut self_resolver = SelfResolver {
418429
ctxt: this,
@@ -429,15 +440,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
429440
args.push(arg);
430441
}
431442

432-
// If we have no params in signature function but user still wrote some code in
433-
// delegation body, then add this code as first arg, eventually an error will be shown,
434-
// also nested delegations may need to access information about this code (#154332),
435-
// so it is better to leave this code as opposed to bodies of extern functions,
436-
// which are completely erased from existence.
443+
// Report an error if user has explicitly specified delegation's block
444+
// in a single delegation when reused function has no params.
437445
if param_count == 0
446+
&& !delegation.from_glob_or_list
438447
&& let Some(block) = block
439448
{
440-
args.push(this.lower_target_expr(&block));
449+
this.dcx().emit_err(DelegationBlockSpecifiedWhenNoParams { span: block.span });
441450
}
442451

443452
let final_expr = this.finalize_body_lowering(delegation, args, generics, span);

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,10 @@ pub(crate) struct CycleInDelegationSignatureResolution {
535535
#[primary_span]
536536
pub span: Span,
537537
}
538+
539+
#[derive(Diagnostic)]
540+
#[diag("delegation block is specified for function with no params")]
541+
pub(crate) struct DelegationBlockSpecifiedWhenNoParams {
542+
#[primary_span]
543+
pub span: Span,
544+
}

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -555,13 +555,21 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
555555
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
556556

557557
for def_id in ast_index.indices() {
558-
match &ast_index[def_id] {
558+
// Check if this def is inside delegation (or it is delegation itself), if so,
559+
// we should lower it in delayed mode, as we need to resolve delegation in order
560+
// to understand whether to generate block as first arg or not.
561+
let def_inside_delegation = resolver.defs_in_delegations_blocks.contains_key(&def_id);
562+
let is_delegation = matches!(
563+
ast_index[def_id],
559564
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
560-
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
561-
delayed_ids.insert(def_id);
562-
}
563-
_ => lowerer.lower_node(def_id),
564-
};
565+
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _)
566+
);
567+
568+
if def_inside_delegation || is_delegation {
569+
delayed_ids.insert(def_id);
570+
} else {
571+
lowerer.lower_node(def_id);
572+
}
565573
}
566574

567575
// Don't hash unless necessary, because it's expensive.
@@ -590,10 +598,53 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
590598
owners: Owners::Map(&mut map),
591599
};
592600

593-
lowerer.lower_node(def_id);
601+
let is_dead_code = || -> bool {
602+
// Try to find enclosing delegation (delegation in which block this `def_id` is placed).
603+
let Some(&parent_del) = resolver.defs_in_delegations_blocks.get(&def_id) else {
604+
return false;
605+
};
606+
607+
let from_glob_or_list = match &ast_index[parent_del] {
608+
AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. })
609+
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(d), .. }, _) => {
610+
d.from_glob_or_list
611+
}
612+
_ => unreachable!(),
613+
};
594614

595-
for (child_def_id, owner) in map {
596-
tcx.feed_delayed_owner(child_def_id, owner);
615+
let is_method_or_free = if let Some(info) = resolver.delegation_infos.get(&parent_del)
616+
&& let Some(sig_id) = resolver
617+
.partial_res_map
618+
.get(&info.resolution_node)
619+
.and_then(|r| r.expect_full_res().opt_def_id())
620+
{
621+
tcx.opt_associated_item(sig_id).is_some_and(|a| a.is_method())
622+
|| matches!(tcx.def_kind(sig_id), DefKind::Fn)
623+
} else {
624+
// If delegation is unresolved for some reason we will generate an error delegation
625+
// and some errors will be certainly emitted, so no delayed bugs should happen.
626+
return false;
627+
};
628+
629+
let (param_count, _) = delegation::param_count(tcx, parent_del.to_def_id());
630+
631+
// Should be in sync with conditions in `lower_delegation_body`.
632+
(!is_method_or_free && from_glob_or_list) || param_count == 0
633+
};
634+
635+
if !is_dead_code() {
636+
lowerer.lower_node(def_id);
637+
638+
for (child_def_id, owner) in map {
639+
// We can encounter `NonOwner` which will result in a phantom being written
640+
// to the map, however this `NonOwner` could be inserted from lowering of
641+
// other owner (for example use trees), so we do not feed delayed_owner
642+
// with Phantom as (1) it is Phantom by default, (2) we want to avoid
643+
// consistency assert during query feeding.
644+
if !matches!(owner, hir::MaybeOwner::Phantom) {
645+
tcx.feed_delayed_owner(child_def_id, owner);
646+
}
647+
}
597648
}
598649
}
599650

compiler/rustc_expand/src/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2066,7 +2066,7 @@ fn build_single_delegations<'a, Node: InvocationCollectorNode>(
20662066
ident: rename.unwrap_or(ident),
20672067
rename,
20682068
body: deleg.body.clone(),
2069-
from_glob,
2069+
from_glob_or_list: true,
20702070
})),
20712071
tokens: None,
20722072
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ pub struct ResolverAstLowering<'tcx> {
247247

248248
// Information about delegations which is used when handling recursive delegations
249249
pub delegation_infos: LocalDefIdMap<DelegationInfo>,
250+
pub defs_in_delegations_blocks: LocalDefIdMap<LocalDefId>,
250251

251252
pub disambiguators: LocalDefIdMap<Steal<PerParentDisambiguatorState>>,
252253
}

compiler/rustc_parse/src/parser/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ impl<'a> Parser<'a> {
906906
ident,
907907
rename,
908908
body: self.parse_delegation_body()?,
909-
from_glob: false,
909+
from_glob_or_list: false,
910910
}))
911911
})
912912
}

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
14621462
let parent = self.parent_scope.module.expect_local();
14631463
let expansion = self.parent_scope.expansion;
14641464
self.r.define_local(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
1465-
} else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob)
1465+
} else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob_or_list)
14661466
&& ident.name != kw::Underscore
14671467
{
14681468
// Don't add underscore names, they cannot be looked up anyway.

compiler/rustc_resolve/src/def_collector.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,39 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
5050
name: Option<Symbol>,
5151
def_kind: DefKind,
5252
span: Span,
53+
) -> TyCtxtFeed<'tcx, LocalDefId> {
54+
self.create_feed(node_id, name, def_kind, span, false)
55+
}
56+
57+
fn create_feed(
58+
&mut self,
59+
node_id: NodeId,
60+
name: Option<Symbol>,
61+
def_kind: DefKind,
62+
span: Span,
63+
is_owner: bool,
5364
) -> TyCtxtFeed<'tcx, LocalDefId> {
5465
let parent_def = self.invocation_parent.parent_def;
5566
debug!(
5667
"create_def(node_id={:?}, def_kind={:?}, parent_def={:?})",
5768
node_id, def_kind, parent_def
5869
);
59-
self.r.create_def(
70+
71+
let feed = self.r.create_def(
6072
parent_def,
6173
node_id,
6274
name,
6375
def_kind,
6476
self.parent_scope.expansion.to_expn_id(),
6577
span.with_parent(None),
66-
false,
67-
)
78+
is_owner,
79+
);
80+
81+
if let Some(last_delegation) = self.invocation_parent.last_delegation {
82+
self.r.defs_in_delegations_blocks.insert(feed.def_id(), last_delegation);
83+
}
84+
85+
feed
6886
}
6987

7088
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
@@ -86,16 +104,8 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
86104
// We only get here if the owner didn't exist yet. After the owner has been created,
87105
// future invocations of `collect_definitions` will get the owner out of the `owners`
88106
// table.
89-
let parent_def = self.invocation_parent.parent_def;
90-
let feed = self.r.create_def(
91-
parent_def,
92-
owner,
93-
name,
94-
def_kind,
95-
self.parent_scope.expansion.to_expn_id(),
96-
span.with_parent(None),
97-
true,
98-
);
107+
108+
let feed = self.create_feed(owner, name, def_kind, span, true);
99109
let tables = PerOwnerResolverData::new(owner, feed.key());
100110

101111
let orig_invoc_owner = mem::replace(&mut self.invocation_parent.owner, owner);
@@ -240,6 +250,22 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
240250
);
241251
}
242252

253+
fn visit_delegation(&mut self, node: &'a Delegation) {
254+
// Do not map defs in path (i.e., consts with blocks), consider only
255+
// delegation's block which is its first argument.
256+
visit::walk_path(self, &node.path);
257+
node.qself.as_ref().inspect(|qself| visit::walk_qself(self, qself));
258+
259+
let orig_last_delegation = mem::replace(
260+
&mut self.invocation_parent.last_delegation,
261+
Some(self.invocation_parent.parent_def),
262+
);
263+
264+
node.body.as_ref().inspect(|block| self.brg_visit_block(block));
265+
266+
self.invocation_parent.last_delegation = orig_last_delegation;
267+
}
268+
243269
fn visit_block(&mut self, block: &'a Block) {
244270
self.brg_visit_block(block);
245271
}

0 commit comments

Comments
 (0)