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
44 changes: 25 additions & 19 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,11 +408,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let block_id = self.lower_body(|this| {
let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count);
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
let mut stmts: &[hir::Stmt<'hir>] = &[];

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

let generate_arg =
|this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span);

let arg = if let Some(block) = block
&& idx == 0
{
Expand All @@ -424,10 +428,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
self_resolver.visit_block(block);
// Target expr needs to lower `self` path.
this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
this.lower_target_expr(&block)

// Lower with `HirId::INVALID` as we will use only expr and stmts.
// FIXME(fn_delegation): Alternatives for target expression lowering:
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
let block = this.lower_block_noalloc(HirId::INVALID, block, false);

stmts = block.stmts;

// The behavior of the delegation's target expression differs from the
// behavior of the usual block, where if there is no final expression
// the `()` is returned. In case of the similar situation in delegation
// (no final expression) we propagate first argument instead of replacing
// it with `()`.
if let Some(&expr) = block.expr { expr } else { generate_arg(this) }
} else {
this.generate_arg(is_method, idx, param.pat.hir_id, span)
generate_arg(this)
};

args.push(arg);
}

Expand All @@ -439,11 +457,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
if param_count == 0
&& let Some(block) = block
{
args.push(this.lower_target_expr(&block));
args.push(this.lower_block_expr(&block));
}

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

call_expr_id = hir_id;

Expand All @@ -455,22 +473,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
(block_id, call_expr_id)
}

// FIXME(fn_delegation): Alternatives for target expression lowering:
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
if let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind
{
return self.lower_expr_mut(expr);
}

let block = self.lower_block(block, false);
self.mk_expr(hir::ExprKind::Block(block, None), block.span)
}

fn finalize_body_lowering(
&mut self,
delegation: &Delegation,
stmts: &'hir [hir::Stmt<'hir>],
args: Vec<hir::Expr<'hir>>,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
Expand Down Expand Up @@ -522,7 +528,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span));

let block = self.arena.alloc(hir::Block {
stmts: &[],
stmts,
expr: Some(call),
hir_id: self.next_id(),
rules: hir::BlockCheckMode::DefaultBlock,
Expand Down Expand Up @@ -587,7 +593,7 @@ impl<'hir> LoweringContext<'_, 'hir> {

let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span));
let args = if let Some(block) = delegation.body.as_ref() {
this.arena.alloc_slice(&[this.lower_target_expr(block)])
this.arena.alloc_slice(&[this.lower_block_expr(block)])
Comment thread
aerooneqq marked this conversation as resolved.
} else {
&mut []
};
Expand Down
54 changes: 26 additions & 28 deletions tests/pretty/delegation-inline-attribute.pp
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,32 @@
fn foo(self: _)
->
_ {
Trait::foo(
// Check that #[inline(hint)] is added to foo0 reuse inside another reuse

// Check that #[inline(hint)] is added when other attributes present in inner reuse

// Check that #[inline(never)] is preserved in inner reuse

// Check that #[inline(always)] is preserved in inner reuse

// Check that #[inline(never)] is preserved when there are other attributes in inner reuse
{
#[attr = Inline(Hint)]
fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) }
#[attr = Cold]
#[attr = MustUse]
#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}]
#[attr = Inline(Hint)]
fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) }
#[attr = Inline(Never)]
fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) }
#[attr = Inline(Always)]
fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) }
#[attr = Cold]
#[attr = MustUse]
#[attr = Inline(Never)]
#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}]
fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) }
})
// 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 = Cold]
#[attr = MustUse]
#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}]
#[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 = Cold]
#[attr = MustUse]
#[attr = Inline(Never)]
#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}]
fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) }
Trait::foo(self)
}

// Check that #[inline(hint)] is added when there are other attributes present in trait reuse
Expand Down
2 changes: 1 addition & 1 deletion tests/pretty/hir-delegation.pp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

trait G {
#[attr = Inline(Hint)]
fn b<C>(arg0: _) -> _ { b::<C>({ }) }
fn b<C>(arg0: _) -> _ { b::<C>(arg0) }
}

mod m {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/delegation/ice-issue-124347.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/ice-issue-124347.rs:4:18
|
LL | reuse Trait::foo { &self.0 }
| ^^^ ------- unexpected argument
| ^^^ ----------- unexpected argument
|
note: associated function defined here
--> $DIR/ice-issue-124347.rs:4:18
Expand All @@ -24,7 +24,7 @@ LL | reuse Trait::foo { &self.0 }
help: remove the extra argument
|
LL - reuse Trait::foo { &self.0 }
LL + reuse Trait::fo&self.0 }
LL + reuse Trait::fo{ &self.0 }
|

warning: function cannot return without recursing
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/delegation/inner-attr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/inner-attr.rs:5:7
|
LL | reuse a as b { #![rustc_dummy] self }
| ^ ---- unexpected argument
| ^ ------------------------ unexpected argument
|
note: function defined here
--> $DIR/inner-attr.rs:3:4
Expand All @@ -23,7 +23,7 @@ LL | fn a() {}
help: remove the extra argument
|
LL - reuse a as b { #![rustc_dummy] self }
LL + reuse self }
LL + reuse { #![rustc_dummy] self }
|

error: aborting due to 2 previous errors
Expand Down
58 changes: 58 additions & 0 deletions tests/ui/delegation/self-coercion-block-errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Test different scenarios with impossible adjustments due to blocks
// or no-op target expressions.

#![feature(fn_delegation)]

trait Trait: Sized {
fn by_value(self) -> i32 { 1 }
fn by_mut_ref(&mut self) -> i32 { 2 }
fn by_ref(&self) -> i32 { 3 }
}

struct F;
impl Trait for F {}

struct Struct(F);
reuse impl Trait for Struct { self.0 }

struct S(F);
reuse impl Trait for S { { self.0 } }
//~^ ERROR: cannot move out of `self` which is behind a shared reference
//~| ERROR: cannot move out of `self` which is behind a mutable reference

struct S1(F);
reuse impl Trait for S1 { { { { { { self.0 } } } } } }
//~^ ERROR: cannot move out of `self` which is behind a shared reference
//~| ERROR: cannot move out of `self` which is behind a mutable reference

struct S2(F);
reuse impl Trait for S2 { }
//~^ WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]

struct S3(F);
reuse impl Trait for S3 { (); }
//~^ WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]

struct S4(F);
reuse impl Trait for S4 { println!(); }
//~^ WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]

struct S5(F);
reuse impl Trait for S5 { fn foo() {} }
//~^ WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]

struct S6(F);
reuse impl Trait for S6;
//~^ WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]
//~| WARN: function cannot return without recursing [unconditional_recursion]

fn main() {}
Loading
Loading