diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 11fc409cf4333..002435b2d0327 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P, Span), + /// A use expression (`x.use`). Span is of use keyword. + Use(P, Span), /// A try block (`try { ... }`). TryBlock(P), @@ -1757,8 +1760,17 @@ pub enum CaptureBy { /// The span of the `move` keyword. move_kw: Span, }, - /// `move` keyword was not specified. + /// `move` or `use` keywords were not specified. Ref, + /// `use |x| y + x`. + /// + /// Note that if you have a regular closure like `|| x.use`, this will *not* result + /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type + /// of `x` and treat `x.use` as either a copy/clone/move as appropriate. + Use { + /// The span of the `use` keyword. + use_kw: Span, + }, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f14646b5a99a5..ee894db7b966b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1745,6 +1745,10 @@ pub fn walk_expr(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); @@ -1895,6 +1899,9 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { CaptureBy::Value { move_kw } => { vis.visit_span(move_kw); } + CaptureBy::Use { use_kw } => { + vis.visit_span(use_kw); + } } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 64f2a98b8a6fc..e43d78f6e7217 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -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> { | Lit(_) | Type(_, _) | Await(_, _) + | Use(_, _) | Field(_, _) | Index(_, _, _) | Underscore diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37139e664f3d2..43ffbe9b071d6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -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)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c70fcdc84a384..acf35b75e4df3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,7 +13,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; @@ -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, @@ -483,7 +484,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); + self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { AstP(Expr { @@ -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, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f583206802845..1c4edd8348f44 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -494,7 +494,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -774,7 +774,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let _def_id = self.create_def( self.current_hir_id_owner.def_id, param, - kw::UnderscoreLifetime, + Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, ident.span, ); @@ -2089,8 +2089,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 728981dea5f83..07cc64a1358ee 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, LangItem}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DesugaringKind, Ident, Span, kw}; +use rustc_span::{DesugaringKind, Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -523,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're generating a range end that didn't exist in the AST, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let unstable_span = self.mark_span_with_reason( diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index de11fe770c5b3..31ff102c127a3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -489,6 +489,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); + gate_all!(ergonomic_clones, "ergonomic clones are experimental"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 496323a35b8d9..e3c41f117abb8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -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, @@ -885,6 +893,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { match capture_clause { ast::CaptureBy::Value { .. } => self.word_space("move"), + ast::CaptureBy::Use { .. } => self.word_space("use"), ast::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 30e94b0bec708..c9be5575da5ce 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { .expect_closure(); let span = match capture_clause { rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), + rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(), rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(), }; diag.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index be4a7736b1c20..145137f923691 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) => { capture_reason = format!("mutable borrow of `{upvar}`"); } - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { capture_reason = format!("possible mutation of `{upvar}`"); } _ => bug!("upvar `{upvar}` borrowed, but not mutably"), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 68e0ab0933e61..64a533e05ffd4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1490,14 +1490,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); - if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind - { - propagate_closure_used_mut_place(self, source); - } else { - bug!( - "closures should only capture user variables \ + match stmt.kind { + StatementKind::Assign(box ( + _, + Rvalue::Ref(_, _, source) + | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)), + )) => { + propagate_closure_used_mut_place(self, source); + } + _ => { + bug!( + "closures should only capture user variables \ or references to user variables" - ); + ); + } } } _ => propagate_closure_used_mut_place(self, place), diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index bb9dc651cec25..a949ab94f3ad7 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::AssignOp(_, _, _) | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | ExprKind::Closure(_) diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 717baebcd8cd6..9fe6baa3d2573 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -16,7 +16,7 @@ use crate::context::CodegenCx; use crate::intrinsic::ArgAbiExt; use crate::type_of::LayoutGccExt; -impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { let func = self.current_func(); let param = func.get_param(index as i32); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 628e34badf9d3..a63da6b6e27d8 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -59,7 +59,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } -impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } @@ -257,7 +257,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_gcc(self, alloc) } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index fb0ca31c54334..c514b7a428bc6 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -302,9 +302,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn const_alloc_to_gcc<'gcc, 'tcx>( - cx: &CodegenCx<'gcc, 'tcx>, - alloc: ConstAllocation<'tcx>, +pub fn const_alloc_to_gcc<'gcc>( + cx: &CodegenCx<'gcc, '_>, + alloc: ConstAllocation<'_>, ) -> RValue<'gcc> { let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index cb08723431a9a..4e0a250b5509a 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -123,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8c75125e009b9..7105933815138 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -654,7 +654,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } -impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { llvm::get_param(self.llfn(), index as c_uint) } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 66723cbf88206..e614115f64b9f 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, }; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; -use crate::common::AsCCharPtr; -use crate::llvm::{self, Context, False, Module, True, Type}; -use crate::{ModuleLlvm, attributes, debuginfo}; +use crate::builder::SBuilder; +use crate::declare::declare_simple_fn; +use crate::llvm::{self, False, True, Type}; +use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, - module_llvm: &mut ModuleLlvm, + cx: SimpleCx<'_>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) { - let llcx = &*module_llvm.llcx; - let llmod = module_llvm.llmod(); - let usize = unsafe { - match tcx.sess.target.pointer_width { - 16 => llvm::LLVMInt16TypeInContext(llcx), - 32 => llvm::LLVMInt32TypeInContext(llcx), - 64 => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), - } + let usize = match tcx.sess.target.pointer_width { + 16 => cx.type_i16(), + 32 => cx.type_i32(), + 64 => cx.type_i64(), + tws => bug!("Unsupported target word size for int: {}", tws), }; - let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; - let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; + let i8 = cx.type_i8(); + let i8p = cx.type_ptr(); if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen( let from_name = global_fn_name(method.name); let to_name = default_fn_name(method.name); - create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); } } // rust alloc error handler create_wrapper_function( tcx, - llcx, - llmod, + &cx, "__rust_alloc_error_handler", alloc_error_handler_name(alloc_error_handler_kind), &[usize, usize], // size, align @@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen( unsafe { // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::set_initializer(ll_g, llval); } if tcx.sess.opts.debuginfo != DebugInfo::None { - let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); + let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod); debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx); dbg_cx.finalize(tcx.sess); } @@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen( fn create_wrapper_function( tcx: TyCtxt<'_>, - llcx: &Context, - llmod: &Module, + cx: &SimpleCx<'_>, from_name: &str, to_name: &str, args: &[&Type], output: Option<&Type>, no_return: bool, ) { - unsafe { - let ty = llvm::LLVMFunctionType( - output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)), - args.as_ptr(), - args.len() as c_uint, - False, - ); - let llfn = llvm::LLVMRustGetOrInsertFunction( - llmod, - from_name.as_c_char_ptr(), - from_name.len(), - ty, - ); - let no_return = if no_return { - // -> ! DIFlagNoReturn - let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); - Some(no_return) - } else { - None - }; - - llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - - if tcx.sess.must_emit_unwind_tables() { - let uwtable = - attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); - } + let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void())); + let llfn = declare_simple_fn( + &cx, + from_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ty, + ); + let no_return = if no_return { + // -> ! DIFlagNoReturn + let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); + Some(no_return) + } else { + None + }; - let callee = - llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); - - let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); - llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) - .collect::>(); - let ret = llvm::LLVMBuildCallWithOperandBundles( - llbuilder, - ty, - callee, - args.as_ptr(), - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - c"".as_ptr(), - ); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - llvm::LLVMBuildRet(llbuilder, ret); - } else { - llvm::LLVMBuildRetVoid(llbuilder); - } - llvm::LLVMDisposeBuilder(llbuilder); + if tcx.sess.must_emit_unwind_tables() { + let uwtable = + attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); + } + + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; + + let mut bx = SBuilder::build(&cx, llbb); + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e8a697431571f..88daa02574048 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1,6 +1,5 @@ use std::assert_matches::assert_matches; -use libc::{c_char, c_uint}; use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -483,12 +482,13 @@ pub(crate) fn inline_asm_call<'ll>( debug!("Asm Output Type: {:?}", output); let fty = bx.cx.type_func(&argtys, output); - unsafe { - // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()); - debug!("constraint verification result: {:?}", constraints_ok); - if constraints_ok { - let v = llvm::LLVMRustInlineAsm( + // Ask LLVM to verify that the constraints are well-formed. + let constraints_ok = + unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) }; + debug!("constraint verification result: {:?}", constraints_ok); + if constraints_ok { + let v = unsafe { + llvm::LLVMRustInlineAsm( fty, asm.as_c_char_ptr(), asm.len(), @@ -498,54 +498,50 @@ pub(crate) fn inline_asm_call<'ll>( alignstack, dia, can_throw, - ); - - let call = if !labels.is_empty() { - assert!(catch_funclet.is_none()); - bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) - } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) - } else { - bx.call(fty, None, None, v, inputs, None, None) - }; + ) + }; - // Store mark in a metadata node so we can map LLVM errors - // back to source locations. See #17552. - let key = "srcloc"; - let kind = llvm::LLVMGetMDKindIDInContext( - bx.llcx, - key.as_ptr().cast::(), - key.len() as c_uint, - ); + let call = if !labels.is_empty() { + assert!(catch_funclet.is_none()); + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) + } else if let Some((catch, funclet)) = catch_funclet { + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + } else { + bx.call(fty, None, None, v, inputs, None, None) + }; - // `srcloc` contains one 64-bit integer for each line of assembly code, - // where the lower 32 bits hold the lo byte position and the upper 32 bits - // hold the hi byte position. - let mut srcloc = vec![]; - if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { - // LLVM inserts an extra line to add the ".intel_syntax", so add - // a dummy srcloc entry for it. - // - // Don't do this if we only have 1 line span since that may be - // due to the asm template string coming from a macro. LLVM will - // default to the first srcloc for lines that don't have an - // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); - } - srcloc.extend(line_spans.iter().map(|span| { - llvm::LLVMValueAsMetadata(bx.const_u64( - u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), - )) - })); - let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); - let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); - llvm::LLVMSetMetadata(call, kind, md); + // Store mark in a metadata node so we can map LLVM errors + // back to source locations. See #17552. + let key = "srcloc"; + let kind = bx.get_md_kind_id(key); - Some(call) - } else { - // LLVM has detected an issue with our constraints, bail out - None + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. + let mut srcloc = vec![]; + if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata( + bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), + ) + })); + let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; + let md = bx.get_metadata_value(md); + llvm::LLVMSetMetadata(call, kind, md); + + Some(call) + } else { + // LLVM has detected an issue with our constraints, bail out + None } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3f20350d0efd5..55d34f5f2efe2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -30,7 +30,7 @@ use tracing::{debug, instrument}; use crate::abi::FnAbiLlvmExt; use crate::common::Funclet; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, }; @@ -40,15 +40,15 @@ use crate::value::Value; use crate::{attributes, llvm_util}; #[must_use] -pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow>> { +pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow>> { pub llbuilder: &'ll mut llvm::Builder<'ll>, - pub cx: &'a CX, + pub cx: &'a GenericCx<'ll, CX>, } -pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>; -pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>; +pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>; +pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, FullCx<'ll, 'tcx>>; -impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { fn drop(&mut self) { unsafe { llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _)); @@ -57,7 +57,7 @@ impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { } impl<'a, 'll> SBuilder<'a, 'll> { - fn call( + pub(crate) fn call( &mut self, llty: &'ll Type, llfn: &'ll Value, @@ -87,79 +87,36 @@ impl<'a, 'll> SBuilder<'a, 'll> { }; call } +} - fn with_scx(scx: &'a SimpleCx<'ll>) -> Self { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self { // Create a fresh builder from the simple context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) }; - SBuilder { llbuilder, cx: scx } + let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) }; + GenericBuilder { llbuilder, cx: scx } } -} -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) } } - fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + pub(crate) fn ret_void(&mut self) { + llvm::LLVMBuildRetVoid(self.llbuilder); } - fn ret(&mut self, v: &'ll Value) { + pub(crate) fn ret(&mut self, v: &'ll Value) { unsafe { llvm::LLVMBuildRet(self.llbuilder, v); } } -} -impl<'a, 'll> SBuilder<'a, 'll> { - fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> { - let bx = SBuilder::with_scx(cx); + + pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self { + let bx = Self::with_cx(cx); unsafe { llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); } bx } - - fn check_call<'b>( - &mut self, - typ: &str, - fn_ty: &'ll Type, - llfn: &'ll Value, - args: &'b [&'ll Value], - ) -> Cow<'b, [&'ll Value]> { - assert!( - self.cx.type_kind(fn_ty) == TypeKind::Function, - "builder::{typ} not passed a function, but {fn_ty:?}" - ); - - let param_tys = self.cx.func_params_types(fn_ty); - - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) - .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); - - if all_args_match { - return Cow::Borrowed(args); - } - - let casted_args: Vec<_> = iter::zip(param_tys, args) - .enumerate() - .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.cx.val_ty(actual_val); - if expected_ty != actual_ty { - debug!( - "type mismatch in function call of {:?}. \ - Expected {:?} for param {}, got {:?}; injecting bitcast", - llfn, expected_ty, i, actual_ty - ); - self.bitcast(actual_val, expected_ty) - } else { - actual_val - } - }) - .collect(); - - Cow::Owned(casted_args) - } } /// Empty string, to be used where LLVM expects an instruction name, indicating @@ -167,17 +124,17 @@ impl<'a, 'll> SBuilder<'a, 'll> { // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. const UNNAMED: *const c_char = c"".as_ptr(); -impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> { - type Value = as BackendTypes>::Value; - type Metadata = as BackendTypes>::Metadata; - type Function = as BackendTypes>::Function; - type BasicBlock = as BackendTypes>::BasicBlock; - type Type = as BackendTypes>::Type; - type Funclet = as BackendTypes>::Funclet; - - type DIScope = as BackendTypes>::DIScope; - type DILocation = as BackendTypes>::DILocation; - type DIVariable = as BackendTypes>::DIVariable; +impl<'ll, CX: Borrow>> BackendTypes for GenericBuilder<'_, 'll, CX> { + type Value = as BackendTypes>::Value; + type Metadata = as BackendTypes>::Metadata; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; + + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; } impl abi::HasDataLayout for Builder<'_, '_, '_> { @@ -293,9 +250,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + llvm::LLVMBuildRetVoid(self.llbuilder); } fn ret(&mut self, v: &'ll Value) { @@ -356,8 +311,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // This function handles switch instructions with more than 2 targets and it needs to // emit branch weights metadata instead of using the intrinsic. // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic. - let cold_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(1)) }; - let hot_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)) }; + let cold_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(1)); + let hot_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)); let weight = |is_cold: bool| -> &Metadata { if is_cold { cold_weight } else { hot_weight } }; @@ -1476,26 +1431,12 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> { - let bx = Builder::with_cx(cx); - unsafe { - llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); - } - bx - } - - fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self { - // Create a fresh builder from the crate context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) }; - Builder { llbuilder, cx } - } - pub(crate) fn llfn(&self) -> &'ll Value { unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) } } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { fn position_at_start(&mut self, llbb: &'ll BasicBlock) { unsafe { llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); @@ -1525,7 +1466,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } } @@ -1626,9 +1567,7 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) }; ret.expect("LLVM does not have support for catchret") } -} -impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn check_call<'b>( &mut self, typ: &str, @@ -1643,7 +1582,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let param_tys = self.cx.func_params_types(fn_ty); - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.val_ty(v))) + let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); if all_args_match { @@ -1653,7 +1592,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let casted_args: Vec<_> = iter::zip(param_tys, args) .enumerate() .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.val_ty(actual_val); + let actual_ty = self.cx.val_ty(actual_val); if expected_ty != actual_ty { debug!( "type mismatch in function call of {:?}. \ @@ -1669,12 +1608,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { Cow::Owned(casted_args) } -} -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } } + impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(intrinsic); @@ -1694,7 +1633,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]); } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { pub(crate) fn phi( &mut self, ty: &'ll Type, diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 2c7899975e3ee..71705ecb4d0f5 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -3,6 +3,7 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::back::write::ModuleConfig; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_errors::FatalError; use tracing::{debug, trace}; @@ -286,7 +287,8 @@ pub(crate) fn differentiate<'ll>( } let diag_handler = cgcx.create_dcx(); - let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx }; + + let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size); // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag? if !diff_items.is_empty() diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f264e3419e428..457e5452ce946 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,7 @@ //! Code that is useful in various codegen modules. +use std::borrow::Borrow; + use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::Primitive::Pointer; @@ -18,6 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; +use crate::context::{GenericCx, SCx}; use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -81,7 +84,7 @@ impl<'ll> Funclet<'ll> { } } -impl<'ll> BackendTypes for CodegenCx<'ll, '_> { +impl<'ll, CX: Borrow>> BackendTypes for GenericCx<'ll, CX> { type Value = &'ll Value; type Metadata = &'ll Metadata; // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`. @@ -118,7 +121,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstNull(t) } } @@ -342,7 +345,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_llvm(self, alloc, /*static*/ false) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 330e8a8f4069d..0dec0d869b0a7 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -490,7 +490,7 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = llvm::LLVMMetadataAsValue(self.llcx, meta); + let val = self.get_metadata_value(meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ed8426ae19746..9f8ec0ea526af 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,13 +1,13 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, c_char, c_uint}; +use std::marker::PhantomData; use std::ops::Deref; use std::str; -use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx}; +use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; -use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; @@ -32,9 +32,9 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::{self, AsCCharPtr}; +use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::{Metadata, MetadataType}; +use crate::llvm::Metadata; use crate::type_::Type; use crate::value::Value; use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; @@ -43,18 +43,19 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; /// However, there are various cx related functions which we want to be available to the builder and /// other compiler pieces. Here we define a small subset which has enough information and can be /// moved around more freely. -pub(crate) struct SimpleCx<'ll> { +pub(crate) struct SCx<'ll> { pub llmod: &'ll llvm::Module, pub llcx: &'ll llvm::Context, + pub isize_ty: &'ll Type, } -impl<'ll> Borrow> for CodegenCx<'ll, '_> { - fn borrow(&self) -> &SimpleCx<'ll> { +impl<'ll> Borrow> for FullCx<'ll, '_> { + fn borrow(&self) -> &SCx<'ll> { &self.scx } } -impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> Deref for FullCx<'ll, 'tcx> { type Target = SimpleCx<'ll>; #[inline] @@ -63,10 +64,25 @@ impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { } } +pub(crate) struct GenericCx<'ll, T: Borrow>>(T, PhantomData>); + +impl<'ll, T: Borrow>> Deref for GenericCx<'ll, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub(crate) type SimpleCx<'ll> = GenericCx<'ll, SCx<'ll>>; + /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM /// `llvm::Context` so that several codegen units may be processed in parallel. /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. -pub(crate) struct CodegenCx<'ll, 'tcx> { +pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>; + +pub(crate) struct FullCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, pub scx: SimpleCx<'ll>, pub use_dll_storage_attrs: bool, @@ -104,8 +120,6 @@ pub(crate) struct CodegenCx<'ll, 'tcx> { /// Mapping of scalar types to llvm types. pub scalar_lltypes: RefCell, &'ll Type>>, - pub isize_ty: &'ll Type, - /// Extra per-CGU codegen state needed when coverage instrumentation is enabled. pub coverage_cx: Option>, pub dbg_cx: Option>, @@ -579,33 +593,33 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { None }; - let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits()); - - CodegenCx { - tcx, - scx: SimpleCx { llcx, llmod }, - use_dll_storage_attrs, - tls_model, - codegen_unit, - instances: Default::default(), - vtables: Default::default(), - const_str_cache: Default::default(), - const_globals: Default::default(), - statics_to_rauw: RefCell::new(Vec::new()), - used_statics: RefCell::new(Vec::new()), - compiler_used_statics: RefCell::new(Vec::new()), - type_lowering: Default::default(), - scalar_lltypes: Default::default(), - isize_ty, - coverage_cx, - dbg_cx, - eh_personality: Cell::new(None), - eh_catch_typeinfo: Cell::new(None), - rust_try_fn: Cell::new(None), - intrinsics: Default::default(), - local_gen_sym_counter: Cell::new(0), - renamed_statics: Default::default(), - } + GenericCx( + FullCx { + tcx, + scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size), + use_dll_storage_attrs, + tls_model, + codegen_unit, + instances: Default::default(), + vtables: Default::default(), + const_str_cache: Default::default(), + const_globals: Default::default(), + statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), + compiler_used_statics: RefCell::new(Vec::new()), + type_lowering: Default::default(), + scalar_lltypes: Default::default(), + coverage_cx, + dbg_cx, + eh_personality: Cell::new(None), + eh_catch_typeinfo: Cell::new(None), + rust_try_fn: Cell::new(None), + intrinsics: Default::default(), + local_gen_sym_counter: Cell::new(0), + renamed_statics: Default::default(), + }, + PhantomData, + ) } pub(crate) fn statics_to_rauw(&self) -> &RefCell> { @@ -628,24 +642,32 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_section(g, c"llvm.metadata"); } } + impl<'ll> SimpleCx<'ll> { - pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type { - common::val_ty(v) + pub(crate) fn new( + llmod: &'ll llvm::Module, + llcx: &'ll llvm::Context, + pointer_size: Size, + ) -> Self { + let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits()); + Self(SCx { llmod, llcx, isize_ty }, PhantomData) } +} +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value { - unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) } + llvm::LLVMMetadataAsValue(self.llcx(), metadata) } pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> { let name = SmallCStr::new(name); - unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) } + unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) } } - pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 { + pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId { unsafe { llvm::LLVMGetMDKindIDInContext( - self.llcx, + self.llcx(), name.as_ptr() as *const c_char, name.len() as c_uint, ) @@ -654,13 +676,9 @@ impl<'ll> SimpleCx<'ll> { pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len()) + llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) }) } - - pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind { - unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } - } } impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -1203,27 +1221,18 @@ impl CodegenCx<'_, '_> { name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY)); name } - - /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } - } } -// This is a duplication of the set_metadata function above. However, so far it's the only one -// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it -// for the Builder. -impl SimpleCx<'_> { - #[allow(unused)] +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } + pub(crate) fn set_metadata<'a>( + &self, + val: &'a Value, + kind_id: impl Into, + md: &'ll Metadata, + ) { + let node = self.get_metadata_value(md); + llvm::LLVMSetMetadata(val, kind_id.into(), node); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index c53ea6d466610..80e54bf045e24 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -8,7 +8,7 @@ use std::ffi::CString; use rustc_abi::Align; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, + BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods, }; use rustc_middle::mir::coverage::{ BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index e79662ebc6472..2419ec1f88854 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -11,6 +11,8 @@ //! * Use define_* family of methods when you might be defining the Value. //! * When in doubt, define. +use std::borrow::Borrow; + use itertools::Itertools; use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_data_structures::fx::FxIndexSet; @@ -22,7 +24,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::common::AsCCharPtr; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx}; use crate::llvm::AttributePlace::Function; use crate::llvm::Visibility; use crate::type_::Type; @@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>( llfn } -impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { /// Declare a global value. /// /// If there’s a value with the same name already declared, the function will /// return its Value instead. pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } + unsafe { + llvm::LLVMRustGetOrInsertGlobal( + (**self).borrow().llmod, + name.as_c_char_ptr(), + name.len(), + ty, + ) + } } +} +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Declare a C ABI function. /// /// Only use this for foreign function ABIs and glue. For Rust functions use diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 0272667e22399..660fc7ec4c404 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -649,7 +649,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time // optimization pass replaces calls to this intrinsic with code to test type membership. - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); self.call_intrinsic("llvm.type.test", &[pointer, typeid]) } @@ -659,7 +659,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { vtable_byte_offset: u64, typeid: &'ll Metadata, ) -> Self::Value { - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); let type_checked_load = self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8f72307eeba3d..e51d4852db280 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -28,6 +28,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; +use context::SimpleCx; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; pub(crate) use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; @@ -115,9 +116,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { - let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let cx = + SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 25ca349880345..f6b238629075c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -3,13 +3,14 @@ use libc::{c_char, c_uint}; +use super::MetadataKindId; use super::ffi::{BasicBlock, Metadata, Module, Type, Value}; use crate::llvm::Bool; #[link(name = "llvm-wrapper", kind = "static")] unsafe extern "C" { // Enzyme - pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool; + pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool; pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value); pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>; pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e3d0b928c9785..39087a4d6f41d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -976,6 +976,16 @@ pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct MetadataKindId(c_uint); + +impl From for MetadataKindId { + fn from(value: MetadataType) -> Self { + Self(value as c_uint) + } +} + unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMContextDispose(C: &'static mut Context); @@ -983,7 +993,7 @@ unsafe extern "C" { C: &Context, Name: *const c_char, SLen: c_uint, - ) -> c_uint; + ) -> MetadataKindId; // Create modules. pub(crate) fn LLVMModuleCreateWithNameInContext( @@ -1050,9 +1060,9 @@ unsafe extern "C" { pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char; pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); - pub(crate) fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value); + pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value); pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); - pub(crate) fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; + pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; // Operations on constants of any type pub(crate) fn LLVMConstNull(Ty: &Type) -> &Value; @@ -1146,7 +1156,7 @@ unsafe extern "C" { pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); - pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( @@ -1203,7 +1213,7 @@ unsafe extern "C" { pub(crate) fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>; // Terminators - pub(crate) fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; + pub(crate) safe fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; pub(crate) fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value; pub(crate) fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value; pub(crate) fn LLVMBuildCondBr<'a>( @@ -1679,7 +1689,7 @@ unsafe extern "C" { Packed: Bool, ); - pub(crate) fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; + pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index d61ce41756270..b89ce90d1a1dc 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::{fmt, ptr}; use libc::{c_char, c_uint}; @@ -11,7 +12,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; use crate::llvm::{Bool, False, Metadata, True}; use crate::type_of::LayoutLlvmExt; @@ -36,29 +37,29 @@ impl fmt::Debug for Type { } impl<'ll> CodegenCx<'ll, '_> {} -impl<'ll> SimpleCx<'ll> { +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type { let name = SmallCStr::new(name); - unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) } + unsafe { llvm::LLVMStructCreateNamed(self.llcx(), name.as_ptr()) } } pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } } pub(crate) fn type_void(&self) -> &'ll Type { - unsafe { llvm::LLVMVoidTypeInContext(self.llcx) } + unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } pub(crate) fn type_token(&self) -> &'ll Type { - unsafe { llvm::LLVMTokenTypeInContext(self.llcx) } + unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) } } pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) } + unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) } } ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } } pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { @@ -121,19 +122,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.type_array(self.type_from_integer(unit), size / unit_size) } } -impl<'ll> SimpleCx<'ll> { + +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { + pub(crate) fn llcx(&self) -> &'ll llvm::Context { + (**self).borrow().llcx + } + + pub(crate) fn isize_ty(&self) -> &'ll Type { + (**self).borrow().isize_ty + } + pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } pub(crate) fn type_i1(&self) -> &'ll Type { - unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) } } pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { unsafe { llvm::LLVMStructTypeInContext( - self.llcx, + self.llcx(), els.as_ptr(), els.len() as c_uint, packed as Bool, @@ -142,45 +152,45 @@ impl<'ll> SimpleCx<'ll> { } } -impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { fn type_i8(&self) -> &'ll Type { - unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt8TypeInContext(self.llcx()) } } fn type_i16(&self) -> &'ll Type { - unsafe { llvm::LLVMInt16TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt16TypeInContext(self.llcx()) } } fn type_i32(&self) -> &'ll Type { - unsafe { llvm::LLVMInt32TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt32TypeInContext(self.llcx()) } } fn type_i64(&self) -> &'ll Type { - unsafe { llvm::LLVMInt64TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) } } fn type_i128(&self) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, 128) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) } } fn type_isize(&self) -> &'ll Type { - self.isize_ty + self.isize_ty() } fn type_f16(&self) -> &'ll Type { - unsafe { llvm::LLVMHalfTypeInContext(self.llcx) } + unsafe { llvm::LLVMHalfTypeInContext(self.llcx()) } } fn type_f32(&self) -> &'ll Type { - unsafe { llvm::LLVMFloatTypeInContext(self.llcx) } + unsafe { llvm::LLVMFloatTypeInContext(self.llcx()) } } fn type_f64(&self) -> &'ll Type { - unsafe { llvm::LLVMDoubleTypeInContext(self.llcx) } + unsafe { llvm::LLVMDoubleTypeInContext(self.llcx()) } } fn type_f128(&self) -> &'ll Type { - unsafe { llvm::LLVMFP128TypeInContext(self.llcx) } + unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) } } fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { @@ -196,7 +206,7 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type { - unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) } + unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) } } fn element_type(&self, ty: &'ll Type) -> &'ll Type { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index c8bb229998ea3..87992ce2e11b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; +use rustc_abi::Size; use rustc_ast::attr; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -355,6 +356,7 @@ pub struct CodegenContext { pub target_is_like_aix: bool, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, + pub pointer_size: Size, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -1216,6 +1218,7 @@ fn start_executing_work( split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, + pointer_size: tcx.data_layout.pointer_size, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 00e01e47fee3a..6988724b42123 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout) } - pub fn len>(&self, cx: &Cx) -> V { + pub fn len>(&self, cx: &Cx) -> V { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece48..49c51caa996e4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -pub trait AbiBuilderMethods<'tcx>: BackendTypes { +pub trait AbiBuilderMethods: BackendTypes { fn get_param(&mut self, index: usize) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 99fd6b6510ffe..5f91133d5b47e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -40,7 +40,7 @@ pub trait BuilderMethods<'a, 'tcx>: + CoverageInfoBuilderMethods<'tcx> + DebugInfoBuilderMethods + ArgAbiBuilderMethods<'tcx> - + AbiBuilderMethods<'tcx> + + AbiBuilderMethods + IntrinsicCallBuilderMethods<'tcx> + AsmBuilderMethods<'tcx> + StaticBuilderMethods diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index dc6b68ceff7d8..d83a04d814be3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -3,7 +3,7 @@ use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; use super::BackendTypes; -pub trait ConstCodegenMethods<'tcx>: BackendTypes { +pub trait ConstCodegenMethods: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; /// Generate an uninitialized value (matching uninitialized memory in MIR). @@ -37,7 +37,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 90fcfbe4da7a1..239857a4298df 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + PartialEq + fmt::Debug; pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + TypeCodegenMethods<'tcx> - + ConstCodegenMethods<'tcx> + + ConstCodegenMethods + StaticCodegenMethods + DebugInfoCodegenMethods<'tcx> + AsmCodegenMethods<'tcx> diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index fbd927d0d663e..32d9f27d32d34 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -9,7 +9,7 @@ use super::misc::MiscCodegenMethods; use crate::common::TypeKind; use crate::mir::place::PlaceRef; -pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { +pub trait BaseTypeCodegenMethods: BackendTypes { fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { } pub trait DerivedTypeCodegenMethods<'tcx>: - BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> + BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { fn type_int(&self) -> Self::Type { match &self.sess().target.c_int_width[..] { @@ -87,10 +87,7 @@ pub trait DerivedTypeCodegenMethods<'tcx>: } impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where - Self: BaseTypeCodegenMethods<'tcx> - + MiscCodegenMethods<'tcx> - + HasTyCtxt<'tcx> - + HasTypingEnv<'tcx> + Self: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 43631330f89bf..e4b2fe5d153e1 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -104,7 +104,7 @@ fn intern_as_new_static<'tcx>( ) { let feed = tcx.create_def( static_id, - sym::nested, + Some(sym::nested), DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c6e992573d6f3..7741f6668c382 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -474,6 +474,8 @@ declare_features! ( (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), + /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` + (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 7e3a8561da08b..ea2581787e47e 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -253,7 +253,9 @@ impl DefKind { } } - pub fn def_path_data(self, name: Symbol) -> DefPathData { + // Some `DefKind`s require a name, some don't. Panics if one is needed but + // not provided. (`AssocTy` is an exception, see below.) + pub fn def_path_data(self, name: Option) -> DefPathData { match self { DefKind::Mod | DefKind::Struct @@ -264,9 +266,13 @@ impl DefKind { | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias - | DefKind::AssocTy | DefKind::TyParam - | DefKind::ExternCrate => DefPathData::TypeNs(name), + | DefKind::ExternCrate => DefPathData::TypeNs(Some(name.unwrap())), + + // An associated type names will be missing for an RPITIT. It will + // later be given a name with `synthetic` in it, if necessary. + DefKind::AssocTy => DefPathData::TypeNs(name), + // It's not exactly an anon const, but wrt DefPathData, there // is no difference. DefKind::Static { nested: true, .. } => DefPathData::AnonConst, @@ -276,9 +282,9 @@ impl DefKind { | DefKind::Static { .. } | DefKind::AssocFn | DefKind::AssocConst - | DefKind::Field => DefPathData::ValueNs(name), - DefKind::Macro(..) => DefPathData::MacroNs(name), - DefKind::LifetimeParam => DefPathData::LifetimeNs(name), + | DefKind::Field => DefPathData::ValueNs(name.unwrap()), + DefKind::Macro(..) => DefPathData::MacroNs(name.unwrap()), + DefKind::LifetimeParam => DefPathData::LifetimeNs(name.unwrap()), DefKind::Ctor(..) => DefPathData::Ctor, DefKind::Use => DefPathData::Use, DefKind::ForeignMod => DefPathData::ForeignMod, diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c4c309e77e194..61f5efd9978c3 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -271,8 +271,9 @@ pub enum DefPathData { Use, /// A global asm item. GlobalAsm, - /// Something in the type namespace. - TypeNs(Symbol), + /// Something in the type namespace. Will be empty for RPITIT associated + /// types, which are given a synthetic name later, if necessary. + TypeNs(Option), /// Something in the value namespace. ValueNs(Symbol), /// Something in the macro namespace. @@ -410,8 +411,9 @@ impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => None, - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + TypeNs(name) => name, + + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst | OpaqueTy => None, @@ -421,12 +423,14 @@ impl DefPathData { pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => { - DefPathDataName::Anon { namespace: sym::synthetic } - } - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { - DefPathDataName::Named(name) + TypeNs(name) => { + if let Some(name) = name { + DefPathDataName::Named(name) + } else { + DefPathDataName::Anon { namespace: sym::synthetic } + } } + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name), // Note that this does not show up in user print-outs. CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, Impl => DefPathDataName::Anon { namespace: kw::Impl }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index df305e6e769d9..928455ace8562 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 41eb5b45bd1e0..25d2a8253438c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -316,8 +316,8 @@ pub trait Visitor<'v>: Sized { fn visit_ident(&mut self, ident: Ident) -> Self::Result { walk_ident(self, ident) } - fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> Self::Result { - walk_mod(self, m, n) + fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result { + walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result { walk_foreign_item(self, i) @@ -464,8 +464,8 @@ pub trait Visitor<'v>: Sized { fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) -> Self::Result { - walk_enum_def(self, enum_definition, item_id) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result { + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result { walk_variant(self, v) @@ -532,28 +532,25 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { + try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ident(item.ident)); match item.kind { ItemKind::ExternCrate(orig_name) => { - try_visit!(visitor.visit_id(item.hir_id())); visit_opt!(visitor, visit_name, orig_name); } ItemKind::Use(ref path, _) => { try_visit!(visitor.visit_use(path, item.hir_id())); } ItemKind::Static(ref typ, _, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Const(ref typ, ref generics, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Fn { sig, generics, body: body_id, .. } => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), sig.decl, @@ -562,19 +559,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: item.owner_id.def_id, )); } - ItemKind::Macro(..) => { - try_visit!(visitor.visit_id(item.hir_id())); - } + ItemKind::Macro(..) => {} ItemKind::Mod(ref module) => { - // `visit_mod()` takes care of visiting the `Item`'s `HirId`. try_visit!(visitor.visit_mod(module, item.span, item.hir_id())); } ItemKind::ForeignMod { abi: _, items } => { - try_visit!(visitor.visit_id(item.hir_id())); walk_list!(visitor, visit_foreign_item_ref, items); } ItemKind::GlobalAsm { asm: _, fake_body } => { - try_visit!(visitor.visit_id(item.hir_id())); // Visit the fake body, which contains the asm statement. // Therefore we should not visit the asm statement again // outside of the body, or some visitors won't have their @@ -582,14 +574,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_nested_body(fake_body)); } ItemKind::TyAlias(ref ty, ref generics) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(ty)); try_visit!(visitor.visit_generics(generics)); } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. - try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id())); + try_visit!(visitor.visit_enum_def(enum_definition)); } ItemKind::Impl(Impl { constness: _, @@ -602,7 +592,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: self_ty, items, }) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); visit_opt!(visitor, visit_trait_ref, of_trait); try_visit!(visitor.visit_ty_unambig(self_ty)); @@ -611,17 +600,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_variant_data(struct_definition)); } ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } ItemKind::TraitAlias(ref generics, bounds) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); } @@ -638,12 +624,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul visitor.visit_name(ident.name) } -pub fn walk_mod<'v, V: Visitor<'v>>( - visitor: &mut V, - module: &'v Mod<'v>, - mod_hir_id: HirId, -) -> V::Result { - try_visit!(visitor.visit_id(mod_hir_id)); +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result { walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); V::Result::output() } @@ -821,6 +802,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)); @@ -1145,7 +1129,6 @@ pub fn walk_use<'v, V: Visitor<'v>>( path: &'v UsePath<'v>, hir_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(hir_id)); let UsePath { segments, ref res, span } = *path; for &res in res { try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id)); @@ -1326,9 +1309,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>( pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, - item_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(item_id)); walk_list!(visitor, visit_variant, enum_definition.variants); V::Result::output() } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c3b14a4e06c79..29f4d5b807699 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -171,6 +171,7 @@ language_item_table! { Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6b61d317d3f50..883a1acdb3094 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1462,7 +1462,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { - let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + let feed = + self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam); feed.def_span(ident.span); feed.def_ident_span(Some(ident.span)); feed.def_id() diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index f5e075367f336..3611db7c68f16 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -84,9 +84,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) + && !self.maybe_suggest_dyn_trait(self_ty, label, sugg, &mut diag) { - // FIXME: Only emit this suggestion if the trait is dyn-compatible. - diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); + self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag); } // Check if the impl trait that we are considering is an impl of a local trait. self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); @@ -123,6 +123,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn maybe_suggest_add_generic_impl_trait( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + let msg = "you might be missing a type parameter"; + let mut sugg = vec![]; + + let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id; + let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item(); + match parent_item.kind { + hir::ItemKind::Struct(_, generics) | hir::ItemKind::Enum(_, generics) => { + sugg.push(( + generics.where_clause_span, + format!( + "", + self.tcx().sess.source_map().span_to_snippet(self_ty.span).unwrap() + ), + )); + sugg.push((self_ty.span, "T".to_string())); + } + _ => {} + } + diag.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable); + true + } /// Make sure that we are in the condition to suggest the blanket implementation. fn maybe_suggest_blanket_trait_impl( &self, @@ -171,6 +198,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn maybe_suggest_dyn_trait( + &self, + self_ty: &hir::Ty<'_>, + label: &str, + sugg: Vec<(Span, String)>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id; + let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item(); + + // If the parent item is an enum, don't suggest the dyn trait. + if let hir::ItemKind::Enum(..) = parent_item.kind { + return false; + } + + // If the parent item is a struct, check if self_ty is the last field. + if let hir::ItemKind::Struct(variant_data, _) = parent_item.kind { + if variant_data.fields().last().unwrap().ty.span != self_ty.span { + return false; + } + } + + // FIXME: Only emit this suggestion if the trait is dyn-compatible. + diag.multipart_suggestion_verbose( + label.to_string(), + sugg, + Applicability::MachineApplicable, + ); + true + } + fn add_generic_param_suggestion( &self, generics: &hir::Generics<'_>, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1f6fb3a329a5d..aafbd2738f92d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1470,6 +1470,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); } @@ -2220,6 +2224,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value { .. } => self.word_space("move"), + hir::CaptureBy::Use { .. } => self.word_space("use"), hir::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2a89a03e0aa49..786e8b876a613 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -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>, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c0617119d67c7..9ff7eeb23688c 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -47,6 +47,21 @@ pub trait Delegate<'tcx> { /// the id of the binding in the pattern `pat`. fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is used, depending + /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. + /// + /// Use of a `Copy` type in a ByUse context is considered a use + /// by `ImmBorrow` and `borrow` is called instead. This is because + /// a shared borrow is the "minimum access" that would be needed + /// to perform a copy. + /// + /// + /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for + /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic + /// id will be the id of the expression `expr` but the place itself will have + /// the id of the binding in the pattern `pat`. + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is being borrowed with kind `bk`. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn borrow( @@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { (**self).consume(place_with_id, diag_expr_id) } + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).use_cloned(place_with_id, diag_expr_id) + } + fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn body_owner_def_id(&self) -> LocalDefId; fn tcx(&self) -> TyCtxt<'tcx>; @@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.infcx.type_is_copy_modulo_regions(self.param_env, ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.body_id } @@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { self.0.type_is_copy_modulo_regions(ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.0.type_is_use_cloned_modulo_regions(ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.1 } @@ -295,6 +324,24 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id); + + // `x.use` will do one of the following + // * if it implements `Copy`, it will be a copy + // * if it implements `UseCloned`, it will be a call to `clone` + // * otherwise, it is a move + // + // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned` + if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); + } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id); + } else { + self.delegate.borrow_mut().consume(place_with_id, diag_expr_id); + } + } + fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> { for expr in exprs { self.consume_expr(expr)?; @@ -313,6 +360,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { + debug!("consume_or_clone_expr(expr={:?})", expr); + + let place_with_id = self.cat_expr(expr)?; + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + self.walk_expr(expr)?; + Ok(()) + } + fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { let place_with_id = self.cat_expr(expr)?; self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id); @@ -366,6 +422,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.consume_exprs(args)?; } + hir::ExprKind::Use(expr, _) => { + self.consume_or_clone_expr(expr)?; + } + hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) self.consume_expr(receiver)?; @@ -1085,6 +1145,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ty::UpvarCapture::ByValue => { self.consume_or_copy(&place_with_id, place_with_id.hir_id); } + ty::UpvarCapture::ByUse => { + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow_mut().borrow( &place_with_id, @@ -1386,6 +1449,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 { .. } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9a0b22470585f..f570d0d8a0d30 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -671,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (place, capture_kind) = match capture_clause { hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind), + hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind), hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind), }; @@ -1165,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match closure_clause { hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value - hir::CaptureBy::Ref => { + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => { // For non move closure the capture kind is the max capture kind of all captures // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue let mut max_capture_info = root_var_min_capture_list.first().unwrap().info; @@ -1292,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } - hir::CaptureBy::Ref => {} + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {} } return None; @@ -1305,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for captured_place in root_var_min_capture_list.iter() { match captured_place.info.capture_kind { // Only care about captures that are moved into the closure - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { projections_list.push(captured_place.place.projections.as_slice()); diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { source_expr: captured_place.info.path_expr_id, @@ -1689,10 +1690,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // If the data will be moved out of this place, then the place will be truncated // at the first Deref in `adjust_for_move_closure` and then moved into the closure. + // + // For example: + // + // struct Buffer<'a> { + // x: &'a String, + // y: Vec, + // } + // + // fn get<'a>(b: Buffer<'a>) -> impl Sized + 'a { + // let c = move || b.x; + // drop(b); + // c + // } + // + // Even though the closure is declared as move, when we are capturing borrowed data (in + // this case, *b.x) we prefer to capture by reference. + // Otherwise you'd get an error in 2021 immediately because you'd be trying to take + // ownership of the (borrowed) String or else you'd take ownership of b, as in 2018 and + // before, which is also an error. hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => { ty::UpvarCapture::ByValue } - hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => { + hir::CaptureBy::Use { .. } if !place.deref_tys().any(Ty::is_ref) => { + ty::UpvarCapture::ByUse + } + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => { ty::UpvarCapture::ByRef(BorrowKind::Immutable) } } @@ -1927,7 +1950,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>( region: ty::Region<'tcx>, ) -> Ty<'tcx> { match capture_kind { - ty::UpvarCapture::ByValue => ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()), } } @@ -2023,6 +2046,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { )); } + #[instrument(skip(self), level = "debug")] + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); + + self.capture_information.push(( + place_with_id.place.clone(), + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByUse, + }, + )); + } + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, @@ -2164,6 +2202,20 @@ fn adjust_for_move_closure( (place, ty::UpvarCapture::ByValue) } +/// Truncate deref of any reference. +fn adjust_for_use_closure( + mut place: Place<'_>, + mut kind: ty::UpvarCapture, +) -> (Place<'_>, ty::UpvarCapture) { + let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(idx) = first_deref { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); + } + + (place, ty::UpvarCapture::ByUse) +} + /// Adjust closure capture just that if taking ownership of data, only move data /// from enclosing stack frame. fn adjust_for_non_move_closure( @@ -2174,7 +2226,7 @@ fn adjust_for_non_move_closure( place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); match kind { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { if let Some(idx) = contains_deref { truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); } @@ -2219,6 +2271,7 @@ fn construct_capture_kind_reason_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; @@ -2240,6 +2293,7 @@ fn construct_capture_info_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} -> {capture_kind_str}") @@ -2335,8 +2389,11 @@ fn determine_capture_info( // expressions. let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b, - (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false, + (ty::UpvarCapture::ByValue, _) + | (ty::UpvarCapture::ByUse, _) + | (ty::UpvarCapture::ByRef(_), _) => false, }; if eq_capture_kind { @@ -2346,10 +2403,20 @@ fn determine_capture_info( } } else { // We select the CaptureKind which ranks higher based the following priority order: - // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow + // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue, _) => capture_info_a, - (_, ty::UpvarCapture::ByValue) => capture_info_b, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => { + bug!("Same capture can't be ByUse and ByValue at the same time") + } + (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) + | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => { + capture_info_a + } + (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => { + capture_info_b + } (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { match (ref_a, ref_b) { // Take LHS: @@ -2401,7 +2468,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>( } ty::UpvarCapture::ByRef(..) => {} - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } place.projections.truncate(len); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 74663e6b4bbe1..cd4106ebf83af 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> { self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty) } + pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty) + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index fd6b3e90adabc..91c7922638de5 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -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, diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index d22515d62d60e..23d6efa050836 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -74,7 +74,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) { lint_callback!(self, check_mod, m, n); - hir_visit::walk_mod(self, m, n); + hir_visit::walk_mod(self, m); } } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fad8c7dcbcbcb..c85af81ee25bd 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1356,7 +1356,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.submodules.push(item.owner_id); // A module collector does not recurse inside nested modules. if self.crate_collector { - intravisit::walk_mod(self, module, item.hir_id()); + intravisit::walk_mod(self, module); } } else { intravisit::walk_item(self, item) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4ad4427594cf2..3ad9201dd6f8e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1533,6 +1533,11 @@ rustc_queries! { query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } } + /// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`, + /// `ty.is_use_cloned()`, etc, since that will prune the environment where possible. + query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `UseCloned`", env.value } + } /// Query backing `Ty::is_sized`. query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 72f31cec00826..f7b98d935d4de 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -315,6 +315,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, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index a9df4d1625be3..d208692f4e711 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -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]); diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 3605f2402e7ff..5d9b1ddfa38ea 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -51,6 +51,9 @@ pub enum UpvarCapture { /// depending on inference. ByValue, + /// Upvar is captured by use. This is true when the closure is labeled `use`. + ByUse, + /// Upvar is captured by reference. ByRef(BorrowKind), } @@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> { pub fn is_by_ref(&self) -> bool { match self.info.capture_kind { - ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false, ty::UpvarCapture::ByRef(..) => true, } } @@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { if !self.is_closure_like(def_id.to_def_id()) { return &[]; - }; + } self.closure_typeinfo(def_id).captures } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4013f7b2c8548..edba2a2530f68 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1890,7 +1890,7 @@ impl<'tcx> TyCtxtAt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let feed = self.tcx.create_def(parent, name, def_kind); @@ -1905,7 +1905,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let data = def_kind.def_path_data(name); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 34d85534d0aea..2a3a7705b7b60 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -569,7 +569,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { + DefPathData::TypeNs(Some(ref mut name)) if Some(visible_parent) != actual_parent => { // Item might be re-exported several times, but filter for the one // that's public and whose identifier isn't `_`. let reexport = self @@ -590,7 +590,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate)); + data = DefPathData::TypeNs(Some(self.tcx().crate_name(def_id.krate))); } _ => {} } diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index 7f0d82d89fede..2d9e0331451fd 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -23,9 +23,11 @@ fn true_significant_drop_ty<'tcx>( match key.disambiguated_data.data { rustc_hir::definitions::DefPathData::CrateRoot => { - name_rev.push(tcx.crate_name(did.krate)) + name_rev.push(tcx.crate_name(did.krate)); + } + rustc_hir::definitions::DefPathData::TypeNs(symbol) => { + name_rev.push(symbol.unwrap()); } - rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol), _ => return None, } if let Some(parent) = key.parent { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 237aa66f486f8..0c68913904fc3 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> { ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty)) } + /// Checks whether `ty: UseCloned` holds while ignoring region constraints. + /// + /// This function should not be used if there is an `InferCtxt` available. + /// Use `InferCtxt::type_is_copy_modulo_regions` instead. + pub fn type_is_use_cloned_modulo_regions( + self, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty)) + } + /// Returns the deeply last field of nested structures, or the same type if /// not a structure at all. Corresponds to the only possible unsized field, /// and its type can be used to determine unsizing strategy. diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 581f45db6c483..50ca924baf9c8 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -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))); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 2c9a1de7f9978..97d34b85f50da 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -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)) + } } } diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index ca55d36bfc659..34524aed40678 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -56,6 +56,7 @@ impl Category { | ExprKind::RawBorrow { .. } | ExprKind::Yield { .. } | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 72443e2f60ddc..333e69475c508 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -4,11 +4,14 @@ 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 rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; @@ -289,6 +292,57 @@ 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; + + if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Copy(place)), + ); + block.unit() + } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, 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() + } else { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Move(place)), + ); + block.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` diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 949559549345f..ff2b59ee07d20 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( .map(|captured_place| { let name = captured_place.to_symbol(); match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => name, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name, ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")), } }) @@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(FieldIdx::new(i), ty)); match capture { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c2eafd0a74e65..d78c874c76607 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -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 { .. } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 7139516702e99..e46e8c9871a5a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -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) } } @@ -648,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> { } }, - hir::ExprKind::Closure { .. } => { + hir::ExprKind::Closure(hir::Closure { .. }) => { let closure_ty = self.typeck_results.expr_ty(expr); let (def_id, args, movability) = match *closure_ty.kind() { ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None), @@ -1248,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> { match upvar_capture { ty::UpvarCapture::ByValue => captured_place_expr, + ty::UpvarCapture::ByUse => { + let span = captured_place_expr.span; + let expr_id = self.thir.exprs.push(captured_place_expr); + + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: upvar_ty, + span: closure_expr.span, + kind: ExprKind::ByUse { expr: expr_id, span }, + } + } ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::Immutable => BorrowKind::Shared, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 954d0cf97abef..dadd1e8546117 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Borrow { .. } | Box { .. } | Call { .. } + | ByUse { .. } | Closure { .. } | ConstBlock { .. } | ConstParam { .. } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index cd56d93afcf75..16cef0ec3acbc 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -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); diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0f5fcb0d8eb99..9cd7045a0a222 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -78,7 +78,6 @@ use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir}; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::kw; pub(crate) fn coroutine_by_move_body_def_id<'tcx>( tcx: TyCtxt<'tcx>, @@ -170,7 +169,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( // this when building the field projection in the MIR body later on. let mut parent_capture_ty = parent_capture.place.ty(); parent_capture_ty = match parent_capture.info.capture_kind { - ty::UpvarCapture::ByValue => parent_capture_ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref( tcx, tcx.lifetimes.re_erased, @@ -214,7 +213,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. - let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody); + let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1d5b59421706f..6d4308cda1a60 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,11 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later + +parse_async_use_order_incorrect = the order of `use` and `async` is incorrect + .suggestion = try switching the order + parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` @@ -348,6 +353,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 diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8d2fd595942c6..e090d9cf7600e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -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, @@ -1499,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_order_incorrect)] +pub(crate) struct AsyncUseOrderIncorrect { + #[primary_span] + #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_double_colon_in_bound)] pub(crate) struct DoubleColonInBound { @@ -1667,6 +1688,13 @@ pub(crate) struct AsyncMoveBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_block_in_2015)] +pub(crate) struct AsyncUseBlockIn2015 { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_async_bound_modifier_in_2015)] pub(crate) struct AsyncBoundModifierIn2015 { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 94db43bb59f81..bb227a58cf19d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -31,15 +31,15 @@ use super::{ SeqSep, TokenType, }; use crate::errors::{ - AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, - BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, - ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, - ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, + AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, + ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, 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, @@ -572,10 +572,17 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); } - if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { - // The 2015 edition is in use because parsing of `async move` has failed. + if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use)) + && self.prev_token.is_keyword(kw::Async) + { + // The 2015 edition is in use because parsing of `async move` or `async use` has failed. let span = self.prev_token.span.to(self.token.span); - return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + if self.token.is_keyword(kw::Move) { + return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + } else { + // kw::Use + return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span })); + } } let expect = tokens_to_string(&expected); @@ -1991,7 +1998,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 +2037,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> { let is_try = self.token.is_keyword(kw::Try); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0a08c6faeb486..b37dd64fbed6b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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; @@ -1397,6 +1404,7 @@ impl<'a> Parser<'a> { } else if this.check_path() { this.parse_expr_path_start() } else if this.check_keyword(exp!(Move)) + || this.check_keyword(exp!(Use)) || this.check_keyword(exp!(Static)) || this.check_const_closure() { @@ -2388,7 +2396,7 @@ impl<'a> Parser<'a> { Ok(closure) } - /// Parses an optional `move` prefix to a closure-like construct. + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { let move_kw_span = self.prev_token.span; @@ -2401,6 +2409,16 @@ impl<'a> Parser<'a> { } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } + } else if self.eat_keyword(exp!(Use)) { + let use_kw_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span); + // Check for `use async` and recover + if self.check_keyword(exp!(Async)) { + let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span })) + } else { + Ok(CaptureBy::Use { use_kw: use_kw_span }) + } } else { Ok(CaptureBy::Ref) } @@ -3415,7 +3433,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(lookahead, &[kw]) && (( // `async move {` - self.is_keyword_ahead(lookahead + 1, &[kw::Move]) + self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() }) @@ -3818,6 +3836,13 @@ impl<'a> Parser<'a> { await_expr } + fn mk_use_expr(&mut self, self_arg: P, lo: Span) -> P { + 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 { P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } @@ -3966,6 +3991,7 @@ impl MutVisitor for CondChecker<'_> { } ExprKind::Unary(_, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c3b1956ad2e82..0b9350c71992a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -209,7 +209,7 @@ impl<'a> Parser<'a> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); - let info = if self.eat_keyword_case(exp!(Use), case) { + let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { self.parse_use_item()? } else if self.check_fn_front_matter(check_pub, case) { // FUNCTION ITEM @@ -1277,6 +1277,21 @@ impl<'a> Parser<'a> { None } + fn is_use_closure(&self) -> bool { + if self.token.is_keyword(kw::Use) { + // Check if this could be a closure. + self.look_ahead(1, |token| { + // Move or Async here would be an error but still we're parsing a closure + let dist = + if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 }; + + self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr)) + }) + } else { + false + } + } + fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) @@ -1290,7 +1305,7 @@ impl<'a> Parser<'a> { if self.check_keyword(exp!(Static)) { // Check if this could be a closure. !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) { + if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) { return true; } matches!(token.kind, token::Or | token::OrOr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7dabc28c6454c..4ec8d9e5e49e0 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -813,9 +813,9 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(0, &[kw::Const]) && self.look_ahead(1, |t| match &t.kind { // async closures do not work with const closures, so we do not parse that here. - token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => { - true - } + token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No) + | token::OrOr + | token::Or => true, _ => false, }) } diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 92ea49f18e5d1..844f74372dea8 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -255,9 +255,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_body(self, b); } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) { + fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) { self.record("Mod", None, m); - hir_visit::walk_mod(self, m, n) + hir_visit::walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { @@ -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 diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 24dc018c66124..822804893fe2a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -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(..) @@ -705,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } } } @@ -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(..) @@ -1493,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> { for (&var_hir_id, min_capture_list) in closure_min_captures { for captured_place in min_capture_list { match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => continue, }; let span = captured_place.get_capture_kind_span(self.ir.tcx); diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index cb17b0f6cf528..d35aedf9a5647 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -182,6 +182,7 @@ impl CheckInlineAssembly { | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) + | ExprKind::Use(..) | ExprKind::Tup(..) | ExprKind::Binary(..) | ExprKind::Unary(..) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 95d637b6b22bc..33f529851ae4f 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, sym}; use tracing::debug; use crate::{ImplTraitContext, InvocationParent, Resolver}; @@ -38,7 +38,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { fn create_def( &mut self, node_id: NodeId, - name: Symbol, + name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -89,7 +89,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.visit_macro_invoc(field.id); } else { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); - let def = self.create_def(field.id, name, DefKind::Field, field.span); + let def = self.create_def(field.id, Some(name), DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); } } @@ -161,7 +161,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { return self.visit_macro_invoc(i.id); } }; - let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def_id = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); @@ -175,7 +175,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Struct, ctor_kind), i.span, ); @@ -211,20 +211,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } let (return_id, return_span) = coroutine_kind.return_id(); - let return_def = - self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span); + let return_def = self.create_def(return_id, None, DefKind::OpaqueTy, return_span); self.with_parent(return_def, |this| this.visit_fn_ret_ty(output)); // If this async fn has no body (i.e. it's an async fn signature in a trait) // then the closure_def will never be used, and we should avoid generating a // def-id for it. if let Some(body) = body { - let closure_def = self.create_def( - coroutine_kind.closure_id(), - kw::Empty, - DefKind::Closure, - span, - ); + let closure_def = + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(closure_def, |this| this.visit_block(body)); } } @@ -235,7 +230,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Async closures desugar to closures inside of closures, so // we must create two defs. let coroutine_def = - self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span); + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(coroutine_def, |this| this.visit_expr(body)); } _ => visit::walk_fn(self, fn_kind), @@ -243,7 +238,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, kw::Empty, DefKind::Use, use_tree.span); + self.create_def(id, None, DefKind::Use, use_tree.span); visit::walk_use_tree(self, use_tree, id); } @@ -262,7 +257,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), }; - let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span); + let def = self.create_def(fi.id, Some(fi.ident.name), def_kind, fi.span); self.with_parent(def, |this| visit::walk_item(this, fi)); } @@ -271,12 +266,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if v.is_placeholder { return self.visit_macro_invoc(v.id); } - let def = self.create_def(v.id, v.ident.name, DefKind::Variant, v.span); + let def = self.create_def(v.id, Some(v.ident.name), DefKind::Variant, v.span); self.with_parent(def, |this| { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Variant, ctor_kind), v.span, ); @@ -312,7 +307,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { GenericParamKind::Type { .. } => DefKind::TyParam, GenericParamKind::Const { .. } => DefKind::ConstParam, }; - self.create_def(param.id, param.ident.name, def_kind, param.ident.span); + self.create_def(param.id, Some(param.ident.name), def_kind, param.ident.span); // impl-Trait can happen inside generic parameters, like // ``` @@ -335,7 +330,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let def = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } @@ -347,8 +342,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let parent = - self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); + let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } @@ -356,18 +350,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let parent_def = match expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { - self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) + self.create_def(expr.id, None, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { for attr in &expr.attrs { visit::walk_attribute(self, attr); } - let def = self.create_def( - constant.id, - kw::Empty, - DefKind::InlineConst, - constant.value.span, - ); + let def = + self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span); self.with_parent(def, |this| visit::walk_anon_const(this, constant)); return; } @@ -391,7 +381,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, name, kind, ty.span); + let id = self.create_def(*id, Some(name), kind, ty.span); match self.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. @@ -495,7 +485,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { InlineAsmOperand::Const { anon_const } => { let def = self.create_def( anon_const.id, - kw::Empty, + None, DefKind::InlineConst, anon_const.value.span, ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4c5d4041022a9..ccdca8552320f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1340,7 +1340,7 @@ impl<'tcx> Resolver<'_, 'tcx> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option, def_kind: DefKind, expn_id: ExpnId, span: Span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 573c65a772cb6..9045fc95ec750 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -862,6 +862,7 @@ symbols! { eprint_macro, eprintln_macro, eq, + ergonomic_clones, ermsb_target_feature, exact_div, except, @@ -2185,6 +2186,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + use_cloned, use_extern_macros, use_nested_groups, used, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f373706b2960c..5cf0600ade8b4 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } + fn type_is_use_cloned_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let ty = self.resolve_vars_if_possible(ty); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) + } + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index de2c3b63997ed..8bc7bf10865f5 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -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 diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index c8034f4e7b9f6..c84055f5b84fe 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -252,7 +252,8 @@ fn associated_type_for_impl_trait_in_trait( assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -304,7 +305,8 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 2157ab3c4022c..20646cf9a826c 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty is_item_raw(tcx, query, LangItem::Copy) } +fn is_use_cloned_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { + is_item_raw(tcx, query, LangItem::UseCloned) +} + fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Sized) } @@ -33,5 +40,12 @@ fn is_item_raw<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; + *providers = Providers { + is_copy_raw, + is_use_cloned_raw, + is_sized_raw, + is_freeze_raw, + is_unpin_raw, + ..*providers + }; } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index ece796b3c71ce..b275cd382ab83 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -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 { .. } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 8877bb45ceb22..0298e7e0e9511 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -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)] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cb93100f56cf0..265b68d3b0eb4 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,6 +56,7 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +#![allow(incomplete_features)] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -113,6 +114,7 @@ #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] +#![feature(ergonomic_clones)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 09206c2f8b290..5847bd8f28138 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -245,6 +245,7 @@ use core::any::Any; use core::cell::Cell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -2333,6 +2334,9 @@ impl Clone for Rc { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Rc {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Rc { @@ -3496,6 +3500,9 @@ impl Clone for Weak { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Weak {} + #[stable(feature = "rc_weak", since = "1.4.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1956dda538816..21ee59cc538af 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,6 +11,7 @@ use core::any::Any; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -2197,6 +2198,9 @@ impl Clone for Arc { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Arc {} + #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Arc { type Target = T; @@ -3158,6 +3162,9 @@ impl Clone for Weak { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Weak {} + #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { /// Constructs a new `Weak`, without allocating memory. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 9d64348289cf2..c777dd995a656 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -184,6 +184,59 @@ pub macro Clone($item:item) { /* compiler built-in */ } +/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted) +/// +/// Cloning an object implementing this trait should in general: +/// - be O(1) (constant) time regardless of the amount of data managed by the object, +/// - not require a memory allocation, +/// - not require copying more than roughly 64 bytes (a typical cache line size), +/// - not block the current thread, +/// - not have any semantic side effects (e.g. allocating a file descriptor), and +/// - not have overhead larger than a couple of atomic operations. +/// +/// The `UseCloned` trait does not provide a method; instead, it indicates that +/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax. +/// +/// ## .use postfix syntax +/// +/// Values can be `.use`d by adding `.use` postfix to the value you want to use. +/// +/// ```ignore (this won't work until we land use) +/// fn foo(f: Foo) { +/// // if `Foo` implements `Copy` f would be copied into x. +/// // if `Foo` implements `UseCloned` f would be cloned into x. +/// // otherwise f would be moved into x. +/// let x = f.use; +/// // ... +/// } +/// ``` +/// +/// ## use closures +/// +/// Use closures allow captured values to be automatically used. +/// This is similar to have a closure that you would call `.use` over each captured value. +#[unstable(feature = "ergonomic_clones", issue = "132290")] +#[cfg_attr(not(bootstrap), lang = "use_cloned")] +pub trait UseCloned: Clone { + // Empty. +} + +macro_rules! impl_use_cloned { + ($($t:ty)*) => { + $( + #[unstable(feature = "ergonomic_clones", issue = "132290")] + impl UseCloned for $t {} + )* + } +} + +impl_use_cloned! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f16 f32 f64 f128 + bool char +} + // FIXME(aburka): these structs are used solely by #[derive] to // assert that every component of a type implements Clone or Copy. // diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 40e6eaf075ed5..e33f58197bba5 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -404,6 +404,8 @@ macro_rules! define_bignum { } } + impl crate::clone::UseCloned for $name {} + impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { let sz = if self.size < 1 { 1 } else { self.size }; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6c9b366d90304..7585ec140e31e 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,7 @@ //! Definitions of integer that is known not to equal zero. use super::{IntErrorKind, ParseIntError}; +use crate::clone::UseCloned; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Freeze, StructuralPartialEq}; @@ -182,6 +183,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for NonZero where T: ZeroablePrimitive {} + #[stable(feature = "nonzero", since = "1.28.0")] impl Copy for NonZero where T: ZeroablePrimitive {} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a9f06b92ad5dd..f668c6f067246 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2050,6 +2050,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 92b5cba153166..ee98a47523fef 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1744,6 +1744,14 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl crate::clone::UseCloned for Result +where + T: crate::clone::UseCloned, + E: crate::clone::UseCloned, +{ +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for Result { type Item = T; diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index bdd330611de3d..5ac3dbc3e9852 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2121,8 +2121,8 @@ mod unsafe_keyword {} #[doc(keyword = "use")] // -/// Import or rename items from other crates or modules, or specify precise capturing -/// with `use<..>`. +/// Import or rename items from other crates or modules, use values under ergonomic clones +/// semantic, or specify precise capturing with `use<..>`. /// /// ## Importing items /// @@ -2205,6 +2205,11 @@ mod unsafe_keyword {} /// /// For more details about precise capturing, see the [Reference][ref-impl-trait]. /// +/// ## Ergonomic clones +/// +/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the +/// value implements `UseCloned` or moving it otherwise. +/// /// [`crate`]: keyword.crate.html /// [`self`]: keyword.self.html /// [`super`]: keyword.super.html diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2c1d85b01e6af..2ea2596088fd5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2021" +edition = "2024" build = "build.rs" default-run = "bootstrap" diff --git a/src/bootstrap/src/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs index 6e87d4222e863..c161d69d5f73b 100644 --- a/src/bootstrap/src/bin/sccache-plus-cl.rs +++ b/src/bootstrap/src/bin/sccache-plus-cl.rs @@ -4,8 +4,13 @@ use std::process::{self, Command}; fn main() { let target = env::var("SCCACHE_TARGET").unwrap(); // Locate the actual compiler that we're invoking - env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); - env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + + // SAFETY: we're in main, there are no other threads + unsafe { + env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); + env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + } + let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .out_dir("/") diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index c7eafadee2df3..9817e47baa101 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -27,7 +27,7 @@ fn rustfmt( rustfmt: &Path, paths: &[PathBuf], check: bool, -) -> impl FnMut(bool) -> RustfmtStatus { +) -> impl FnMut(bool) -> RustfmtStatus + use<> { let mut cmd = Command::new(rustfmt); // Avoid the submodule config paths from coming into play. We only allow a single global config // for the workspace for now. diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 006dfe7e5d7b3..715ce90e2e1e3 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -9,20 +9,24 @@ use crate::{Build, Config, Flags}; fn test_cc2ar_env_specific() { let triple = "x86_64-unknown-linux-gnu"; let key = "AR_x86_64_unknown_linux_gnu"; - env::set_var(key, "custom-ar"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var(key, "custom-ar") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); let result = cc2ar(cc, target, default_ar); - env::remove_var(key); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var(key) }; assert_eq!(result, Some(PathBuf::from("custom-ar"))); } #[test] fn test_cc2ar_musl() { let triple = "x86_64-unknown-linux-musl"; - env::remove_var("AR_x86_64_unknown_linux_musl"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -33,8 +37,10 @@ fn test_cc2ar_musl() { #[test] fn test_cc2ar_openbsd() { let triple = "x86_64-unknown-openbsd"; - env::remove_var("AR_x86_64_unknown_openbsd"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_openbsd") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/cc"); let default_ar = PathBuf::from("default-ar"); @@ -45,8 +51,10 @@ fn test_cc2ar_openbsd() { #[test] fn test_cc2ar_vxworks() { let triple = "armv7-wrs-vxworks"; - env::remove_var("AR_armv7_wrs_vxworks"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_armv7_wrs_vxworks") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -57,8 +65,10 @@ fn test_cc2ar_vxworks() { #[test] fn test_cc2ar_nto_i586() { let triple = "i586-unknown-nto-something"; - env::remove_var("AR_i586_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_i586_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -69,8 +79,10 @@ fn test_cc2ar_nto_i586() { #[test] fn test_cc2ar_nto_aarch64() { let triple = "aarch64-unknown-nto-something"; - env::remove_var("AR_aarch64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_aarch64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -81,8 +93,10 @@ fn test_cc2ar_nto_aarch64() { #[test] fn test_cc2ar_nto_x86_64() { let triple = "x86_64-unknown-nto-something"; - env::remove_var("AR_x86_64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -94,8 +108,10 @@ fn test_cc2ar_nto_x86_64() { #[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] fn test_cc2ar_nto_unknown() { let triple = "powerpc-unknown-nto-something"; - env::remove_var("AR_powerpc_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_powerpc_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -177,7 +193,8 @@ fn test_default_compiler_wasi() { let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); - env::set_var("WASI_SDK_PATH", &wasi_sdk); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) }; let mut cfg = cc::Build::new(); if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { let expected = { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 7ad308cd06728..89d93a29acbca 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -286,7 +286,7 @@ pub fn output(cmd: &mut Command) -> String { /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap. #[track_caller] -pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> { let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { Ok(child) => child, Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index a60e889fd576c..99fc3e2dc7b55 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -7,7 +7,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {} #[cfg(all(unix, not(target_os = "haiku")))] pub unsafe fn setup(build: &mut crate::Build) { if build.config.low_priority { - libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + unsafe { + libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + } } } diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 82385c1c4db5d..4610e092cdfaf 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -251,7 +251,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { // If it's a "mod foo {}", we want to look to its documentation page. self.extract_info_from_hir_id(id); } - intravisit::walk_mod(self, m, id); + intravisit::walk_mod(self, m); } fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 8d1e893cb1af2..33ba401d60c21 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 39e5e140b7a40..fb5d49a100475 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> { impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { if let PlaceBase::Local(id) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index b679fdfadc3a9..dd7a6f77acff5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>( | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), + ExprKind::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => { never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) }, diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 09440c396ee16..d0905733ab506 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -99,7 +99,7 @@ where }); if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { match captures.get(l) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => { return None; }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a80977459f21d..f51bdc78f8a51 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index d5c5679c990df..dc10de24bc8c7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + #[allow(clippy::if_same_then_else)] fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 380cc380ad0f2..dc85176ebb9e9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { self.move_common(cmt); } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {} fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 5737a91031db2..03b907ebdf4d8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} @@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index de9f055863cb2..75b18bc651e2a 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>( .then_some(()) .and_then(|()| none_captures.get(local_id)) }) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, Some(CaptureKind::Ref(Mutability::Not)) | None => (), } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 76b9bbbd32fde..6f6683eb97123 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e84a..9d8c161873c05 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Tup({elements})"); self.slice(elements, |e| self.expr(e)); }, + ExprKind::Use(expr, _) => { + bind!(self, expr); + kind!("Use({expr})"); + self.expr(expr); + }, ExprKind::Binary(op, left, right) => { bind!(self, op, left, right); kind!("Binary({op}, {left}, {right})"); @@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }) => { let capture_clause = match capture_clause { CaptureBy::Value { .. } => "Value { .. }", + CaptureBy::Use { .. } => "Use { .. }", CaptureBy::Ref => "Ref", }; diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index aaea8d71efbef..4543a20cc2cd4 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS ExprKind::ConstBlock(_) | ExprKind::Array(_) | ExprKind::Tup(_) + | ExprKind::Use(..) | ExprKind::Lit(_) | ExprKind::Cast(..) | ExprKind::Type(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c47c08285c2eb..9938e64d24264 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> { && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), + (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), @@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Ret(..) | &ExprKind::Struct(..) | &ExprKind::Tup(..) + | &ExprKind::Use(..) | &ExprKind::Type(..) | &ExprKind::Unary(..) | &ExprKind::Yield(..) @@ -1053,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Tup(tup) => { self.hash_exprs(tup); }, + ExprKind::Use(expr, _) => { + self.hash_expr(expr); + }, ExprKind::Unary(lop, le) => { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index d850cc410008d..d89692468441c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1129,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CaptureKind { Value, + Use, Ref(Mutability), } impl CaptureKind { @@ -1141,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind { fn bitor(self, rhs: Self) -> Self::Output { match (self, rhs) { (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value, + (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use, (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_)) | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut), (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not), @@ -1220,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { }, ExprKind::Let(let_expr) => { let mutability = match pat_capture_kind(cx, let_expr.pat) { - CaptureKind::Value => Mutability::Not, + CaptureKind::Value | CaptureKind::Use => Mutability::Not, CaptureKind::Ref(m) => m, }; return CaptureKind::Ref(mutability); @@ -1229,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { let mut mutability = Mutability::Not; for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) { match capture { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut, CaptureKind::Ref(Mutability::Not) => (), } @@ -1239,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { _ => break, }, Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, capture @ CaptureKind::Ref(_) => return capture, }, _ => break, @@ -1294,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { UpvarCapture::ByValue => CaptureKind::Value, + UpvarCapture::ByUse => CaptureKind::Use, UpvarCapture::ByRef(kind) => match kind { BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmutable | BorrowKind::Mutable => { @@ -3489,7 +3492,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { + if let DefPathData::TypeNs(Some(s)) = l { path.push(s.to_string()); } if let DefPathData::TypeNs(_) = r { @@ -3500,7 +3503,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3514,7 +3517,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // `super` chain would be too long, just use the absolute path instead once(String::from("crate")) .chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(sym) = el.data { + if let DefPathData::TypeNs(Some(sym)) = el.data { Some(sym.to_string()) } else { None diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 4a9ab17d4a609..24b4f0d9e6d81 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -147,6 +147,7 @@ impl<'a> Sugg<'a> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Tup(..) + | ExprKind::Use(..) | ExprKind::Err(_) | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), @@ -217,6 +218,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) @@ -835,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 3bf518f7fe706..a079fd940c009 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -66,6 +66,8 @@ impl MutVarsDelegate { impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { self.update(cmt); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 2ac0efd7e392d..63dd00f2de0fb 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, + ExprKind::Use(expr, _) => { + helper(typeck, true, expr, f)?; + }, ExprKind::Index(borrowed, consumed, _) | ExprKind::Assign(borrowed, consumed, _) | ExprKind::AssignOp(_, borrowed, consumed) => { diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index 885ed3b08faca..da1e74b4a56bc 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -15,7 +15,7 @@ impl TestCx<'_> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { self.fatal(&format!( - "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \ + "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful \ name, add a doc-comment to the start of the test explaining why it exists and \ move it to tests/ui or wherever you see fit. Adding 'Fixes #' to your PR \ description ensures that the corresponding ticket is auto-closed upon merge. \ diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 16b7e7aa709dd..eff2d2e3ff4a3 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -137,6 +137,10 @@ pub(crate) fn format_expr( ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) } + ast::ExprKind::Use(_, _) => { + // FIXME: properly implement this + Ok(context.snippet(expr.span()).to_owned()) + } ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr), ast::ExprKind::If(..) | ast::ExprKind::ForLoop { .. } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ba4a4c045f1c2..fe716c186389f 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -513,6 +513,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Become(..) | ast::ExprKind::Yeet(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) | ast::ExprKind::Yield(None) | ast::ExprKind::Underscore => false, diff --git a/tests/crashes/133426.rs b/tests/crashes/133426.rs deleted file mode 100644 index 307a94c0f6ca6..0000000000000 --- a/tests/crashes/133426.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133426 - -fn a( - _: impl Iterator< - Item = [(); { - match *todo!() { ! }; - }], - >, -) { -} - -fn b(_: impl Iterator) {} diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 905e1249d972d..152a6f3a41e64 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -44,22 +44,22 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index af5cc515bb224..53f1b827f9c6a 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -44,34 +44,34 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30 | LL | if local_passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 diff --git a/tests/ui/ergonomic-clones/async/basic.rs b/tests/ui/ergonomic-clones/async/basic.rs new file mode 100644 index 0000000000000..ad2bfd97cd1b5 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/basic.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ edition:2018 + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::future::Future; + +fn ergonomic_clone_async_closures() -> impl Future { + let s = String::from("hi"); + + async use { + s + } +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/async/edition-2015.rs b/tests/ui/ergonomic-clones/async/edition-2015.rs new file mode 100644 index 0000000000000..d3b2071b9f91f --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.rs @@ -0,0 +1,7 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + async use {}; + //~^ ERROR `async use` blocks are only allowed in Rust 2018 or later +} diff --git a/tests/ui/ergonomic-clones/async/edition-2015.stderr b/tests/ui/ergonomic-clones/async/edition-2015.stderr new file mode 100644 index 0000000000000..b218e6b242e19 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.stderr @@ -0,0 +1,8 @@ +error: `async use` blocks are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:5:5 + | +LL | async use {}; + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/ergonomic-clones/async/local-type.rs b/tests/ui/ergonomic-clones/async/local-type.rs new file mode 100644 index 0000000000000..e891686b550ae --- /dev/null +++ b/tests/ui/ergonomic-clones/async/local-type.rs @@ -0,0 +1,10 @@ +// Check that using the parameter name in its type does not ICE. +//@ edition:2018 + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let _ = async use |x: x| x; //~ ERROR expected type + let _ = async use |x: bool| -> x { x }; //~ ERROR expected type +} diff --git a/tests/ui/ergonomic-clones/async/local-type.stderr b/tests/ui/ergonomic-clones/async/local-type.stderr new file mode 100644 index 0000000000000..fd832fbc8d295 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/local-type.stderr @@ -0,0 +1,15 @@ +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:8:27 + | +LL | let _ = async use |x: x| x; + | ^ not a type + +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:9:36 + | +LL | let _ = async use |x: bool| -> x { x }; + | ^ not a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/ergonomic-clones/closure/basic.rs b/tests/ui/ergonomic-clones/closure/basic.rs new file mode 100644 index 0000000000000..01d3b08ffa27c --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/basic.rs @@ -0,0 +1,58 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; +use std::future::Future; + +fn ergonomic_clone_closure_no_captures() -> i32 { + let cl = use || { + 1 + }; + cl() +} + +fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + let cl = use || { + s + }; + cl() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + let f1 = use || { + f + }; + + let f2 = use || { + f + }; + + f +} + +fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + let i1 = use || { + i + }; + + let i2 = use || { + i + }; + + i +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/const-closure.rs b/tests/ui/ergonomic-clones/closure/const-closure.rs new file mode 100644 index 0000000000000..6b4de824df9ef --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/const-closure.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![feature(const_closures)] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +const fn foo() { + let cl = const use || {}; +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/expect-region.rs b/tests/ui/ergonomic-clones/closure/expect-region.rs new file mode 100644 index 0000000000000..cbb13e56a18a8 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/expect-region.rs @@ -0,0 +1,25 @@ +#![feature(ergonomic_clones)] +#![allow(warnings)] + +fn closure_expecting_bound(_: F) +where + F: FnOnce(&u32), +{ +} + +fn expect_bound_supply_named<'x>() { + let mut f: Option<&u32> = None; + + // Here we give a type annotation that `x` should be free. We get + // an error because of that. + closure_expecting_bound(use |x: &'x u32| { + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + + // Borrowck doesn't get a chance to run, but if it did it should error + // here. + f = Some(x); + }); +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/expect-region.stderr b/tests/ui/ergonomic-clones/closure/expect-region.stderr new file mode 100644 index 0000000000000..4df1df1378b8d --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/expect-region.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/expect-region.rs:15:34 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(use |x: &'x u32| { + | ^ - let's call the lifetime of this reference `'1` + | | + | requires that `'1` must outlive `'x` + +error: lifetime may not live long enough + --> $DIR/expect-region.rs:15:34 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(use |x: &'x u32| { + | ^ requires that `'x` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/ergonomic-clones/closure/fn-once.rs b/tests/ui/ergonomic-clones/closure/fn-once.rs new file mode 100644 index 0000000000000..24060f3ed3b8b --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/fn-once.rs @@ -0,0 +1,14 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn get_closure() -> Box Vec> { + let vec = vec![1u8, 2u8]; + + let closure = use || { //~ ERROR expected a closure + vec + }; + + Box::new(closure) +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/fn-once.stderr b/tests/ui/ergonomic-clones/closure/fn-once.stderr new file mode 100644 index 0000000000000..40f1200695cc3 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/fn-once.stderr @@ -0,0 +1,16 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/fn-once.rs:7:19 + | +LL | let closure = use || { + | ^^^^^^ this closure implements `FnOnce`, not `Fn` +LL | vec + | --- closure is `FnOnce` because it moves the variable `vec` out of its environment +... +LL | Box::new(closure) + | ----------------- the requirement to implement `Fn` derives from here + | + = note: required for the cast from `Box<{closure@$DIR/fn-once.rs:7:19: 7:25}>` to `Box<(dyn Fn() -> Vec + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0525`. diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed new file mode 100644 index 0000000000000..1e57063245272 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed @@ -0,0 +1,16 @@ +//@ run-rustfix + +// Point at the captured immutable outer variable + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let mut y = true; + foo(Box::new(use || y = !y) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable +} diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs new file mode 100644 index 0000000000000..59aa61f581d92 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs @@ -0,0 +1,16 @@ +//@ run-rustfix + +// Point at the captured immutable outer variable + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn foo(mut f: Box) { + f(); +} + +fn main() { + let y = true; + foo(Box::new(use || y = !y) as Box<_>); + //~^ ERROR cannot assign to `y`, as it is not declared as mutable +} diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr new file mode 100644 index 0000000000000..f7c742d33fda9 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr @@ -0,0 +1,14 @@ +error[E0594]: cannot assign to `y`, as it is not declared as mutable + --> $DIR/immutable-outer-variable.rs:14:25 + | +LL | foo(Box::new(use || y = !y) as Box<_>); + | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut y = true; + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/ergonomic-clones/closure/local-type.rs b/tests/ui/ergonomic-clones/closure/local-type.rs new file mode 100644 index 0000000000000..b2f99efa1e666 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/local-type.rs @@ -0,0 +1,9 @@ +// Check that using the parameter name in its type does not ICE. + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let _ = use |x: x| x; //~ ERROR expected type + let _ = use |x: bool| -> x { x }; //~ ERROR expected type +} diff --git a/tests/ui/ergonomic-clones/closure/local-type.stderr b/tests/ui/ergonomic-clones/closure/local-type.stderr new file mode 100644 index 0000000000000..5a42ae63afaf1 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/local-type.stderr @@ -0,0 +1,15 @@ +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:7:21 + | +LL | let _ = use |x: x| x; + | ^ not a type + +error[E0573]: expected type, found local variable `x` + --> $DIR/local-type.rs:8:30 + | +LL | let _ = use |x: bool| -> x { x }; + | ^ not a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/ergonomic-clones/closure/mutation.rs b/tests/ui/ergonomic-clones/closure/mutation.rs new file mode 100644 index 0000000000000..ef05fffd47993 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation.rs @@ -0,0 +1,12 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let mut my_var = false; + let mut callback = use || { + my_var = true; + }; + callback(); +} diff --git a/tests/ui/ergonomic-clones/closure/mutation2.rs b/tests/ui/ergonomic-clones/closure/mutation2.rs new file mode 100644 index 0000000000000..1cb5b8a7ec3f6 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation2.rs @@ -0,0 +1,11 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + let mut my_var = false; + let callback = use || { + my_var = true; + }; + callback(); + //~^ ERROR cannot borrow `callback` as mutable, as it is not declared as mutable [E0596] +} diff --git a/tests/ui/ergonomic-clones/closure/mutation2.stderr b/tests/ui/ergonomic-clones/closure/mutation2.stderr new file mode 100644 index 0000000000000..3ff33cf701748 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/mutation2.stderr @@ -0,0 +1,17 @@ +error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable + --> $DIR/mutation2.rs:9:5 + | +LL | my_var = true; + | ------ calling `callback` requires mutable binding due to possible mutation of `my_var` +LL | }; +LL | callback(); + | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut callback = use || { + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/ergonomic-clones/closure/nested.rs b/tests/ui/ergonomic-clones/closure/nested.rs new file mode 100644 index 0000000000000..fc364fb594b2c --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/nested.rs @@ -0,0 +1,21 @@ +//@ run-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn work(_: Box) {} +fn foo(_: F) {} + +pub fn main() { + let a = Box::new(Foo); + foo(use || { foo(use || { work(a) }) }); + let x = use || { use || { Foo } }; + let _y = x(); +} diff --git a/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs new file mode 100644 index 0000000000000..a8267ac5359f1 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs @@ -0,0 +1,19 @@ +//@ run-pass +// Testing guarantees provided by once functions. + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::sync::Arc; + +fn foo(blk: F) { + blk(); +} + +pub fn main() { + let x = Arc::new(true); + foo(use || { + assert!(*x); + drop(x); + }); +} diff --git a/tests/ui/ergonomic-clones/closure/parse.rs b/tests/ui/ergonomic-clones/closure/parse.rs new file mode 100644 index 0000000000000..0b3bfae0608ab --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/parse.rs @@ -0,0 +1,22 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn parse1() { + || use { + //~^ ERROR expected one of `async`, `|`, or `||`, found `{` + }; +} + +fn parse2() { + move use || { + //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `use` + }; +} + +fn parse3() { + use move || { + //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `move` + }; +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/closure/parse.stderr b/tests/ui/ergonomic-clones/closure/parse.stderr new file mode 100644 index 0000000000000..c37cb71394be8 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/parse.stderr @@ -0,0 +1,28 @@ +error: expected one of `async`, `|`, or `||`, found `{` + --> $DIR/parse.rs:5:12 + | +LL | || use { + | -- ^ expected one of `async`, `|`, or `||` + | | + | while parsing the body of this closure + | +help: you might have meant to open the body of the closure, instead of enclosing the closure in a block + | +LL ~ fn parse1() +LL ~ || { use { + | + +error: expected one of `async`, `|`, or `||`, found keyword `use` + --> $DIR/parse.rs:11:10 + | +LL | move use || { + | ^^^ expected one of `async`, `|`, or `||` + +error: expected one of `async`, `|`, or `||`, found keyword `move` + --> $DIR/parse.rs:17:9 + | +LL | use move || { + | ^^^^ expected one of `async`, `|`, or `||` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.rs b/tests/ui/ergonomic-clones/closure/print-verbose.rs new file mode 100644 index 0000000000000..e80d0d4b649a5 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print-verbose.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Zverbose-internals + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn to_fn_once(f: F) -> F { + f +} + +fn f(y: T) { + struct Foo { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(use || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.stderr b/tests/ui/ergonomic-clones/closure/print-verbose.stderr new file mode 100644 index 0000000000000..283405c79d61e --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print-verbose.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/print-verbose.rs:22:5 + | +LL | let c = to_fn_once(use || { + | - move occurs because `c` has type `{f::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)}`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/print-verbose.rs:21:5 + | +LL | c(); + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/print.rs b/tests/ui/ergonomic-clones/closure/print.rs new file mode 100644 index 0000000000000..c24a4cc5094be --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print.rs @@ -0,0 +1,26 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn to_fn_once(f: F) -> F { + f +} + +fn f(y: T) { + struct Foo { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(use || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/tests/ui/ergonomic-clones/closure/print.stderr b/tests/ui/ergonomic-clones/closure/print.stderr new file mode 100644 index 0000000000000..5f48059ebff29 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/print.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/print.rs:20:5 + | +LL | let c = to_fn_once(use || { + | - move occurs because `c` has type `{closure@$DIR/print.rs:15:24: 15:30}`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/print.rs:19:5 + | +LL | c(); + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/ergonomic-clones/closure/with-binders.rs b/tests/ui/ergonomic-clones/closure/with-binders.rs new file mode 100644 index 0000000000000..4260c252d9dd9 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/with-binders.rs @@ -0,0 +1,10 @@ +//@ edition:2021 +//@ check-pass + +#![feature(closure_lifetime_binder)] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn main() { + for<'a> use || -> () {}; +} diff --git a/tests/ui/ergonomic-clones/dotuse/basic.rs b/tests/ui/ergonomic-clones/dotuse/basic.rs new file mode 100644 index 0000000000000..8f962f079df75 --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/basic.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +use std::clone::UseCloned; + +fn basic_test(x: i32) -> i32 { + x.use.use.abs() +} + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn do_not_move_test(x: Foo) -> Foo { + let s = x.use; + x +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse/parse.rs b/tests/ui/ergonomic-clones/dotuse/parse.rs new file mode 100644 index 0000000000000..37ef5c37029cf --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/parse.rs @@ -0,0 +1,39 @@ +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +fn parse1() { + 1.use!; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + } + +fn parse2() { + 1.use!(2); + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + } + +fn parse3() { + 1.use 2; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + } + +fn parse4() { + 1.use? 2; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + } + +fn parse5() { + 1.use(); + //~^ ERROR: incorrect use of `use` +} + +fn parse6() { + 1.use(2); + //~^ ERROR: expected function, found `{integer}` [E0618] +} + +fn parse7() { + 1.use { 2 }; + //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` +} + +fn main() {} diff --git a/tests/ui/ergonomic-clones/dotuse/parse.stderr b/tests/ui/ergonomic-clones/dotuse/parse.stderr new file mode 100644 index 0000000000000..4b7a92534eda1 --- /dev/null +++ b/tests/ui/ergonomic-clones/dotuse/parse.stderr @@ -0,0 +1,53 @@ +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + --> $DIR/parse.rs:5:10 + | +LL | 1.use!; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!` + --> $DIR/parse.rs:10:10 + | +LL | 1.use!(2); + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + --> $DIR/parse.rs:15:11 + | +LL | 1.use 2; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2` + --> $DIR/parse.rs:20:12 + | +LL | 1.use? 2; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: incorrect use of `use` + --> $DIR/parse.rs:25:10 + | +LL | 1.use(); + | ^^ + | +help: `use` is not a method call, try removing the parentheses + | +LL - 1.use(); +LL + 1.use; + | + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/parse.rs:35:11 + | +LL | 1.use { 2 }; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error[E0618]: expected function, found `{integer}` + --> $DIR/parse.rs:30:5 + | +LL | 1.use(2); + | ^^^^^--- + | | + | call expression requires function + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0618`. diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs new file mode 100644 index 0000000000000..c2e44064cfad7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs @@ -0,0 +1,32 @@ +use std::clone::UseCloned; +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +fn ergonomic_clone(x: i32) -> i32 { + x.use + //~^ ERROR ergonomic clones are experimental [E0658] +} + +#[derive(Clone)] +struct Foo; + +fn foo() {} +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +impl UseCloned for Foo {} +//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658] + +fn ergonomic_closure_clone() { + let f1 = Foo; + + let f2 = use || { + //~^ ERROR ergonomic clones are experimental [E0658] + f1 + }; + + let f3 = use || { + //~^ ERROR ergonomic clones are experimental [E0658] + f1 + }; +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr new file mode 100644 index 0000000000000..cf92f2f28df80 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr @@ -0,0 +1,63 @@ +error[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:5:7 + | +LL | x.use + | ^^^ + | + = note: see issue #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[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:21:14 + | +LL | let f2 = use || { + | ^^^ + | + = note: see issue #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[E0658]: ergonomic clones are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:26:14 + | +LL | let f3 = use || { + | ^^^ + | + = note: see issue #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[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:1:5 + | +LL | use std::clone::UseCloned; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:12:11 + | +LL | fn foo() {} + | ^^^^^^^^^ + | + = note: see issue #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[E0658]: use of unstable library feature `ergonomic_clones` + --> $DIR/feature-gate-ergonomic-clones.rs:15:6 + | +LL | impl UseCloned for Foo {} + | ^^^^^^^^^ + | + = note: see issue #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 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs index 20999df9844eb..db23dcd5e5eb7 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs @@ -1,10 +1,10 @@ //@ check-pass -// this test checks that the `dead_code` lint is *NOT* being emited +// this test checks that the `dead_code` lint is *NOT* being emitted // for `foo` as `foo` is being used by `main`, and so the `#[expect]` // is unfulfilled // -// it also checks that the `dead_code` lint is also *NOT* emited +// it also checks that the `dead_code` lint is also *NOT* emitted // for `bar` as it's suppresed by the `#[expect]` on `bar` #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs index 08103b233872a..c4476e43e1ffc 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs @@ -1,7 +1,7 @@ //@ check-pass // this test makes sure that the `unfulfilled_lint_expectations` lint -// is being emited for `foo` as foo is not dead code, it's pub +// is being emitted for `foo` as foo is not dead code, it's pub #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs index f2625f0781f6e..ea2e81261d10c 100644 --- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs +++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs @@ -2,7 +2,7 @@ //@ revisions: allow expect // this test checks that no matter if we put #[allow(dead_code)] -// or #[expect(dead_code)], no warning is being emited +// or #[expect(dead_code)], no warning is being emitted #![warn(dead_code)] // to override compiletest diff --git a/tests/ui/lint/unused/must-use-ops.rs b/tests/ui/lint/unused/must-use-ops.rs index f61cf0fcfcb49..5085dbb58c19f 100644 --- a/tests/ui/lint/unused/must-use-ops.rs +++ b/tests/ui/lint/unused/must-use-ops.rs @@ -6,7 +6,7 @@ #![feature(never_type)] fn deref_never(x: &!) { - // Don't lint for uninhabited typess + // Don't lint for uninhabited types *x; } diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs new file mode 100644 index 0000000000000..fc3b51b40a545 --- /dev/null +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.rs @@ -0,0 +1,20 @@ +//! Test for the crash in #133426, caused by an empty symbol being used for a +//! type name. + +#![allow(incomplete_features)] +#![feature(never_patterns)] + +fn a( + _: impl Iterator< + Item = [(); { + match *todo!() { ! }; //~ ERROR type `!` cannot be dereferenced + }], + >, +) { +} + +fn b(_: impl Iterator) {} +//~^ ERROR associated const equality is incomplete +//~| ERROR expected type, found constant + +fn main() {} diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr new file mode 100644 index 0000000000000..555d8eec6babf --- /dev/null +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr @@ -0,0 +1,31 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/no-name-for-DefPath-issue-133426.rs:16:23 + | +LL | fn b(_: impl Iterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` 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[E0614]: type `!` cannot be dereferenced + --> $DIR/no-name-for-DefPath-issue-133426.rs:10:19 + | +LL | match *todo!() { ! }; + | ^^^^^^^^ can't be dereferenced + +error: expected type, found constant + --> $DIR/no-name-for-DefPath-issue-133426.rs:16:30 + | +LL | fn b(_: impl Iterator) {} + | ---- ^^^^^^^^^^^^^^^^^ unexpected constant + | | + | expected a type because of this associated type + | +note: the associated type is defined here + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0614, E0658. +For more information about an error, try `rustc --explain E0614`. diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs index 2fde37ce6acef..b08c830bfc76f 100644 --- a/tests/ui/parser/block-no-opening-brace.rs +++ b/tests/ui/parser/block-no-opening-brace.rs @@ -30,7 +30,7 @@ fn in_try() { // FIXME(#80931) fn in_async() { async - let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` + let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let` } // FIXME(#78168) diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index b65de4eac3f80..f51ee92626f53 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try` LL | try | ^^^ expected expression -error: expected one of `move`, `|`, or `||`, found keyword `let` +error: expected one of `move`, `use`, `|`, or `||`, found keyword `let` --> $DIR/block-no-opening-brace.rs:33:9 | LL | async - | - expected one of `move`, `|`, or `||` + | - expected one of `move`, `use`, `|`, or `||` LL | let x = 0; | ^^^ unexpected token diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr index a002d54dc9112..2507326fb2854 100644 --- a/tests/ui/parser/misspelled-keywords/async-move.stderr +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `|`, or `||`, found `Move` +error: expected one of `move`, `use`, `|`, or `||`, found `Move` --> $DIR/async-move.rs:4:11 | LL | async Move {} - | ^^^^ expected one of `move`, `|`, or `||` + | ^^^^ expected one of `move`, `use`, `|`, or `||` | help: write keyword `move` in lowercase | diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs index 10af39b700748..1f5004ad0998d 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.rs +++ b/tests/ui/parser/recover/recover-quantified-closure.rs @@ -7,6 +7,6 @@ fn main() { enum Foo { Bar } fn foo(x: impl Iterator) { for ::Bar in x {} - //~^ ERROR expected one of `move`, `static`, `|` + //~^ ERROR expected one of `move`, `static`, `use`, `|` //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr index 6e03bbb586959..48dea071ae64e 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.stderr +++ b/tests/ui/parser/recover/recover-quantified-closure.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `static`, `|`, or `||`, found `::` +error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::` --> $DIR/recover-quantified-closure.rs:9:14 | LL | for ::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^ expected one of `move`, `static`, `use`, `|`, or `||` error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5 diff --git a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs index d7ade7f0e96c5..009cc66f3f74e 100644 --- a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs +++ b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs @@ -5,7 +5,7 @@ #![deny(exported_private_dependencies)] // Ensure the libbar.rlib is loaded first. If the command line parameter `--extern foo` does not -// exist, previus version would fail to compile +// exist, previous version would fail to compile #![crate_type = "rlib"] extern crate bar; extern crate foo; diff --git a/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs new file mode 100644 index 0000000000000..9963b5be4f2b8 --- /dev/null +++ b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.rs @@ -0,0 +1,30 @@ +//@ edition:2021 +trait Trait {} + +struct Foo1 { + a: Trait, + //~^ ERROR expected a type, found a trait + b: u32, +} + +struct Foo2 { + a: i32, + b: Trait, + //~^ ERROR expected a type, found a trait +} + + +enum Enum1 { + A(Trait), + //~^ ERROR expected a type, found a trait + B(u32), +} + +enum Enum2 { + A(u32), + B(Trait), + //~^ ERROR expected a type, found a trait +} + + +fn main() {} diff --git a/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr new file mode 100644 index 0000000000000..433196919caf2 --- /dev/null +++ b/tests/ui/suggestions/suggest-struct-or-union-add-generic-impl-trait.stderr @@ -0,0 +1,51 @@ +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:5:8 + | +LL | a: Trait, + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ struct Foo1 { +LL ~ a: T, + | + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:12:8 + | +LL | b: Trait, + | ^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | b: dyn Trait, + | +++ + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:18:7 + | +LL | A(Trait), + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ enum Enum1 { +LL ~ A(T), + | + +error[E0782]: expected a type, found a trait + --> $DIR/suggest-struct-or-union-add-generic-impl-trait.rs:25:7 + | +LL | B(Trait), + | ^^^^^ + | +help: you might be missing a type parameter + | +LL ~ enum Enum2 { +LL | A(u32), +LL ~ B(T), + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0782`.