mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 12:36:47 +00:00
Implement .use keyword as an alias of clone
This commit is contained in:
parent
0cf8dbc96c
commit
05c516446a
@ -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>),
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
| ExprKind::AssignOp(_, _, _)
|
||||
| ExprKind::Gen(_, _, _, _)
|
||||
| ExprKind::Await(_, _)
|
||||
| ExprKind::Use(_, _)
|
||||
| ExprKind::Block(_, _)
|
||||
| ExprKind::Break(_, _)
|
||||
| ExprKind::Closure(_)
|
||||
|
@ -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`).
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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 { .. }
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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]);
|
||||
|
@ -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)));
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@ impl Category {
|
||||
| ExprKind::RawBorrow { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::Call { .. }
|
||||
| ExprKind::ByUse { .. }
|
||||
| ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
|
||||
|
||||
ExprKind::Array { .. }
|
||||
|
@ -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`
|
||||
|
@ -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 { .. }
|
||||
|
@ -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) }
|
||||
}
|
||||
|
@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
| Borrow { .. }
|
||||
| Box { .. }
|
||||
| Call { .. }
|
||||
| ByUse { .. }
|
||||
| Closure { .. }
|
||||
| ConstBlock { .. }
|
||||
| ConstParam { .. }
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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(_)
|
||||
|
@ -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
|
||||
|
@ -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(..)
|
||||
|
@ -182,6 +182,7 @@ impl CheckInlineAssembly {
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::Use(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Unary(..)
|
||||
|
@ -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
|
||||
|
@ -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 { .. }
|
||||
|
@ -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)]
|
||||
|
14
tests/ui/ergonomic-clones/dotuse.rs
Normal file
14
tests/ui/ergonomic-clones/dotuse.rs
Normal 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() {}
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user