Implement .use keyword as an alias of clone

This commit is contained in:
Santiago Pastorino 2024-10-02 16:35:37 -03:00
parent 0cf8dbc96c
commit 05c516446a
No known key found for this signature in database
GPG Key ID: 8131A24E0C79EFAF
36 changed files with 247 additions and 24 deletions

View File

@ -1399,6 +1399,7 @@ impl Expr {
// Never need parens
ExprKind::Array(_)
| ExprKind::Await(..)
| ExprKind::Use(..)
| ExprKind::Block(..)
| ExprKind::Call(..)
| ExprKind::ConstBlock(_)
@ -1588,6 +1589,8 @@ pub enum ExprKind {
Gen(CaptureBy, P<Block>, GenBlockKind, Span),
/// An await expression (`my_future.await`). Span is of await keyword.
Await(P<Expr>, Span),
/// A use expression (`x.use`). Span is of use keyword.
Use(P<Expr>, Span),
/// A try block (`try { ... }`).
TryBlock(P<Block>),

View File

@ -1745,6 +1745,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
vis.visit_expr(expr);
vis.visit_span(await_kw_span);
}
ExprKind::Use(expr, use_kw_span) => {
vis.visit_expr(expr);
vis.visit_span(use_kw_span);
}
ExprKind::Assign(el, er, span) => {
vis.visit_expr(el);
vis.visit_expr(er);

View File

@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
Assign(e, _, _)
| AssignOp(_, e, _)
| Await(e, _)
| Use(e, _)
| Binary(_, e, _)
| Call(e, _)
| Cast(e, _)
@ -224,6 +225,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| Lit(_)
| Type(_, _)
| Await(_, _)
| Use(_, _)
| Field(_, _)
| Index(_, _, _)
| Underscore

View File

@ -1211,6 +1211,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
}
ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)),
ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)),
ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)),
ExprKind::Assign(lhs, rhs, _span) => {
try_visit!(visitor.visit_expr(lhs));
try_visit!(visitor.visit_expr(rhs));

View File

@ -207,6 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
),
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),
ExprKind::Closure(box Closure {
binder,
capture_clause,
@ -1067,6 +1068,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
}
fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
}
fn lower_expr_closure(
&mut self,
binder: &ClosureBinder,

View File

@ -574,6 +574,14 @@ impl<'a> State<'a> {
);
self.word(".await");
}
ast::ExprKind::Use(expr, _) => {
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Unambiguous,
fixup,
);
self.word(".use");
}
ast::ExprKind::Assign(lhs, rhs, _) => {
self.print_expr_cond_paren(
lhs,

View File

@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::AssignOp(_, _, _)
| ExprKind::Gen(_, _, _, _)
| ExprKind::Await(_, _)
| ExprKind::Use(_, _)
| ExprKind::Block(_, _)
| ExprKind::Break(_, _)
| ExprKind::Closure(_)

View File

@ -2166,6 +2166,7 @@ impl Expr<'_> {
| ExprKind::Tup(_)
| ExprKind::Type(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Use(..)
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
ExprKind::DropTemps(expr, ..) => expr.precedence(),
@ -2212,6 +2213,7 @@ impl Expr<'_> {
ExprKind::Path(QPath::TypeRelative(..))
| ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Use(..)
| ExprKind::Struct(..)
| ExprKind::Tup(..)
| ExprKind::If(..)
@ -2285,7 +2287,9 @@ impl Expr<'_> {
pub fn can_have_side_effects(&self) -> bool {
match self.peel_drop_temps().kind {
ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false,
ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => {
false
}
ExprKind::Type(base, _)
| ExprKind::Unary(_, base)
| ExprKind::Field(base, _)
@ -2547,6 +2551,8 @@ pub enum ExprKind<'hir> {
///
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
/// An use expression (e.g., `var.use`).
Use(&'hir Expr<'hir>, Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(&'hir [Expr<'hir>]),
/// A binary operation (e.g., `a + b`, `a * b`).

View File

@ -821,6 +821,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
try_visit!(visitor.visit_expr(receiver));
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Use(expr, _) => {
try_visit!(visitor.visit_expr(expr));
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
try_visit!(visitor.visit_expr(left_expression));
try_visit!(visitor.visit_expr(right_expression));

View File

@ -1544,6 +1544,10 @@ impl<'a> State<'a> {
hir::ExprKind::MethodCall(segment, receiver, args, _) => {
self.print_expr_method_call(segment, receiver, args);
}
hir::ExprKind::Use(expr, _) => {
self.print_expr(expr);
self.word(".use");
}
hir::ExprKind::Binary(op, lhs, rhs) => {
self.print_expr_binary(op, lhs, rhs);
}

View File

@ -362,6 +362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Any expression child of these expressions constitute reads.
ExprKind::Array(_)
| ExprKind::Call(_, _)
| ExprKind::Use(_, _)
| ExprKind::MethodCall(_, _, _, _)
| ExprKind::Tup(_)
| ExprKind::Binary(_, _, _)
@ -552,6 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
ExprKind::Block(body, _) => self.check_expr_block(body, expected),
ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected),
ExprKind::MethodCall(segment, receiver, args, _) => {
self.check_expr_method_call(expr, segment, receiver, args, expected)
}
@ -1616,6 +1618,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
/// Checks use `x.use`.
fn check_expr_use(
&self,
used_expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
self.check_expr_with_expectation(used_expr, expected)
}
fn check_expr_cast(
&self,
e: &'tcx hir::Expr<'tcx>,

View File

@ -366,6 +366,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
self.consume_exprs(args)?;
}
hir::ExprKind::Use(expr, _) => {
self.consume_expr(expr)?;
}
hir::ExprKind::MethodCall(.., receiver, args, _) => {
// callee.m(args)
self.consume_expr(receiver)?;
@ -1386,6 +1390,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
hir::ExprKind::AddrOf(..)
| hir::ExprKind::Call(..)
| hir::ExprKind::Use(..)
| hir::ExprKind::Assign(..)
| hir::ExprKind::AssignOp(..)
| hir::ExprKind::Closure { .. }

View File

@ -159,7 +159,10 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
ExprKind::Path(..) => false,
// Calls return rvalues.
ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Use(..)
| ExprKind::Binary(..) => true,
// Inner blocks are rvalues.
ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,

View File

@ -312,6 +312,14 @@ pub enum ExprKind<'tcx> {
/// (e.g. `foo(a, b)` in `x.foo(a, b)`).
fn_span: Span,
},
/// A use expression `x.use`.
ByUse {
/// The expression on which use is applied.
expr: ExprId,
/// The span of use, without the dot and receiver
/// (e.g. `use` in `x.use`).
span: Span,
},
/// A *non-overloaded* dereference.
Deref {
arg: ExprId,

View File

@ -59,6 +59,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
visitor.visit_expr(&visitor.thir()[arg]);
}
}
ByUse { expr, span: _ } => {
visitor.visit_expr(&visitor.thir()[expr]);
}
Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
visitor.visit_expr(&visitor.thir()[lhs]);

View File

@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
// these are not places, so we need to make a temporary.
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));

View File

@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
block.and(Rvalue::Use(operand))
}
ExprKind::ByUse { expr, span: _ } => {
let operand = unpack!(
block =
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
);
block.and(Rvalue::Use(operand))
}
}
}

View File

@ -56,6 +56,7 @@ impl Category {
| ExprKind::RawBorrow { .. }
| ExprKind::Yield { .. }
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
ExprKind::Array { .. }

View File

@ -4,10 +4,12 @@ use rustc_ast::{AsmMacro, InlineAsmOptions};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
use rustc_span::DUMMY_SP;
use rustc_span::source_map::Spanned;
use tracing::{debug, instrument};
@ -289,6 +291,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.diverge_from(block);
success.unit()
}
ExprKind::ByUse { expr, span } => {
let place = unpack!(block = this.as_place(block, expr));
let ty = place.ty(&this.local_decls, this.tcx).ty;
// Convert `expr.use` to a call like `Clone::clone(&expr)`
let success = this.cfg.start_new_block();
let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
let ref_place = this.temp(ref_ty, span);
this.cfg.push_assign(
block,
source_info,
ref_place,
Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place),
);
this.cfg.terminate(
block,
source_info,
TerminatorKind::Call {
func,
args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }].into(),
destination,
target: Some(success),
unwind: UnwindAction::Unreachable,
call_source: CallSource::Misc,
fn_span: expr_span,
},
);
success.unit()
}
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
ExprKind::Borrow { arg, borrow_kind } => {
// We don't do this in `as_rvalue` because we use `as_place`

View File

@ -451,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::Tuple { .. }
| ExprKind::Unary { .. }
| ExprKind::Call { .. }
| ExprKind::ByUse { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::Break { .. }

View File

@ -464,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
}
}
hir::ExprKind::Use(expr, span) => {
ExprKind::ByUse { expr: self.mirror_expr(expr), span }
}
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
}

View File

@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
| Borrow { .. }
| Box { .. }
| Call { .. }
| ByUse { .. }
| Closure { .. }
| ConstBlock { .. }
| ConstParam { .. }

View File

@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "}", depth_lvl);
}
ByUse { expr, span } => {
print_indented!(self, "ByUse {", depth_lvl);
print_indented!(self, "expr:", depth_lvl + 1);
self.print_expr(*expr, depth_lvl + 2);
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
print_indented!(self, "}", depth_lvl);
}
Deref { arg } => {
print_indented!(self, "Deref {", depth_lvl);
self.print_expr(*arg, depth_lvl + 1);

View File

@ -348,6 +348,9 @@ parse_incorrect_use_of_await = incorrect use of `await`
parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation
parse_incorrect_use_of_use = incorrect use of `use`
.parentheses_suggestion = `use` is not a method call, try removing the parentheses
parse_incorrect_visibility_restriction = incorrect visibility restriction
.help = some possible visibility restrictions are:
`pub(crate)`: visible only on the current crate

View File

@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_incorrect_use_of_use)]
pub(crate) struct IncorrectUseOfUse {
#[primary_span]
#[suggestion(
parse_parentheses_suggestion,
style = "verbose",
code = "",
applicability = "machine-applicable"
)]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
parse_incorrect_use_of_await_postfix_suggestion,

View File

@ -38,8 +38,8 @@ use crate::errors::{
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
@ -1991,7 +1991,7 @@ impl<'a> Parser<'a> {
self.parse_expr()
}
.map_err(|mut err| {
err.span_label(await_sp, "while parsing this incorrect await expression");
err.span_label(await_sp, format!("while parsing this incorrect await expression"));
err
})?;
Ok((expr.span, expr, is_question))
@ -2030,6 +2030,21 @@ impl<'a> Parser<'a> {
self.dcx().emit_err(IncorrectUseOfAwait { span });
}
}
///
/// If encountering `x.use()`, consumes and emits an error.
pub(super) fn recover_from_use(&mut self) {
if self.token == token::OpenDelim(Delimiter::Parenthesis)
&& self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
{
// var.use()
let lo = self.token.span;
self.bump(); // (
let span = lo.to(self.token.span);
self.bump(); // )
self.dcx().emit_err(IncorrectUseOfUse { span });
}
}
pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
let is_try = self.token.is_keyword(kw::Try);

View File

@ -778,6 +778,7 @@ impl<'a> Parser<'a> {
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_, _) => "`.await`",
ExprKind::Use(_, _) => "`.use`",
ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
ExprKind::Err(_) => return Ok(with_postfix),
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> {
return Ok(self.mk_await_expr(self_arg, lo));
}
if self.eat_keyword(exp!(Use)) {
let use_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
return Ok(self.mk_use_expr(self_arg, lo));
}
// Post-fix match
if self.eat_keyword(exp!(Match)) {
let match_span = self.prev_token.span;
@ -3818,6 +3825,13 @@ impl<'a> Parser<'a> {
await_expr
}
fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
let span = lo.to(self.prev_token.span);
let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
self.recover_from_use();
use_expr
}
pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
}
@ -3966,6 +3980,7 @@ impl MutVisitor for CondChecker<'_> {
}
ExprKind::Unary(_, _)
| ExprKind::Await(_, _)
| ExprKind::Use(_, _)
| ExprKind::AssignOp(_, _, _)
| ExprKind::Range(_, _, _)
| ExprKind::Try(_)

View File

@ -328,6 +328,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Array,
Call,
MethodCall,
Use,
Tup,
Binary,
Unary,
@ -626,7 +627,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
(self, e, e.kind, None, ast, Expr, ExprKind),
[
Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign,
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy

View File

@ -426,6 +426,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::Array(..)
| hir::ExprKind::Call(..)
| hir::ExprKind::MethodCall(..)
| hir::ExprKind::Use(..)
| hir::ExprKind::Tup(..)
| hir::ExprKind::Binary(..)
| hir::ExprKind::AddrOf(..)
@ -1031,6 +1032,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_expr(receiver, succ)
}
hir::ExprKind::Use(expr, _) => {
let succ = self.check_is_ty_uninhabited(expr, succ);
self.propagate_through_expr(expr, succ)
}
hir::ExprKind::Tup(exprs) => self.propagate_through_exprs(exprs, succ),
hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
@ -1418,6 +1424,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
// no correctness conditions related to liveness
hir::ExprKind::Call(..)
| hir::ExprKind::MethodCall(..)
| hir::ExprKind::Use(..)
| hir::ExprKind::Match(..)
| hir::ExprKind::Loop(..)
| hir::ExprKind::Index(..)

View File

@ -182,6 +182,7 @@ impl CheckInlineAssembly {
| ExprKind::Array(..)
| ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Use(..)
| ExprKind::Tup(..)
| ExprKind::Binary(..)
| ExprKind::Unary(..)

View File

@ -14,6 +14,8 @@ ty_utils_borrow_not_supported = borrowing is not supported in generic constants
ty_utils_box_not_supported = allocations are not allowed in generic constants
ty_utils_by_use_not_supported = .use is not allowed in generic constants
ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
ty_utils_const_block_not_supported = const blocks are not supported in generic constants

View File

@ -230,7 +230,9 @@ fn recurse_build<'tcx>(
error(GenericConstantTooComplexSub::LoopNotSupported(node.span))?
}
ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?,
ExprKind::ByUse { .. } => {
error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))?
}
ExprKind::Unary { .. } => unreachable!(),
// we handle valid unary/binary ops above
ExprKind::Binary { .. } => {
@ -317,6 +319,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
| thir::ExprKind::Box { .. }
| thir::ExprKind::If { .. }
| thir::ExprKind::Call { .. }
| thir::ExprKind::ByUse { .. }
| thir::ExprKind::Deref { .. }
| thir::ExprKind::Binary { .. }
| thir::ExprKind::LogicalOp { .. }

View File

@ -55,6 +55,8 @@ pub(crate) enum GenericConstantTooComplexSub {
BoxNotSupported(#[primary_span] Span),
#[label(ty_utils_binary_not_supported)]
BinaryNotSupported(#[primary_span] Span),
#[label(ty_utils_by_use_not_supported)]
ByUseNotSupported(#[primary_span] Span),
#[label(ty_utils_logical_op_not_supported)]
LogicalOpNotSupported(#[primary_span] Span),
#[label(ty_utils_assign_not_supported)]

View File

@ -0,0 +1,14 @@
//@ check-pass
#![feature(ergonomic_clones)]
fn basic_test(x: i32) -> i32 {
x.use.use.abs()
}
fn do_not_move_test(x: String) -> String {
let s = x.use;
x
}
fn main() {}

View File

@ -1,18 +1,18 @@
fn ergonomic_clone(x: i32) -> i32 {
x.use
//~^ ERROR expected identifier, found keyword `use`
//~| ERROR `i32` is a primitive type and therefore doesn't have fields [E0610]
//~^ ERROR `.use` calls are experimental [E0658]
}
fn ergonomic_closure_clone() {
let s1 = String::from("hi!");
let s2 = use || {
//~^ ERROR expected expression, found keyword `use`
//~^ ERROR incorrect use of `use`
s1
};
let s3 = use || {
//~^ ERROR incorrect use of `use`
s1
};
}

View File

@ -1,26 +1,49 @@
error: expected identifier, found keyword `use`
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
error: incorrect use of `use`
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
|
LL | x.use
| ^^^ expected identifier, found keyword
LL | let s2 = use || {
| ______________^
LL | |
LL | | s1
LL | | };
| |_____^
|
help: escape `use` to use it as an identifier
help: `use` is a postfix operation
|
LL ~ let s2 = || {
LL |
LL | s1
LL ~ }.use;
|
LL | x.r#use
| ++
error: expected expression, found keyword `use`
--> $DIR/feature-gate-ergonomic-clones.rs:10:14
error: incorrect use of `use`
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
LL | let s3 = use || {
| ______________^
LL | |
LL | | s1
LL | | };
| |_____^
|
help: `use` is a postfix operation
|
LL ~ let s3 = || {
LL |
LL | s1
LL ~ }.use;
|
LL | let s2 = use || {
| ^^^ expected expression
error[E0610]: `i32` is a primitive type and therefore doesn't have fields
error[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
|
LL | x.use
| ^^^
|
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0610`.
For more information about this error, try `rustc --explain E0658`.