diff --git a/src/doc/unstable-book/src/compiler-flags/self-profile.md b/src/doc/unstable-book/src/compiler-flags/self-profile.md index 6de1c774f7cd7..7305141a42714 100644 --- a/src/doc/unstable-book/src/compiler-flags/self-profile.md +++ b/src/doc/unstable-book/src/compiler-flags/self-profile.md @@ -13,7 +13,7 @@ For example: First, run a compilation session and provide the `-Zself-profile` flag: ```console -$ rustc --crate-name foo -Zself-profile` +$ rustc --crate-name foo -Zself-profile ``` This will generate three files in the working directory such as: diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 00a171e6b5fb1..abf461338d80a 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -27,6 +27,7 @@ use crate::task::{Context, Poll}; #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] +#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")] pub trait Future { /// The type of value produced on completion. #[stable(feature = "futures_api", since = "1.36.0")] diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs index e23e2f2c1306f..bb7d59e113c08 100644 --- a/src/libprofiler_builtins/build.rs +++ b/src/libprofiler_builtins/build.rs @@ -24,6 +24,12 @@ fn main() { "InstrProfilingUtil.c", "InstrProfilingValue.c", "InstrProfilingWriter.c", + // This file was renamed in LLVM 10. + "InstrProfilingRuntime.cc", + "InstrProfilingRuntime.cpp", + // These files were added in LLVM 11. + "InstrProfilingInternal.c", + "InstrProfilingBiasVar.c", ]; if target.contains("msvc") { @@ -69,14 +75,12 @@ fn main() { let src_root = root.join("lib").join("profile"); for src in profile_sources { - cfg.file(src_root.join(src)); + let path = src_root.join(src); + if path.exists() { + cfg.file(path); + } } - // The file was renamed in LLVM 10. - let old_runtime_path = src_root.join("InstrProfilingRuntime.cc"); - let new_runtime_path = src_root.join("InstrProfilingRuntime.cpp"); - cfg.file(if old_runtime_path.exists() { old_runtime_path } else { new_runtime_path }); - cfg.include(root.join("include")); cfg.warnings(false); cfg.compile("profiler-rt"); diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index d2c4478ccfeb6..90a3a5ec64e0e 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; +use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_target::asm; use std::collections::hash_map::Entry; @@ -1361,9 +1361,14 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::Expr<'hir> { + let orig_head_span = head.span; // expand <head> let mut head = self.lower_expr_mut(head); - let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); + let desugared_span = self.mark_span_with_reason( + DesugaringKind::ForLoop(ForLoopLoc::Head), + orig_head_span, + None, + ); head.span = desugared_span; let iter = Ident::with_dummy_span(sym::iter); @@ -1458,10 +1463,16 @@ impl<'hir> LoweringContext<'_, 'hir> { // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); + let into_iter_span = self.mark_span_with_reason( + DesugaringKind::ForLoop(ForLoopLoc::IntoIter), + orig_head_span, + None, + ); + // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` let into_iter_expr = { let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter]; - self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head]) + self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head]) }; let match_expr = self.arena.alloc(self.expr_match( diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index d3e3441b087c2..9764c9a102e8a 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -797,6 +797,7 @@ pub unsafe fn optimize_thin_module( kind: ModuleKind::Regular, }; { + let target = &*module.module_llvm.tm; let llmod = module.module_llvm.llmod(); save_temp_bitcode(&cgcx, &module, "thin-lto-input"); @@ -833,7 +834,7 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) { + if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { let msg = "failed to prepare thin LTO module"; return Err(write::llvm_err(&diag_handler, msg)); } @@ -865,7 +866,7 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) { + if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { let msg = "failed to prepare thin LTO module"; return Err(write::llvm_err(&diag_handler, msg)); } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 8063d97aa73a9..7beb4fc897472 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -233,6 +233,8 @@ pub enum TypeKind { Metadata = 14, X86_MMX = 15, Token = 16, + ScalableVector = 17, + BFloat = 18, } impl TypeKind { @@ -255,6 +257,8 @@ impl TypeKind { TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata, TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX, TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token, + TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector, + TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat, } } } @@ -2141,10 +2145,18 @@ extern "C" { PreservedSymbols: *const *const c_char, PreservedSymbolsLen: c_uint, ) -> Option<&'static mut ThinLTOData>; - pub fn LLVMRustPrepareThinLTORename(Data: &ThinLTOData, Module: &Module) -> bool; + pub fn LLVMRustPrepareThinLTORename( + Data: &ThinLTOData, + Module: &Module, + Target: &TargetMachine, + ) -> bool; pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool; pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool; - pub fn LLVMRustPrepareThinLTOImport(Data: &ThinLTOData, Module: &Module) -> bool; + pub fn LLVMRustPrepareThinLTOImport( + Data: &ThinLTOData, + Module: &Module, + Target: &TargetMachine, + ) -> bool; pub fn LLVMRustGetThinLTOModuleImports( Data: *const ThinLTOData, ModuleNameCallback: ThinLTOModuleNameCallback, diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index 0d0321ec4ae5e..432b2f3bdc3c1 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -98,6 +98,8 @@ pub enum TypeKind { Metadata, X86_MMX, Token, + ScalableVector, + BFloat, } // FIXME(mw): Anything that is produced via DepGraph::with_task() must implement diff --git a/src/librustc_errors/json.rs b/src/librustc_errors/json.rs index 1382825922b0e..24186198fd2b1 100644 --- a/src/librustc_errors/json.rs +++ b/src/librustc_errors/json.rs @@ -36,6 +36,7 @@ pub struct JsonEmitter { pretty: bool, ui_testing: bool, json_rendered: HumanReadableErrorType, + terminal_width: Option<usize>, macro_backtrace: bool, } @@ -45,6 +46,7 @@ impl JsonEmitter { source_map: Lrc<SourceMap>, pretty: bool, json_rendered: HumanReadableErrorType, + terminal_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { @@ -54,6 +56,7 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, + terminal_width, macro_backtrace, } } @@ -61,6 +64,7 @@ impl JsonEmitter { pub fn basic( pretty: bool, json_rendered: HumanReadableErrorType, + terminal_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); @@ -69,6 +73,7 @@ impl JsonEmitter { Lrc::new(SourceMap::new(file_path_mapping)), pretty, json_rendered, + terminal_width, macro_backtrace, ) } @@ -79,6 +84,7 @@ impl JsonEmitter { source_map: Lrc<SourceMap>, pretty: bool, json_rendered: HumanReadableErrorType, + terminal_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { @@ -88,6 +94,7 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, + terminal_width, macro_backtrace, } } @@ -247,7 +254,13 @@ impl Diagnostic { let buf = BufWriter::default(); let output = buf.clone(); je.json_rendered - .new_emitter(Box::new(buf), Some(je.sm.clone()), false, None, je.macro_backtrace) + .new_emitter( + Box::new(buf), + Some(je.sm.clone()), + false, + je.terminal_width, + je.macro_backtrace, + ) .ui_testing(je.ui_testing) .emit_diagnostic(diag); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index cd6f034f7a5da..5aaf219b315bd 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -21,11 +21,26 @@ use rustc_span::Span; use lazy_static::lazy_static; +pub enum LangItemGroup { + Op, +} + +const NUM_GROUPS: usize = 1; + +macro_rules! expand_group { + () => { + None + }; + ($group:expr) => { + Some($group) + }; +} + // The actual lang items defined come at the end of this file in one handy table. // So you probably just want to nip down to the end. macro_rules! language_item_table { ( - $( $variant:ident, $name:expr, $method:ident, $target:expr; )* + $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )* ) => { enum_from_u32! { @@ -45,6 +60,13 @@ macro_rules! language_item_table { $( $variant => $name, )* } } + + pub fn group(self) -> Option<LangItemGroup> { + use LangItemGroup::*; + match self { + $( $variant => expand_group!($($group)*), )* + } + } } #[derive(HashStable_Generic)] @@ -54,6 +76,9 @@ macro_rules! language_item_table { pub items: Vec<Option<DefId>>, /// Lang items that were not found during collection. pub missing: Vec<LangItem>, + /// Mapping from `LangItemGroup` discriminants to all + /// `DefId`s of lang items in that group. + pub groups: [Vec<DefId>; NUM_GROUPS], } impl LanguageItems { @@ -64,6 +89,7 @@ macro_rules! language_item_table { Self { items: vec![$(init_none($variant)),*], missing: Vec::new(), + groups: [vec![]; NUM_GROUPS], } } @@ -79,6 +105,10 @@ macro_rules! language_item_table { self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) } + pub fn group(&self, group: LangItemGroup) -> &[DefId] { + self.groups[group as usize].as_ref() + } + $( /// Returns the corresponding `DefId` for the lang item #[doc = $name] @@ -171,30 +201,30 @@ language_item_table! { CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; - AddTraitLangItem, "add", add_trait, Target::Trait; - SubTraitLangItem, "sub", sub_trait, Target::Trait; - MulTraitLangItem, "mul", mul_trait, Target::Trait; - DivTraitLangItem, "div", div_trait, Target::Trait; - RemTraitLangItem, "rem", rem_trait, Target::Trait; - NegTraitLangItem, "neg", neg_trait, Target::Trait; - NotTraitLangItem, "not", not_trait, Target::Trait; - BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait; - BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait; - BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait; - ShlTraitLangItem, "shl", shl_trait, Target::Trait; - ShrTraitLangItem, "shr", shr_trait, Target::Trait; - AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait; - SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait; - MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait; - DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait; - RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait; - BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait; - BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait; - BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait; - ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait; - ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; - IndexTraitLangItem, "index", index_trait, Target::Trait; - IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; + AddTraitLangItem(Op), "add", add_trait, Target::Trait; + SubTraitLangItem(Op), "sub", sub_trait, Target::Trait; + MulTraitLangItem(Op), "mul", mul_trait, Target::Trait; + DivTraitLangItem(Op), "div", div_trait, Target::Trait; + RemTraitLangItem(Op), "rem", rem_trait, Target::Trait; + NegTraitLangItem(Op), "neg", neg_trait, Target::Trait; + NotTraitLangItem(Op), "not", not_trait, Target::Trait; + BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait; + BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait; + BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait; + ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait; + ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait; + AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait; + SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait; + MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait; + DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait; + RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait; + BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait; + BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait; + BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait; + ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait; + ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait; + IndexTraitLangItem(Op), "index", index_trait, Target::Trait; + IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait; UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; VaListTypeLangItem, "va_list", va_list, Target::Struct; diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 04d941fb8a7c4..1687bcc155636 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let msg = if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.desugaring_kind() { None => format!("consider giving `{}` {}", simple_ident, suffix), - Some(DesugaringKind::ForLoop) => { + Some(DesugaringKind::ForLoop(_)) => { "the element type for this iterator is not specified".to_string() } _ => format!("this needs {}", suffix), diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs index 6677c0e59f63a..20617bb8bd8fc 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -28,30 +28,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { br: &ty::BoundRegion, ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> { if let Some(anon_reg) = self.tcx().is_suitable_region(region) { - let def_id = anon_reg.def_id; - if let Some(def_id) = def_id.as_local() { - let hir_id = self.tcx().hir().as_local_hir_id(def_id); - let fndecl = match self.tcx().hir().get(hir_id) { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Fn(ref m, ..), - .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Fn(ref m, ..), - .. - }) => &m.decl, - _ => return None, - }; + let hir_id = self.tcx().hir().as_local_hir_id(anon_reg.def_id); + let fndecl = match self.tcx().hir().get(hir_id) { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Fn(ref m, ..), + .. + }) + | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Fn(ref m, ..), .. + }) => &m.decl, + _ => return None, + }; - return fndecl - .inputs - .iter() - .find_map(|arg| self.find_component_for_bound_region(arg, br)) - .map(|ty| (ty, &**fndecl)); - } + fndecl + .inputs + .iter() + .find_map(|arg| self.find_component_for_bound_region(arg, br)) + .map(|ty| (ty, &**fndecl)) + } else { + None } - None } // This method creates a FindNestedTypeVisitor which returns the type corresponding diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 3012928a09854..72deba990b0b5 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -75,8 +75,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { - let is_self_anon = self.is_self_anon(is_first, scope_def_id); - if is_self_anon { + if self.is_self_anon(is_first, scope_def_id) { return None; } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 46dad81a099bb..b6e971feb0e5f 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,219 +10,217 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> { debug!("try_report_static_impl_trait(error={:?})", self.error); - if let Some(ref error) = self.error { - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, - ) = error - { - debug!( - "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", - var_origin, sub_origin, sub_r, sup_origin, sup_r + if let Some(RegionResolutionError::SubSupConflict( + _, + var_origin, + ref sub_origin, + sub_r, + ref sup_origin, + sup_r, + )) = self.error + { + debug!( + "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", + var_origin, sub_origin, sub_r, sup_origin, sup_r + ); + let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; + debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); + let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + if fn_returns.is_empty() { + return None; + } + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); + if *sub_r == RegionKind::ReStatic { + let sp = var_origin.span(); + let return_sp = sub_origin.span(); + let param_info = self.find_param_with_region(sup_r, sub_r)?; + let (lifetime_name, lifetime) = if sup_r.has_name() { + (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + } else { + ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) + }; + let mut err = struct_span_err!( + self.tcx().sess, + sp, + E0759, + "cannot infer an appropriate lifetime" ); - let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); - let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id); - if fn_returns.is_empty() { - return None; - } - debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); - if **sub_r == RegionKind::ReStatic { - let sp = var_origin.span(); - let return_sp = sub_origin.span(); - let param_info = self.find_param_with_region(sup_r, sub_r)?; - let (lifetime_name, lifetime) = if sup_r.has_name() { - (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + err.span_label( + param_info.param_ty_span, + &format!("this data with {}...", lifetime), + ); + debug!("try_report_static_impl_trait: param_info={:?}", param_info); + + // We try to make the output have fewer overlapping spans if possible. + if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) + && sup_origin.span() != return_sp + { + // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` + + // Customize the spans and labels depending on their relative order so + // that split sentences flow correctly. + if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { + // Avoid the following: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ---------^- + // + // and instead show: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ^ + err.span_label( + sup_origin.span(), + "...is captured here, requiring it to live as long as `'static`", + ); } else { - ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) - }; - let mut err = struct_span_err!( - self.tcx().sess, - sp, - E0759, - "cannot infer an appropriate lifetime" - ); + err.span_label(sup_origin.span(), "...is captured here..."); + if return_sp < sup_origin.span() { + err.span_note( + return_sp, + "...and is required to live as long as `'static` here", + ); + } else { + err.span_label( + return_sp, + "...and is required to live as long as `'static` here", + ); + } + } + } else { err.span_label( - param_info.param_ty_span, - &format!("this data with {}...", lifetime), + return_sp, + "...is captured and required to live as long as `'static` here", ); - debug!("try_report_static_impl_trait: param_info={:?}", param_info); + } - // We try to make the output have fewer overlapping spans if possible. - if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) - && sup_origin.span() != return_sp - { - // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param_info.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = + format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = + format!("explicit `'static` bound to the lifetime of {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = + "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + for fn_return in fn_returns { + if fn_return.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + continue; + } + match fn_return.kind { + TyKind::OpaqueDef(item_id, _) => { + let item = self.tcx().hir().item(item_id.id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + err.emit(); + return Some(ErrorReported); + }; - // Customize the spans and labels depending on their relative order so - // that split sentences flow correctly. - if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { - // Avoid the following: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } - // | ---- ---------^- - // - // and instead show: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } - // | ---- ^ - err.span_label( - sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", - ); - } else { - err.span_label(sup_origin.span(), "...is captured here..."); - if return_sp < sup_origin.span() { - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", + if let Some(span) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some(*span), + _ => None, + }) + .next() + { + err.span_suggestion_verbose( + span, + &format!("{} `impl Trait`'s {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, ); + err.span_suggestion_verbose( + param_info.param_ty_span, + add_static_bound, + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } else if let Some(_) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { name, span, .. }) + if name.ident().to_string() == lifetime_name => + { + Some(*span) + } + _ => None, + }) + .next() + { } else { - err.span_label( - return_sp, - "...and is required to live as long as `'static` here", + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, ); } } - } else { - err.span_label( - return_sp, - "...is captured and required to live as long as `'static` here", - ); - } - - // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; - let arg = match param_info.param.pat.simple_ident() { - Some(simple_ident) => format!("argument `{}`", simple_ident), - None => "the argument".to_string(), - }; - let explicit = - format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = - format!("explicit `'static` bound to the lifetime of {}", arg); - let captures = format!("captures data from {}", arg); - let add_static_bound = - "alternatively, add an explicit `'static` bound to this reference"; - let plus_lt = format!(" + {}", lifetime_name); - for fn_return in fn_returns { - if fn_return.span.desugaring_kind().is_some() { - // Skip `async` desugaring `impl Future`. - continue; - } - match fn_return.kind { - TyKind::OpaqueDef(item_id, _) => { - let item = self.tcx().hir().item(item_id.id); - let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { - opaque - } else { - err.emit(); - return Some(ErrorReported); - }; - - if let Some(span) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { - name: LifetimeName::Static, - span, - .. - }) => Some(*span), - _ => None, - }) - .next() - { - err.span_suggestion_verbose( - span, - &format!("{} `impl Trait`'s {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } else if let Some(_) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { name, span, .. }) - if name.ident().to_string() == lifetime_name => - { - Some(*span) - } - _ => None, - }) - .next() - { - } else { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } + TyKind::TraitObject(_, lt) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt.clone(), + Applicability::MaybeIncorrect, + ); + } + name if name.ident().to_string() != lifetime_name => { + // With this check we avoid suggesting redundant bounds. This + // would happen if there are nested impl/dyn traits and only + // one of them has the bound we'd suggest already there, like + // in `impl Foo<X = dyn Bar> + '_`. + err.span_suggestion_verbose( + lt.span, + &format!("{} trait object's {}", consider, explicit_static), + lifetime_name.clone(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + add_static_bound, + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); } - TyKind::TraitObject(_, lt) => match lt.name { - LifetimeName::ImplicitObjectLifetimeDefault => { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!( - "{declare} trait object {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), - plus_lt.clone(), - Applicability::MaybeIncorrect, - ); - } - name if name.ident().to_string() != lifetime_name => { - // With this check we avoid suggesting redundant bounds. This - // would happen if there are nested impl/dyn traits and only - // one of them has the bound we'd suggest already there, like - // in `impl Foo<X = dyn Bar> + '_`. - err.span_suggestion_verbose( - lt.span, - &format!("{} trait object's {}", consider, explicit_static), - lifetime_name.clone(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion_verbose( - param_info.param_ty_span, - add_static_bound, - param_info.param_ty.to_string(), - Applicability::MaybeIncorrect, - ); - } - _ => {} - }, _ => {} - } + }, + _ => {} } - err.emit(); - return Some(ErrorReported); } + err.emit(); + return Some(ErrorReported); } } None diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs index 22b130cdf5ffe..fa999abb1a86c 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs @@ -3,7 +3,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, DefIdTree, Region, Ty}; use rustc_span::Span; @@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // FIXME(#42703) - Need to handle certain cases here. pub(super) fn is_return_type_anon( &self, - scope_def_id: DefId, + scope_def_id: LocalDefId, br: ty::BoundRegion, decl: &hir::FnDecl<'_>, ) -> Option<Span> { @@ -112,9 +112,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // corresponds to self and if yes, we display E0312. // FIXME(#42700) - Need to format self properly to // enable E0621 for it. - pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool { + pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> bool { is_first - && self.tcx().opt_associated_item(scope_def_id).map(|i| i.fn_has_self_parameter) + && self + .tcx() + .opt_associated_item(scope_def_id.to_def_id()) + .map(|i| i.fn_has_self_parameter) == Some(true) } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 814ca627e2cf8..d0275a0dd0dcb 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,7 +11,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -525,78 +525,82 @@ enum FfiResult<'tcx> { FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> }, } -fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { - ty::FnPtr(_) => true, - ty::Ref(..) => true, - ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { - for field in field_def.all_fields() { - let field_ty = - tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs)); - if field_ty.is_zst(tcx, field.did) { - continue; - } +impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { + /// Is type known to be non-null? + fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool { + match ty.kind { + ty::FnPtr(_) => true, + ty::Ref(..) => true, + ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => { + for field in field_def.all_fields() { + let field_ty = self.cx.tcx.normalize_erasing_regions( + self.cx.param_env, + field.ty(self.cx.tcx, substs), + ); + if field_ty.is_zst(self.cx.tcx, field.did) { + continue; + } - let attrs = tcx.get_attrs(field_def.did); - if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed)) - || ty_is_known_nonnull(tcx, field_ty) - { - return true; + let attrs = self.cx.tcx.get_attrs(field_def.did); + if attrs + .iter() + .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed)) + || self.ty_is_known_nonnull(field_ty) + { + return true; + } } - } - false + false + } + _ => false, } - _ => false, } -} -/// Check if this enum can be safely exported based on the -/// "nullable pointer optimization". Currently restricted -/// to function pointers, references, core::num::NonZero*, -/// core::ptr::NonNull, and #[repr(transparent)] newtypes. -/// FIXME: This duplicates code in codegen. -fn is_repr_nullable_ptr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - ty_def: &'tcx ty::AdtDef, - substs: SubstsRef<'tcx>, -) -> bool { - if ty_def.variants.len() != 2 { - return false; - } + /// Check if this enum can be safely exported based on the "nullable pointer optimization". + /// Currently restricted to function pointers, references, `core::num::NonZero*`, + /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. + fn is_repr_nullable_ptr( + &self, + ty: Ty<'tcx>, + ty_def: &'tcx ty::AdtDef, + substs: SubstsRef<'tcx>, + ) -> bool { + if ty_def.variants.len() != 2 { + return false; + } - let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields; - let variant_fields = [get_variant_fields(0), get_variant_fields(1)]; - let fields = if variant_fields[0].is_empty() { - &variant_fields[1] - } else if variant_fields[1].is_empty() { - &variant_fields[0] - } else { - return false; - }; + let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields; + let variant_fields = [get_variant_fields(0), get_variant_fields(1)]; + let fields = if variant_fields[0].is_empty() { + &variant_fields[1] + } else if variant_fields[1].is_empty() { + &variant_fields[0] + } else { + return false; + }; - if fields.len() != 1 { - return false; - } + if fields.len() != 1 { + return false; + } - let field_ty = fields[0].ty(tcx, substs); - if !ty_is_known_nonnull(tcx, field_ty) { - return false; - } + let field_ty = fields[0].ty(self.cx.tcx, substs); + if !self.ty_is_known_nonnull(field_ty) { + return false; + } - // At this point, the field's type is known to be nonnull and the parent enum is Option-like. - // If the computed size for the field and the enum are different, the nonnull optimization isn't - // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, ParamEnv::reveal_all()).unwrap(); - if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) { - bug!("improper_ctypes: Option nonnull optimization not applied?"); - } + // At this point, the field's type is known to be nonnull and the parent enum is + // Option-like. If the computed size for the field and the enum are different, the non-null + // optimization isn't being applied (and we've got a problem somewhere). + let compute_size_skeleton = + |t| SizeSkeleton::compute(t, self.cx.tcx, self.cx.param_env).unwrap(); + if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } - true -} + true + } -impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { if let ty::Array(..) = ty.kind { @@ -738,7 +742,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // discriminant. if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() { // Special-case types like `Option<extern fn()>`. - if !is_repr_nullable_ptr(cx, ty, def, substs) { + if !self.is_repr_nullable_ptr(ty, def, substs) { return FfiUnsafe { ty, reason: "enum has no representation hint".into(), diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 25e57aa77acd0..2254d553337d5 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1339,13 +1339,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Symbol] { + fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] { let param_names = match self.kind(id) { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names, EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names, _ => Lazy::empty(), }; - tcx.arena.alloc_from_iter(param_names.decode(self)) + tcx.arena.alloc_from_iter(param_names.decode((self, tcx))) } fn exported_symbols( diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index cdc8b5e90a642..d01c767e2bc04 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder, UseSpecializedEncodable}; use rustc_session::config::CrateType; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span}; use rustc_target::abi::VariantIdx; use std::hash::Hash; @@ -1004,18 +1004,12 @@ impl EncodeContext<'tcx> { } } - fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Symbol]> { - self.tcx.dep_graph.with_ignore(|| { - let body = self.tcx.hir().body(body_id); - self.lazy(body.params.iter().map(|arg| match arg.pat.kind { - hir::PatKind::Binding(_, _, ident, _) => ident.name, - _ => kw::Invalid, - })) - }) + fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> { + self.tcx.dep_graph.with_ignore(|| self.lazy(self.tcx.hir().body_param_names(body_id))) } - fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Symbol]> { - self.lazy(param_names.iter().map(|ident| ident.name)) + fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Ident]> { + self.lazy(param_names.iter()) } fn encode_optimized_mir(&mut self, def_id: LocalDefId) { diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 0edea63f922d6..381e7ee115e17 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -19,7 +19,7 @@ use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::CrateDisambiguator; use rustc_span::edition::Edition; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, Span}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -327,7 +327,7 @@ struct ModData { struct FnData { asyncness: hir::IsAsync, constness: hir::Constness, - param_names: Lazy<[Symbol]>, + param_names: Lazy<[Ident]>, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index 3a4fc581f5f26..75c10de9bbe5e 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -14,7 +14,7 @@ use rustc_hir::*; use rustc_index::vec::IndexVec; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -374,6 +374,13 @@ impl<'hir> Map<'hir> { }) } + pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir { + self.body(id).params.iter().map(|arg| match arg.pat.kind { + PatKind::Binding(_, _, ident, _) => ident, + _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP), + }) + } + /// Returns the `BodyOwnerKind` of this `LocalDefId`. /// /// Panics if `LocalDefId` does not have an associated body. @@ -451,11 +458,11 @@ impl<'hir> Map<'hir> { } } - pub fn visit_item_likes_in_module<V>(&self, module: DefId, visitor: &mut V) + pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V) where V: ItemLikeVisitor<'hir>, { - let module = self.tcx.hir_module_items(module.expect_local()); + let module = self.tcx.hir_module_items(module); for id in &module.items { visitor.visit_item(self.expect_item(*id)); diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs index 1e3676496ce39..e152d11c081a1 100644 --- a/src/librustc_middle/hir/mod.rs +++ b/src/librustc_middle/hir/mod.rs @@ -12,10 +12,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; -use rustc_hir::Body; -use rustc_hir::HirId; -use rustc_hir::ItemLocalId; -use rustc_hir::Node; +use rustc_hir::*; use rustc_index::vec::IndexVec; pub struct Owner<'tcx> { @@ -79,5 +76,20 @@ pub fn provide(providers: &mut Providers<'_>) { }; providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature; providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref(); + providers.fn_arg_names = |tcx, id| { + let hir = tcx.hir(); + let hir_id = hir.as_local_hir_id(id.expect_local()); + if let Some(body_id) = hir.maybe_body_owned_by(hir_id) { + tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) + } else if let Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(_, TraitFn::Required(idents)), + .. + }) = hir.get(hir_id) + { + tcx.arena.alloc_slice(idents) + } else { + span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); + } + }; map::provide(providers); } diff --git a/src/librustc_middle/lint.rs b/src/librustc_middle/lint.rs index 27239b4ad2e78..bb62c1bb82428 100644 --- a/src/librustc_middle/lint.rs +++ b/src/librustc_middle/lint.rs @@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>( pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false, ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 2f51b98085b4e..ba5a8c3ec2052 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -15,11 +15,11 @@ use rustc_query_system::query::QueryDescription; use rustc_span::symbol::Symbol; use std::borrow::Cow; -fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String { +fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { if def_id.is_top_level_module() { "top-level module".to_string() } else { - format!("module `{}`", tcx.def_path_str(def_id)) + format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) } } @@ -473,49 +473,49 @@ rustc_queries! { Other { query lint_mod(key: LocalDefId) -> () { - desc { |tcx| "linting {}", describe_as_module(key.to_def_id(), tcx) } + desc { |tcx| "linting {}", describe_as_module(key, tcx) } } /// Checks the attributes in the module. - query check_mod_attrs(key: DefId) -> () { + query check_mod_attrs(key: LocalDefId) -> () { desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) } } - query check_mod_unstable_api_usage(key: DefId) -> () { + query check_mod_unstable_api_usage(key: LocalDefId) -> () { desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } } /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`). - query check_mod_const_bodies(key: DefId) -> () { + query check_mod_const_bodies(key: LocalDefId) -> () { desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) } } /// Checks the loops in the module. - query check_mod_loops(key: DefId) -> () { + query check_mod_loops(key: LocalDefId) -> () { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_item_types(key: DefId) -> () { + query check_mod_item_types(key: LocalDefId) -> () { desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } } query check_mod_privacy(key: LocalDefId) -> () { - desc { |tcx| "checking privacy in {}", describe_as_module(key.to_def_id(), tcx) } + desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } } - query check_mod_intrinsics(key: DefId) -> () { + query check_mod_intrinsics(key: LocalDefId) -> () { desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } } - query check_mod_liveness(key: DefId) -> () { + query check_mod_liveness(key: LocalDefId) -> () { desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_impl_wf(key: DefId) -> () { + query check_mod_impl_wf(key: LocalDefId) -> () { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } } - query collect_mod_item_types(key: DefId) -> () { + query collect_mod_item_types(key: LocalDefId) -> () { desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } } @@ -729,7 +729,7 @@ rustc_queries! { } Other { - query fn_arg_names(def_id: DefId) -> &'tcx [Symbol] { + query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } } /// Gets the rendered value of the specified constant or associated constant. diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index df08e083d2cbb..44c8c1f6fdba4 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -873,8 +873,8 @@ impl<'tcx> CommonConsts<'tcx> { // conflict. #[derive(Debug)] pub struct FreeRegionInfo { - // def id corresponding to FreeRegion - pub def_id: DefId, + // `LocalDefId` corresponding to FreeRegion + pub def_id: LocalDefId, // the bound region corresponding to FreeRegion pub boundregion: ty::BoundRegion, // checks if bound region is in Impl Item @@ -1412,14 +1412,17 @@ impl<'tcx> TyCtxt<'tcx> { // Returns the `DefId` and the `BoundRegion` corresponding to the given region. pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> { let (suitable_region_binding_scope, bound_region) = match *region { - ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), - ty::ReEarlyBound(ref ebr) => { - (self.parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name)) + ty::ReFree(ref free_region) => { + (free_region.scope.expect_local(), free_region.bound_region) } + ty::ReEarlyBound(ref ebr) => ( + self.parent(ebr.def_id).unwrap().expect_local(), + ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ), _ => return None, // not a free region }; - let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope.expect_local()); + let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope); let is_impl_item = match self.hir().find(hir_id) { Some(Node::Item(..) | Node::TraitItem(..)) => false, Some(Node::ImplItem(..)) => { @@ -1436,8 +1439,11 @@ impl<'tcx> TyCtxt<'tcx> { } /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. - pub fn return_type_impl_or_dyn_traits(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> { - let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); + pub fn return_type_impl_or_dyn_traits( + &self, + scope_def_id: LocalDefId, + ) -> Vec<&'tcx hir::Ty<'tcx>> { + let hir_id = self.hir().as_local_hir_id(scope_def_id); let hir_output = match self.hir().get(hir_id) { Node::Item(hir::Item { kind: @@ -1480,9 +1486,9 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. - let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); + let hir_id = self.hir().as_local_hir_id(scope_def_id); match self.hir().get(hir_id) { Node::Item(item) => { match item.kind { @@ -1512,8 +1518,9 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool { - let container_id = self.associated_item(suitable_region_binding_scope).container.id(); + pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + let container_id = + self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { // For now, we do not try to target impls of traits. This is // because this message is going to suggest that the user diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 60a1fe0b19870..e85f69554d0c8 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -24,7 +24,8 @@ use crate::borrow_check::{ }; use super::{ - explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans, + explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, + RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -150,11 +151,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("value moved{} here, in previous iteration of loop", move_msg), ); } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); - move_spans.var_span_label( - &mut err, - format!("variable moved due to use{}", move_spans.describe()), - ); + if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = + move_spans + { + let place_name = self + .describe_place(moved_place.as_ref()) + .map(|n| format!("`{}`", n)) + .unwrap_or_else(|| "value".to_owned()); + match kind { + FnSelfUseKind::FnOnceCall => { + err.span_label( + fn_call_span, + &format!("{} moved due to this call", place_name), + ); + err.span_note( + var_span, + "this value implements `FnOnce`, which causes it to be moved when called", + ); + } + FnSelfUseKind::Operator { self_arg } => { + err.span_label( + fn_call_span, + &format!("{} moved due to usage in operator", place_name), + ); + if self.fn_self_span_reported.insert(fn_span) { + err.span_note( + self_arg.span, + "calling this operator moves the left-hand side", + ); + } + } + FnSelfUseKind::Normal { self_arg, implicit_into_iter } => { + if implicit_into_iter { + err.span_label( + fn_call_span, + &format!( + "{} moved due to this implicit call to `.into_iter()`", + place_name + ), + ); + } else { + err.span_label( + fn_call_span, + &format!("{} moved due to this method call", place_name), + ); + } + // Avoid pointing to the same function in multiple different + // error messages + if self.fn_self_span_reported.insert(self_arg.span) { + err.span_note( + self_arg.span, + &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name) + ); + } + } + } + } else { + err.span_label(move_span, format!("value moved{} here", move_msg)); + move_spans.var_span_label( + &mut err, + format!("variable moved due to use{}", move_spans.describe()), + ); + } } if let UseSpans::PatUse(span) = move_spans { err.span_suggestion_verbose( @@ -170,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { + if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { let sess = self.infcx.tcx.sess; if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) { err.span_suggestion( diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 849fd63998db4..b591b938b5ac3 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -509,7 +509,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Used in a closure. (LaterUseKind::ClosureCapture, var_span) } - UseSpans::PatUse(span) | UseSpans::OtherUse(span) => { + UseSpans::PatUse(span) + | UseSpans::OtherUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } => { let block = &self.body.basic_blocks()[location.block]; let kind = if let Some(&Statement { diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index 388076a9d60af..e94952e1c543c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -4,6 +4,7 @@ use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItemGroup; use rustc_hir::GeneratorKind; use rustc_middle::mir::{ AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, @@ -11,7 +12,11 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::{ + hygiene::{DesugaringKind, ForLoopLoc}, + symbol::sym, + Span, +}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -33,6 +38,7 @@ crate use mutability_errors::AccessKind; crate use outlives_suggestion::OutlivesSuggestionBuilder; crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; crate use region_name::{RegionName, RegionNameSource}; +use rustc_span::symbol::Ident; pub(super) struct IncludingDowncast(pub(super) bool); @@ -529,18 +535,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } -// The span(s) associated to a use of a place. +/// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) enum UseSpans { - // The access is caused by capturing a variable for a closure. + /// The access is caused by capturing a variable for a closure. ClosureUse { - // This is true if the captured variable was from a generator. + /// This is true if the captured variable was from a generator. generator_kind: Option<GeneratorKind>, - // The span of the args of the closure, including the `move` keyword if - // it's present. + /// The span of the args of the closure, including the `move` keyword if + /// it's present. args_span: Span, - // The span of the first use of the captured variable inside the closure. + /// The span of the first use of the captured variable inside the closure. + var_span: Span, + }, + /// The access is caused by using a variable as the receiver of a method + /// that takes 'self' + FnSelfUse { + /// The span of the variable being moved var_span: Span, + /// The span of the method call on the variable + fn_call_span: Span, + /// The definition span of the method being called + fn_span: Span, + kind: FnSelfUseKind, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -548,11 +565,22 @@ pub(super) enum UseSpans { OtherUse(Span), } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum FnSelfUseKind { + /// A normal method call of the form `receiver.foo(a, b, c)` + Normal { self_arg: Ident, implicit_into_iter: bool }, + /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` + FnOnceCall, + /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) + Operator { self_arg: Ident }, +} + impl UseSpans { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, } } @@ -561,6 +589,7 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) + | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, } } @@ -631,6 +660,7 @@ impl UseSpans { match self { closure @ UseSpans::ClosureUse { .. } => closure, UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), + fn_self @ UseSpans::FnSelfUse { .. } => fn_self, } } } @@ -733,25 +763,112 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind { - let def_id = match kind { + match kind { box AggregateKind::Closure(def_id, _) - | box AggregateKind::Generator(def_id, _, _) => def_id, - _ => return OtherUse(stmt.source_info.span), + | box AggregateKind::Generator(def_id, _, _) => { + debug!("move_spans: def_id={:?} places={:?}", def_id, places); + if let Some((args_span, generator_kind, var_span)) = + self.closure_span(*def_id, moved_place, places) + { + return ClosureUse { generator_kind, args_span, var_span }; + } + } + _ => {} + } + } + + let normal_ret = + if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { + PatUse(stmt.source_info.span) + } else { + OtherUse(stmt.source_info.span) }; - debug!("move_spans: def_id={:?} places={:?}", def_id, places); - if let Some((args_span, generator_kind, var_span)) = - self.closure_span(*def_id, moved_place, places) - { - return ClosureUse { generator_kind, args_span, var_span }; + // We are trying to find MIR of the form: + // ``` + // _temp = _moved_val; + // ... + // FnSelfCall(_temp, ...) + // ``` + // + // where `_moved_val` is the place we generated the move error for, + // `_temp` is some other local, and `FnSelfCall` is a function + // that has a `self` parameter. + + let target_temp = match stmt.kind { + StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => { + temp.as_local().unwrap() } - } + _ => return normal_ret, + }; - if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { - PatUse(stmt.source_info.span) - } else { - OtherUse(stmt.source_info.span) + debug!("move_spans: target_temp = {:?}", target_temp); + + if let Some(Terminator { + kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. }, + .. + }) = &self.body[location.block].terminator + { + let mut method_did = None; + if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { + if let ty::FnDef(def_id, _) = ty.kind { + debug!("move_spans: fn = {:?}", def_id); + if let Some(ty::AssocItem { fn_has_self_parameter, .. }) = + self.infcx.tcx.opt_associated_item(def_id) + { + if *fn_has_self_parameter { + method_did = Some(def_id); + } + } + } + } + + let tcx = self.infcx.tcx; + let method_did = if let Some(did) = method_did { did } else { return normal_ret }; + + if let [Operand::Move(self_place), ..] = **args { + if self_place.as_local() == Some(target_temp) { + let parent = tcx.parent(method_did); + let is_fn_once = parent == tcx.lang_items().fn_once_trait(); + let is_operator = !from_hir_call + && parent.map_or(false, |p| { + tcx.lang_items().group(LangItemGroup::Op).contains(&p) + }); + let fn_call_span = *fn_span; + + let self_arg = tcx.fn_arg_names(method_did)[0]; + + let kind = if is_fn_once { + FnSelfUseKind::FnOnceCall + } else if is_operator { + FnSelfUseKind::Operator { self_arg } + } else { + debug!( + "move_spans: method_did={:?}, fn_call_span={:?}", + method_did, fn_call_span + ); + let implicit_into_iter = matches!( + fn_call_span.desugaring_kind(), + Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ); + FnSelfUseKind::Normal { self_arg, implicit_into_iter } + }; + + return FnSelfUse { + var_span: stmt.source_info.span, + fn_call_span, + fn_span: self + .infcx + .tcx + .sess + .source_map() + .guess_head_span(self.infcx.tcx.def_span(method_did)), + kind, + }; + } + } } + return normal_ret; } /// Finds the span of arguments of a closure (within `maybe_closure_span`) diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index b49e4187fb810..4883b08e42442 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -408,7 +408,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { format!("{}.as_ref()", snippet), Applicability::MaybeIncorrect, ); - } else if span.is_desugaring(DesugaringKind::ForLoop) + } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) && self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) { // FIXME: suggest for anything that implements `IntoIterator`. diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 4d4b6fb9386db..b4bc89e827daa 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -365,7 +365,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); match opt_desugaring_kind { // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop) => Some(( + Some(DesugaringKind::ForLoop(_)) => Some(( false, opt_assignment_rhs_span.unwrap(), format!( diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index f1923b9e81c66..99b9788c20b05 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -579,7 +579,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let (Some(f), Some(ty::RegionKind::ReStatic)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - if let Some((ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self + if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self .infcx .tcx .is_suitable_region(f) @@ -592,7 +592,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // eg. check for `impl Trait + 'static` instead of `impl Trait`. let has_static_predicate = { - let predicates_of = self.infcx.tcx.predicates_of(*did); + let predicates_of = self.infcx.tcx.predicates_of(did); let bounds = predicates_of.instantiate(self.infcx.tcx, substs); let mut found = false; @@ -625,7 +625,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str)); } else { // Otherwise, we should suggest adding a constraint on the return type. - let span = self.infcx.tcx.def_span(*did); + let span = self.infcx.tcx.def_span(did); if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { let suggestable_fr_name = if fr_name.was_named() { fr_name.to_string() diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 03b663eb75056..83691d439eb81 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -278,6 +278,7 @@ fn do_mir_borrowck<'a, 'tcx>( move_data: &move_data, location_table: &LocationTable::new(promoted_body), movable_generator, + fn_self_span_reported: Default::default(), locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), @@ -311,6 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>( location_table, movable_generator, locals_are_invalidated_at_exit, + fn_self_span_reported: Default::default(), access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), reservation_warnings: Default::default(), @@ -487,6 +489,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { // but it is currently inconvenient to track down the `BorrowIndex` // at the time we detect and report a reservation error. reservation_error_reported: FxHashSet<Place<'tcx>>, + /// This fields keeps track of the `Span`s that we have + /// used to report extra information for `FnSelfUse`, to avoid + /// unnecessarily verbose errors. + fn_self_span_reported: FxHashSet<Span>, /// Migration warnings to be reported for #56254. We delay reporting these /// so that we can suppress the warning if there's a corresponding error /// for the activation of the borrow. diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs index 3003f4639d9fa..7b292ee71f99d 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/src/librustc_mir/borrow_check/universal_regions.rs @@ -232,8 +232,7 @@ impl<'tcx> UniversalRegions<'tcx> { ) -> Self { let tcx = infcx.tcx; let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id); - UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env } - .build() + UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build() } /// Given a reference to a closure type, extracts all the values @@ -389,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> { struct UniversalRegionsBuilder<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, - mir_def_id: DefId, + mir_def_id: LocalDefId, mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, } @@ -418,7 +417,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id); + let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id()); // If this is a closure or generator, then the late-bound regions from the enclosing // function are actually external regions to us. For example, here, 'a is not local @@ -426,7 +425,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // fn foo<'a>() { // let c = || { let x: &'a u32 = ...; } // } - if self.mir_def_id != closure_base_def_id { + if self.mir_def_id.to_def_id() != closure_base_def_id { self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices) } @@ -443,7 +442,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ); // Converse of above, if this is a function then the late-bound regions declared on its // signature are local to the fn. - if self.mir_def_id == closure_base_def_id { + if self.mir_def_id.to_def_id() == closure_base_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices); } @@ -508,14 +507,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id); + let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id()); match tcx.hir().body_owner_kind(self.mir_hir_id) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def_id == closure_base_def_id { + let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id { tcx.type_of(closure_base_def_id) } else { - let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local()); + let tables = tcx.typeck_tables_of(self.mir_def_id); tables.node_type(self.mir_hir_id) }; @@ -540,11 +539,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - assert_eq!(closure_base_def_id, self.mir_def_id); + assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs); - DefiningTy::Const(self.mir_def_id, substs) + DefiningTy::Const(self.mir_def_id.to_def_id(), substs) } } } @@ -559,7 +558,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id); + let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id()); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let fr_substs = match defining_ty { DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { @@ -593,7 +592,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let tcx = self.infcx.tcx; match defining_ty { DefiningTy::Closure(def_id, substs) => { - assert_eq!(self.mir_def_id, def_id); + assert_eq!(self.mir_def_id.to_def_id(), def_id); let closure_sig = substs.as_closure().sig(); let inputs_and_output = closure_sig.inputs_and_output(); let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap(); @@ -617,7 +616,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } DefiningTy::Generator(def_id, substs, movability) => { - assert_eq!(self.mir_def_id, def_id); + assert_eq!(self.mir_def_id.to_def_id(), def_id); let resume_ty = substs.as_generator().resume_ty(); let output = substs.as_generator().return_ty(); let generator_ty = tcx.mk_generator(def_id, substs, movability); @@ -635,7 +634,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::Const(def_id, _) => { // For a constant body, there are no inputs, and one // "output" (the type of the constant). - assert_eq!(self.mir_def_id, def_id); + assert_eq!(self.mir_def_id.to_def_id(), def_id); let ty = tcx.type_of(def_id); let ty = indices.fold_to_region_vids(tcx, &ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) @@ -656,7 +655,7 @@ trait InferCtxtExt<'tcx> { fn replace_bound_regions_with_nll_infer_vars<T>( &self, origin: NLLRegionVariableOrigin, - all_outlive_scope: DefId, + all_outlive_scope: LocalDefId, value: &ty::Binder<T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T @@ -665,7 +664,7 @@ trait InferCtxtExt<'tcx> { fn replace_late_bound_regions_with_nll_infer_vars( &self, - mir_def_id: DefId, + mir_def_id: LocalDefId, indices: &mut UniversalRegionIndices<'tcx>, ); } @@ -685,7 +684,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_bound_regions_with_nll_infer_vars<T>( &self, origin: NLLRegionVariableOrigin, - all_outlive_scope: DefId, + all_outlive_scope: LocalDefId, value: &ty::Binder<T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T @@ -699,7 +698,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: all_outlive_scope, + scope: all_outlive_scope.to_def_id(), bound_region: br, })); let region_vid = self.next_nll_region_var(origin); @@ -724,11 +723,11 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// inputs vector. fn replace_late_bound_regions_with_nll_infer_vars( &self, - mir_def_id: DefId, + mir_def_id: LocalDefId, indices: &mut UniversalRegionIndices<'tcx>, ) { debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); - let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id); + let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); if !indices.indices.contains_key(&r) { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 95e193b625354..9c72a18c6d469 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::ty::layout::{self, TyAndLayout}; use rustc_middle::ty::{ - self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable, + self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, }; use rustc_span::{source_map::DUMMY_SP, Span}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; @@ -24,6 +24,7 @@ use super::{ Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, ScalarMaybeUninit, StackPopJump, }; +use crate::transform::validate::equal_up_to_regions; use crate::util::storage::AlwaysLiveLocals; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { @@ -220,42 +221,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, src: TyAndLayout<'tcx>, dest: TyAndLayout<'tcx>, ) -> bool { - if src.ty == dest.ty { - // Equal types, all is good. - return true; - } - if src.layout != dest.layout { - // Layout differs, definitely not equal. - // We do this here because Miri would *do the wrong thing* if we allowed layout-changing - // assignments. - return false; - } - - // Type-changing assignments can happen for (at least) two reasons: - // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment. - // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types - // with their late-bound lifetimes are still around and can lead to type differences. - // Normalize both of them away. - let normalize = |ty: Ty<'tcx>| { - ty.fold_with(&mut BottomUpFolder { - tcx, - // Normalize all references to immutable. - ty_op: |ty| match ty.kind { - ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee), - _ => ty, - }, - // We just erase all late-bound lifetimes, but this is not fully correct (FIXME): - // lifetimes in invariant positions could matter (e.g. through associated types). - // We rely on the fact that layout was confirmed to be equal above. - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts unchanged. - ct_op: |ct| ct, - }) - }; - normalize(src.ty) == normalize(dest.ty) + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) { + // Make sure the layout is equal, too -- just to be safe. Miri really + // needs layout equality. For performance reason we skip this check when + // the types are equal. Equal types *can* have different layouts when + // enum downcast is involved (as enum variants carry the type of the + // enum), but those should never occur in assignments. + if cfg!(debug_assertions) || src.ty != dest.ty { + assert_eq!(src.layout, dest.layout); + } + true + } else { + false + } } /// Use the already known layout if given (but sanity check in debug mode), @@ -263,6 +249,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( #[cfg_attr(not(debug_assertions), inline(always))] pub(super) fn from_known_layout<'tcx>( tcx: TyCtxtAt<'tcx>, + param_env: ParamEnv<'tcx>, known_layout: Option<TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -271,7 +258,7 @@ pub(super) fn from_known_layout<'tcx>( Some(known_layout) => { if cfg!(debug_assertions) { let check_layout = compute()?; - if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) { + if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { span_bug!( tcx.span, "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", @@ -475,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // have to support that case (mostly by skipping all caching). match frame.locals.get(local).and_then(|state| state.layout.get()) { None => { - let layout = from_known_layout(self.tcx, layout, || { + let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index dd746f5cfb409..fd55deaf83bba 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -488,6 +488,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Sanity-check the type we ended up with. debug_assert!(mir_assign_valid_types( *self.tcx, + self.param_env, self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( place.ty(&self.frame().body.local_decls, *self.tcx).ty ))?, @@ -570,7 +571,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // documentation). let val_val = M::adjust_global_const(self, val_val)?; // Other cases need layout. - let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?; + let layout = + from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.create_memory_alloc(alloc); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 396aec0a8f89f..98a1cea97e220 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -652,6 +652,7 @@ where // Sanity-check the type we ended up with. debug_assert!(mir_assign_valid_types( *self.tcx, + self.param_env, self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( place.ty(&self.frame().body.local_decls, *self.tcx).ty ))?, @@ -855,7 +856,7 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) { + if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { span_bug!( self.cur_span(), "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", @@ -912,7 +913,7 @@ where src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) { + if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { // Fast path: Just use normal `copy_op` return self.copy_op(src, dest); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e1c5a4f5b1885..a891f12c8e15f 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -512,6 +512,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // This is basically `force_bits`. let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok()); if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { + debug!("check_binary_op: reporting assert for {:?}", source_info); self.report_assert_as_lint( lint::builtin::ARITHMETIC_OVERFLOW, source_info, diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index c5343d9b5d014..d3f486c815e6c 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -7,7 +7,11 @@ use rustc_middle::{ BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }, - ty::{self, ParamEnv, TyCtxt}, + ty::{ + self, + relate::{Relate, RelateResult, TypeRelation}, + ParamEnv, Ty, TyCtxt, + }, }; #[derive(Copy, Clone, Debug)] @@ -28,6 +32,98 @@ impl<'tcx> MirPass<'tcx> for Validator { } } +/// Returns whether the two types are equal up to lifetimes. +/// All lifetimes, including higher-ranked ones, get ignored for this comparison. +/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.) +/// +/// The point of this function is to approximate "equal up to subtyping". However, +/// the approximation is incorrect as variance is ignored. +pub fn equal_up_to_regions( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + // Fast path. + if src == dest { + return true; + } + + struct LifetimeIgnoreRelation<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + } + + impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn tag(&self) -> &'static str { + "librustc_mir::transform::validate" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance<T: Relate<'tcx>>( + &mut self, + _: ty::Variance, + a: &T, + b: &T, + ) -> RelateResult<'tcx, T> { + // Ignore variance, require types to be exactly the same. + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + if a == b { + // Short-circuit. + return Ok(a); + } + ty::relate::super_relate_tys(self, a, b) + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + _b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + // Ignore regions. + Ok(a) + } + + fn consts( + &mut self, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + ty::relate::super_relate_consts(self, a, b) + } + + fn binders<T>( + &mut self, + a: &ty::Binder<T>, + b: &ty::Binder<T>, + ) -> RelateResult<'tcx, ty::Binder<T>> + where + T: Relate<'tcx>, + { + self.relate(a.skip_binder(), b.skip_binder())?; + Ok(a.clone()) + } + } + + // Instantiate and run relation. + let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env }; + relator.relate(&src, &dest).is_ok() +} + struct TypeChecker<'a, 'tcx> { when: &'a str, source: MirSource<'tcx>, @@ -81,6 +177,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) } } + + /// Check if src can be assigned into dest. + /// This is not precise, it will accept some incorrect assignments. + fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { + // Fast path before we normalize. + if src == dest { + // Equal types, all is good. + return true; + } + // Normalize projections and things like that. + // FIXME: We need to reveal_all, as some optimizations change types in ways + // that require unfolding opaque types. + let param_env = self.param_env.with_reveal_all(); + let src = self.tcx.normalize_erasing_regions(param_env, src); + let dest = self.tcx.normalize_erasing_regions(param_env, dest); + + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + equal_up_to_regions(self.tcx, param_env, src, dest) + } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -99,20 +217,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - // The sides of an assignment must not alias. Currently this just checks whether the places - // are identical. - if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind { - match rvalue { - Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); + match &statement.kind { + StatementKind::Assign(box (dest, rvalue)) => { + // LHS and RHS of the assignment must have the same type. + let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty; + let right_ty = rvalue.ty(&self.body.local_decls, self.tcx); + if !self.mir_assign_valid_types(right_ty, left_ty) { + self.fail( + location, + format!( + "encountered `Assign` statement with incompatible types:\n\ + left-hand side has type: {}\n\ + right-hand side has type: {}", + left_ty, right_ty, + ), + ); + } + // The sides of an assignment must not alias. Currently this just checks whether the places + // are identical. + match rvalue { + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { + if dest == src { + self.fail( + location, + "encountered `Assign` statement with overlapping memory", + ); + } } + _ => {} } - _ => {} } + _ => {} } } diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 408f2e8c19a5d..ef84f251390e6 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -12,7 +12,7 @@ use rustc_ast::ast::{Attribute, NestedMetaItem}; use rustc_ast::attr; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{self, HirId, Item, ItemKind, TraitItem}; use rustc_hir::{MethodKind, Target}; @@ -464,7 +464,7 @@ fn is_c_like_enum(item: &Item<'_>) -> bool { } } -fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir() .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor()); } diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 94f9c619a3a26..90a076eeded7e 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -9,7 +9,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; @@ -62,7 +62,7 @@ impl NonConstExpr { } } -fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let mut vis = CheckConstVisitor::new(tcx); tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor()); } diff --git a/src/librustc_passes/hir_id_validator.rs b/src/librustc_passes/hir_id_validator.rs index 80dfcd9c2417a..2edbc29b7efb6 100644 --- a/src/librustc_passes/hir_id_validator.rs +++ b/src/librustc_passes/hir_id_validator.rs @@ -17,7 +17,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| { let local_def_id = hir_map.local_def_id(*module_id); hir_map.visit_item_likes_in_module( - local_def_id.to_def_id(), + local_def_id, &mut OuterVisitor { hir_map, errors: &errors }, ); }); diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index c8666ba1fd078..683039df15ac6 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -2,7 +2,7 @@ use rustc_ast::ast::{FloatTy, InlineAsmTemplatePiece, IntTy, UintTy}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_index::vec::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; @@ -14,7 +14,7 @@ use rustc_target::abi::{Pointer, VariantIdx}; use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType}; use rustc_target::spec::abi::Abi::RustIntrinsic; -fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor()); } diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index f4167c8644e6e..0be37cb096038 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -102,7 +102,8 @@ impl LanguageItemCollector<'tcx> { // Check for duplicates. if let Some(original_def_id) = self.items.items[item_index] { if original_def_id != item_def_id { - let name = LangItem::from_u32(item_index as u32).unwrap().name(); + let lang_item = LangItem::from_u32(item_index as u32).unwrap(); + let name = lang_item.name(); let mut err = match self.tcx.hir().span_if_local(item_def_id) { Some(span) => struct_span_err!( self.tcx.sess, @@ -152,6 +153,9 @@ impl LanguageItemCollector<'tcx> { // Matched. self.items.items[item_index] = Some(item_def_id); + if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() { + self.items.groups[group as usize].push(item_def_id); + } } } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index ff5dabd5418c9..798c6b8925bbf 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -89,7 +89,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::*; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node}; use rustc_middle::hir::map::Map; @@ -172,7 +172,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } } -fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(), @@ -248,7 +248,7 @@ enum VarKind { struct IrMaps<'tcx> { tcx: TyCtxt<'tcx>, - body_owner: DefId, + body_owner: LocalDefId, num_live_nodes: usize, num_vars: usize, live_node_map: HirIdMap<LiveNode>, @@ -259,7 +259,7 @@ struct IrMaps<'tcx> { } impl IrMaps<'tcx> { - fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> { + fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> { IrMaps { tcx, body_owner, @@ -349,7 +349,7 @@ fn visit_fn<'tcx>( // swap in a new set of IR maps for this function body: let def_id = ir.tcx.hir().local_def_id(id); - let mut fn_maps = IrMaps::new(ir.tcx, def_id.to_def_id()); + let mut fn_maps = IrMaps::new(ir.tcx, def_id); // Don't run unused pass for #[derive()] if let FnKind::Method(..) = fk { @@ -484,7 +484,7 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { } ir.set_captures(expr.hir_id, call_caps); let old_body_owner = ir.body_owner; - ir.body_owner = closure_def_id.to_def_id(); + ir.body_owner = closure_def_id; intravisit::walk_expr(ir, expr); ir.body_owner = old_body_owner; } @@ -937,7 +937,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for (&var_hir_id, upvar) in upvars.iter().rev() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner.expect_local(), + closure_expr_id: self.ir.body_owner, }; match self.tables.upvar_capture(upvar_id) { ty::UpvarCapture::ByRef(_) => { @@ -1614,7 +1614,7 @@ impl<'tcx> Liveness<'_, 'tcx> { let var = self.variable(var_hir_id, upvar.span); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner.expect_local(), + closure_expr_id: self.ir.body_owner, }; match self.tables.upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => {} diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 767a6909d31d4..d7012d4d711df 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -2,7 +2,7 @@ use Context::*; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; @@ -29,7 +29,7 @@ struct CheckLoopVisitor<'a, 'hir> { cx: Context, } -fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(), diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 054748c09fc44..ad512c63352f1 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Generics, HirId, Item, StructField, Variant}; use rustc_middle::hir::map::Map; @@ -472,7 +472,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { /// Cross-references the feature names of unstable APIs with enabled /// features and possibly prints errors. -fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor()); } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 2ea312c42dc64..fcd5dab94a6c2 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -1061,8 +1061,15 @@ fn default_emitter( } } (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( - JsonEmitter::stderr(Some(registry), source_map, pretty, json_rendered, macro_backtrace) - .ui_testing(sopts.debugging_opts.ui_testing), + JsonEmitter::stderr( + Some(registry), + source_map, + pretty, + json_rendered, + sopts.debugging_opts.terminal_width, + macro_backtrace, + ) + .ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( JsonEmitter::new( @@ -1071,6 +1078,7 @@ fn default_emitter( source_map, pretty, json_rendered, + sopts.debugging_opts.terminal_width, macro_backtrace, ) .ui_testing(sopts.debugging_opts.ui_testing), @@ -1416,7 +1424,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false)) } config::ErrorOutputType::Json { pretty, json_rendered } => { - Box::new(JsonEmitter::basic(pretty, json_rendered, false)) + Box::new(JsonEmitter::basic(pretty, json_rendered, None, false)) } }; let handler = rustc_errors::Handler::with_emitter(true, None, emitter); @@ -1431,7 +1439,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false)) } config::ErrorOutputType::Json { pretty, json_rendered } => { - Box::new(JsonEmitter::basic(pretty, json_rendered, false)) + Box::new(JsonEmitter::basic(pretty, json_rendered, None, false)) } }; let handler = rustc_errors::Handler::with_emitter(true, None, emitter); diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs index c0fb84e741f4a..60bbdd0495cc4 100644 --- a/src/librustc_span/hygiene.rs +++ b/src/librustc_span/hygiene.rs @@ -822,7 +822,14 @@ pub enum DesugaringKind { OpaqueTy, Async, Await, - ForLoop, + ForLoop(ForLoopLoc), +} + +/// A location in the desugaring of a `for` loop +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)] +pub enum ForLoopLoc { + Head, + IntoIter, } impl DesugaringKind { @@ -835,7 +842,7 @@ impl DesugaringKind { DesugaringKind::QuestionMark => "operator `?`", DesugaringKind::TryBlock => "`try` block", DesugaringKind::OpaqueTy => "`impl Trait`", - DesugaringKind::ForLoop => "`for` loop", + DesugaringKind::ForLoop(_) => "`for` loop", } } } diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 9624006683467..dcd2e83b74713 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -30,8 +30,9 @@ use source_map::SourceMap; pub mod edition; use edition::Edition; pub mod hygiene; +pub use hygiene::SyntaxContext; use hygiene::Transparency; -pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext}; +pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind}; pub mod def_id; use def_id::{CrateNum, DefId, LOCAL_CRATE}; mod span_encoding; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0325782e69d51..7c4048ab22302 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -737,7 +737,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { tcx.hir().krate().par_visit_all_item_likes(&visit); } -fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 054165f2b0977..b486e3d3536c9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -55,7 +55,7 @@ struct OnlySelfBounds(bool); /////////////////////////////////////////////////////////////////////////// // Main entry point -fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module( module_def_id, &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(), diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 37d383db68ab6..77cd1b3de0106 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -14,7 +14,7 @@ use min_specialization::check_min_specialization; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; @@ -59,11 +59,11 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) { // but it's one that we must perform earlier than the rest of // WfCheck. for &module in tcx.hir().krate().modules.keys() { - tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module).to_def_id()); + tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module)); } } -fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) { +fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let min_specialization = tcx.features().min_specialization; tcx.hir() .visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx, min_specialization }); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8ab6c74289d17..38f202e84accb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -193,8 +193,15 @@ pub fn new_handler( Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty())) }); Box::new( - JsonEmitter::stderr(None, source_map, pretty, json_rendered, false) - .ui_testing(debugging_opts.ui_testing), + JsonEmitter::stderr( + None, + source_map, + pretty, + json_rendered, + debugging_opts.terminal_width, + false, + ) + .ui_testing(debugging_opts.ui_testing), ) } }; diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f4c164a324e32..17f890375f843 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1033,8 +1033,16 @@ impl Metadata { /// [`is_dir`], and will be false for symlink metadata /// obtained from [`symlink_metadata`]. /// + /// When the goal is simply to read from (or write to) the source, the most + /// reliable way to test the source can be read (or written to) is to open + /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on + /// a Unix-like system for example. See [`File::open`] or + /// [`OpenOptions::open`] for more information. + /// /// [`is_dir`]: struct.Metadata.html#method.is_dir /// [`symlink_metadata`]: fn.symlink_metadata.html + /// [`File::open`]: struct.File.html#method.open + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -1307,8 +1315,16 @@ impl FileType { /// [`is_dir`] and [`is_symlink`]; only zero or one of these /// tests may pass. /// + /// When the goal is simply to read from (or write to) the source, the most + /// reliable way to test the source can be read (or written to) is to open + /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on + /// a Unix-like system for example. See [`File::open`] or + /// [`OpenOptions::open`] for more information. + /// /// [`is_dir`]: struct.FileType.html#method.is_dir /// [`is_symlink`]: struct.FileType.html#method.is_symlink + /// [`File::open`]: struct.File.html#method.open + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -1429,7 +1445,10 @@ impl DirEntry { /// Returns the metadata for the file that this entry points at. /// /// This function will not traverse symlinks if this entry points at a - /// symlink. + /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`]. + /// + /// [`fs::metadata`]: fn.metadata.html + /// [`fs::File::metadata`]: struct.File.html#method.metadata /// /// # Platform-specific behavior /// diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8ff7508ba6457..f14a9ff72f62f 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2503,11 +2503,20 @@ impl Path { /// # See Also /// /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [fs::metadata] and handle its Result. Then call - /// [fs::Metadata::is_file] if it was Ok. - /// - /// [fs::metadata]: ../../std/fs/fn.metadata.html - /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file + /// check errors, call [`fs::metadata`] and handle its Result. Then call + /// [`fs::Metadata::is_file`] if it was Ok. + /// + /// When the goal is simply to read from (or write to) the source, the most + /// reliable way to test the source can be read (or written to) is to open + /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on + /// a Unix-like system for example. See [`File::open`] or + /// [`OpenOptions::open`] for more information. + /// + /// [`fs::metadata`]: ../../std/fs/fn.metadata.html + /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html + /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file + /// [`File::open`]: ../../std/fs/struct.File.html#method.open + /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open #[stable(feature = "path_ext", since = "1.5.0")] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 9bc111c26ba6b..41b14714842fd 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -49,8 +49,10 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) +#if LLVM_VERSION_LT(11, 0) DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef) +#endif extern "C" void LLVMInitializePasses() { PassRegistry &Registry = *PassRegistry::getPassRegistry(); @@ -343,17 +345,17 @@ enum class LLVMRustPassBuilderOptLevel { static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) { switch (Level) { case LLVMRustPassBuilderOptLevel::O0: - return PassBuilder::O0; + return PassBuilder::OptimizationLevel::O0; case LLVMRustPassBuilderOptLevel::O1: - return PassBuilder::O1; + return PassBuilder::OptimizationLevel::O1; case LLVMRustPassBuilderOptLevel::O2: - return PassBuilder::O2; + return PassBuilder::OptimizationLevel::O2; case LLVMRustPassBuilderOptLevel::O3: - return PassBuilder::O3; + return PassBuilder::OptimizationLevel::O3; case LLVMRustPassBuilderOptLevel::Os: - return PassBuilder::Os; + return PassBuilder::OptimizationLevel::Os; case LLVMRustPassBuilderOptLevel::Oz: - return PassBuilder::Oz; + return PassBuilder::OptimizationLevel::Oz; default: report_fatal_error("Bad PassBuilderOptLevel."); } @@ -796,8 +798,13 @@ LLVMRustOptimizeWithNewPassManager( // We manually collect pipeline callbacks so we can apply them at O0, where the // PassBuilder does not create a pipeline. std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks; +#if LLVM_VERSION_GE(11, 0) + std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>> + OptimizerLastEPCallbacks; +#else std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>> OptimizerLastEPCallbacks; +#endif if (VerifyIR) { PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) { @@ -811,6 +818,14 @@ LLVMRustOptimizeWithNewPassManager( SanitizerOptions->SanitizeMemoryTrackOrigins, SanitizerOptions->SanitizeMemoryRecover, /*CompileKernel=*/false); +#if LLVM_VERSION_GE(11, 0) + OptimizerLastEPCallbacks.push_back( + [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + MPM.addPass(MemorySanitizerPass(Options)); + MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); + } + ); +#else #if LLVM_VERSION_GE(10, 0) PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) { MPM.addPass(MemorySanitizerPass(Options)); @@ -821,9 +836,18 @@ LLVMRustOptimizeWithNewPassManager( FPM.addPass(MemorySanitizerPass(Options)); } ); +#endif } if (SanitizerOptions->SanitizeThread) { +#if LLVM_VERSION_GE(11, 0) + OptimizerLastEPCallbacks.push_back( + [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + MPM.addPass(ThreadSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); + } + ); +#else #if LLVM_VERSION_GE(10, 0) PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) { MPM.addPass(ThreadSanitizerPass()); @@ -834,9 +858,22 @@ LLVMRustOptimizeWithNewPassManager( FPM.addPass(ThreadSanitizerPass()); } ); +#endif } if (SanitizerOptions->SanitizeAddress) { +#if LLVM_VERSION_GE(11, 0) + OptimizerLastEPCallbacks.push_back( + [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); + MPM.addPass(ModuleAddressSanitizerPass( + /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); + MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass( + /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover, + /*UseAfterScope=*/true))); + } + ); +#else PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) { MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); }); @@ -853,21 +890,27 @@ LLVMRustOptimizeWithNewPassManager( /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); } ); +#endif } } ModulePassManager MPM(DebugPassManager); if (!NoPrepopulatePasses) { - if (OptLevel == PassBuilder::O0) { + if (OptLevel == PassBuilder::OptimizationLevel::O0) { for (const auto &C : PipelineStartEPCallbacks) C(MPM); +#if LLVM_VERSION_GE(11, 0) + for (const auto &C : OptimizerLastEPCallbacks) + C(MPM, OptLevel); +#else if (!OptimizerLastEPCallbacks.empty()) { FunctionPassManager FPM(DebugPassManager); for (const auto &C : OptimizerLastEPCallbacks) C(FPM, OptLevel); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } +#endif MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers)); @@ -892,12 +935,17 @@ LLVMRustOptimizeWithNewPassManager( break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); +#if LLVM_VERSION_GE(11, 0) + for (const auto &C : OptimizerLastEPCallbacks) + C(MPM, OptLevel); +#else if (!OptimizerLastEPCallbacks.empty()) { FunctionPassManager FPM(DebugPassManager); for (const auto &C : OptimizerLastEPCallbacks) C(FPM, OptLevel); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } +#endif break; case LLVMRustOptStage::PreLinkFatLTO: MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); @@ -994,10 +1042,10 @@ class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter { const Value *Value; if (const CallInst *CI = dyn_cast<CallInst>(I)) { Name = "call"; - Value = CI->getCalledValue(); + Value = CI->getCalledOperand(); } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) { Name = "invoke"; - Value = II->getCalledValue(); + Value = II->getCalledOperand(); } else { // Could demangle more operations, e. g. // `store %place, @function`. @@ -1335,10 +1383,33 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { // `ProcessThinLTOModule` function. Here they're split up into separate steps // so rustc can save off the intermediate bytecode between each step. +#if LLVM_VERSION_GE(11, 0) +static bool +clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) { + // When linking an ELF shared object, dso_local should be dropped. We + // conservatively do this for -fpic. + bool ClearDSOLocalOnDeclarations = + TM.getTargetTriple().isOSBinFormatELF() && + TM.getRelocationModel() != Reloc::Static && + Mod.getPIELevel() == PIELevel::Default; + return ClearDSOLocalOnDeclarations; +} +#endif + extern "C" bool -LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { +LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M, + LLVMTargetMachineRef TM) { Module &Mod = *unwrap(M); - if (renameModuleForThinLTO(Mod, Data->Index)) { + TargetMachine &Target = *unwrap(TM); + +#if LLVM_VERSION_GE(11, 0) + bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target); + bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal); +#else + bool error = renameModuleForThinLTO(Mod, Data->Index); +#endif + + if (error) { LLVMRustSetLastError("renameModuleForThinLTO failed"); return false; } @@ -1362,8 +1433,10 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef } extern "C" bool -LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { +LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, + LLVMTargetMachineRef TM) { Module &Mod = *unwrap(M); + TargetMachine &Target = *unwrap(TM); const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier()); auto Loader = [&](StringRef Identifier) { @@ -1399,7 +1472,12 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { return MOrErr; }; +#if LLVM_VERSION_GE(11, 0) + bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target); + FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal); +#else FunctionImporter Importer(Data->Index, Loader); +#endif Expected<bool> Result = Importer.importFunctions(Mod, ImportList); if (!Result) { LLVMRustSetLastError(toString(Result.takeError()).c_str()); @@ -1558,22 +1636,11 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { } // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and - // process it recursively. Note that we specifically iterate over instructions - // to ensure we feed everything into it. + // process it recursively. Note that we used to specifically iterate over + // instructions to ensure we feed everything into it, but `processModule` + // started doing this the same way in LLVM 7 (commit d769eb36ab2b8). DebugInfoFinder Finder; Finder.processModule(*M); - for (Function &F : M->functions()) { - for (auto &FI : F) { - for (Instruction &BI : FI) { - if (auto Loc = BI.getDebugLoc()) - Finder.processLocation(*M, Loc); - if (auto DVI = dyn_cast<DbgValueInst>(&BI)) - Finder.processValue(*M, DVI); - if (auto DDI = dyn_cast<DbgDeclareInst>(&BI)) - Finder.processDeclare(*M, DDI); - } - } - } // After we've found all our debuginfo, rewrite all subprograms to point to // the same `DICompileUnit`. diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index cdb3a157eab97..063b6acc604ea 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1,5 +1,4 @@ #include "rustllvm.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -214,50 +213,50 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index, LLVMRustAttribute RustAttr) { - CallSite Call = CallSite(unwrap<Instruction>(Instr)); + CallBase *Call = unwrap<CallBase>(Instr); Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr)); - Call.addAttribute(Index, Attr); + Call->addAttribute(Index, Attr); } extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint32_t Bytes) { - CallSite Call = CallSite(unwrap<Instruction>(Instr)); + CallBase *Call = unwrap<CallBase>(Instr); AttrBuilder B; B.addAlignmentAttr(Bytes); - Call.setAttributes(Call.getAttributes().addAttributes( + Call->setAttributes(Call->getAttributes().addAttributes( Call->getContext(), Index, B)); } extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { - CallSite Call = CallSite(unwrap<Instruction>(Instr)); + CallBase *Call = unwrap<CallBase>(Instr); AttrBuilder B; B.addDereferenceableAttr(Bytes); - Call.setAttributes(Call.getAttributes().addAttributes( + Call->setAttributes(Call->getAttributes().addAttributes( Call->getContext(), Index, B)); } extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, unsigned Index, uint64_t Bytes) { - CallSite Call = CallSite(unwrap<Instruction>(Instr)); + CallBase *Call = unwrap<CallBase>(Instr); AttrBuilder B; B.addDereferenceableOrNullAttr(Bytes); - Call.setAttributes(Call.getAttributes().addAttributes( + Call->setAttributes(Call->getAttributes().addAttributes( Call->getContext(), Index, B)); } extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, LLVMTypeRef Ty) { - CallSite Call = CallSite(unwrap<Instruction>(Instr)); + CallBase *Call = unwrap<CallBase>(Instr); #if LLVM_VERSION_GE(9, 0) Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty)); #else Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal); #endif - Call.addAttribute(Index, Attr); + Call->addAttribute(Index, Attr); } extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, @@ -336,20 +335,24 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name, LLVMAtomicOrdering Order) { - LoadInst *LI = new LoadInst(unwrap(Source)); + Value *Ptr = unwrap(Source); + Type *Ty = Ptr->getType()->getPointerElementType(); + LoadInst *LI = unwrap(B)->CreateLoad(Ty, Ptr, Name); LI->setAtomic(fromRust(Order)); - return wrap(unwrap(B)->Insert(LI, Name)); + return wrap(LI); } extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, LLVMValueRef V, LLVMValueRef Target, LLVMAtomicOrdering Order) { - StoreInst *SI = new StoreInst(unwrap(V), unwrap(Target)); + StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target)); SI->setAtomic(fromRust(Order)); - return wrap(unwrap(B)->Insert(SI)); + return wrap(SI); } +// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak +// once we raise our minimum support to LLVM 10. extern "C" LLVMValueRef LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target, LLVMValueRef Old, LLVMValueRef Source, @@ -965,8 +968,14 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef Ty) { +#if LLVM_VERSION_GE(11, 0) + bool IsDefault = false; // FIXME: should we ever set this true? + return wrap(Builder->createTemplateTypeParameter( + unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault)); +#else return wrap(Builder->createTemplateTypeParameter( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty))); +#endif } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace( @@ -1227,12 +1236,23 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { return LLVMArrayTypeKind; case Type::PointerTyID: return LLVMPointerTypeKind; +#if LLVM_VERSION_GE(11, 0) + case Type::FixedVectorTyID: + return LLVMVectorTypeKind; +#else case Type::VectorTyID: return LLVMVectorTypeKind; +#endif case Type::X86_MMXTyID: return LLVMX86_MMXTypeKind; case Type::TokenTyID: return LLVMTokenTypeKind; +#if LLVM_VERSION_GE(11, 0) + case Type::ScalableVectorTyID: + return LLVMScalableVectorTypeKind; + case Type::BFloatTyID: + return LLVMBFloatTypeKind; +#endif } report_fatal_error("Unhandled TypeID."); } @@ -1359,10 +1379,12 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, OperandBundleDef *Bundle) { + Value *Callee = unwrap(Fn); + FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType()); unsigned Len = Bundle ? 1 : 0; ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len); return wrap(unwrap(B)->CreateCall( - unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles)); + FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles)); } extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) { @@ -1422,9 +1444,11 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, OperandBundleDef *Bundle, const char *Name) { + Value *Callee = unwrap(Fn); + FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType()); unsigned Len = Bundle ? 1 : 0; ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len); - return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch), + return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name)); } diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs index 719f219ce4ef1..433d32abd37c6 100644 --- a/src/test/codegen/sanitizer-recover.rs +++ b/src/test/codegen/sanitizer-recover.rs @@ -27,17 +27,17 @@ // ASAN: } // // MSAN-LABEL: define i32 @penguin( -// MSAN: call void @__msan_warning_noreturn() +// MSAN: call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}} // MSAN: unreachable // MSAN: } // // MSAN-RECOVER-LABEL: define i32 @penguin( -// MSAN-RECOVER: call void @__msan_warning() +// MSAN-RECOVER: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} // MSAN-RECOVER-NOT: unreachable // MSAN-RECOVER: } // // MSAN-RECOVER-LTO-LABEL: define i32 @penguin( -// MSAN-RECOVER-LTO: call void @__msan_warning() +// MSAN-RECOVER-LTO: call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}} // MSAN-RECOVER-LTO-NOT: unreachable // MSAN-RECOVER-LTO: } // diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs index cf10ebfeca939..86d459bf084b1 100644 --- a/src/test/ui/async-await/async-error-span.rs +++ b/src/test/ui/async-await/async-error-span.rs @@ -5,7 +5,7 @@ use std::future::Future; fn get_future() -> impl Future<Output = ()> { -//~^ ERROR the trait bound `(): std::future::Future` is not satisfied +//~^ ERROR `()` is not a future panic!() } diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 4054e739c483d..9523f040aa8cd 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -1,12 +1,13 @@ -error[E0277]: the trait bound `(): std::future::Future` is not satisfied +error[E0277]: `()` is not a future --> $DIR/async-error-span.rs:7:20 | LL | fn get_future() -> impl Future<Output = ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future LL | LL | panic!() | -------- this returned value is of type `!` | + = help: the trait `std::future::Future` is not implemented for `()` = note: the return type of a function must have a statically known size error[E0698]: type inside `async fn` body must be known in this context diff --git a/src/test/ui/async-await/issue-70594.rs b/src/test/ui/async-await/issue-70594.rs index e78231a68512d..34d12db8806dc 100644 --- a/src/test/ui/async-await/issue-70594.rs +++ b/src/test/ui/async-await/issue-70594.rs @@ -6,7 +6,7 @@ async fn fun() { //~| error: `.await` is not allowed in a `const` //~| error: `loop` is not allowed in a `const` //~| error: `.await` is not allowed in a `const` - //~| error: the trait bound `(): std::future::Future` is not satisfied + //~| error: `()` is not a future } fn main() {} diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index 496ca506c60f2..1b7abe317222d 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -27,12 +27,13 @@ error[E0744]: `.await` is not allowed in a `const` LL | [1; ().await]; | ^^^^^^^^ -error[E0277]: the trait bound `(): std::future::Future` is not satisfied +error[E0277]: `()` is not a future --> $DIR/issue-70594.rs:4:9 | LL | [1; ().await]; - | ^^^^^^^^ the trait `std::future::Future` is not implemented for `()` + | ^^^^^^^^ `()` is not a future | + = help: the trait `std::future::Future` is not implemented for `()` = note: required by `std::future::Future::poll` error: aborting due to 5 previous errors diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index ec4e9e397a81e..e3ba74a03c898 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -27,12 +27,13 @@ LL | fn main() { LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks -error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]: std::future::Future` is not satisfied +error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future --> $DIR/issue-62009-1.rs:12:5 | LL | (|_| 2333).await; - | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future | + = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` = note: required by `std::future::Future::poll` error: aborting due to 4 previous errors diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr index acdc03e372638..addc8a0efe1aa 100644 --- a/src/test/ui/binop/binop-consume-args.stderr +++ b/src/test/ui/binop/binop-consume-args.stderr @@ -4,10 +4,15 @@ error[E0382]: use of moved value: `lhs` LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs + rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -35,10 +40,15 @@ error[E0382]: use of moved value: `lhs` LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs - rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn sub(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -66,10 +76,15 @@ error[E0382]: use of moved value: `lhs` LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs * rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn mul(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -97,10 +112,15 @@ error[E0382]: use of moved value: `lhs` LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs / rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn div(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -128,10 +148,15 @@ error[E0382]: use of moved value: `lhs` LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs % rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn rem(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -159,10 +184,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs & rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitand(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -190,10 +220,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs | rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitor(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -221,10 +256,15 @@ error[E0382]: use of moved value: `lhs` LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs ^ rhs; - | --- value moved here + | --------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn bitxor(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -252,10 +292,15 @@ error[E0382]: use of moved value: `lhs` LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs << rhs; - | --- value moved here + | ---------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn shl(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) { @@ -283,10 +328,15 @@ error[E0382]: use of moved value: `lhs` LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) { | --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait LL | lhs >> rhs; - | --- value moved here + | ---------- `lhs` moved due to usage in operator LL | drop(lhs); | ^^^ value used here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn shr(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) { diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index 6d5ac9cab30c0..97b70efe20e79 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -1,14 +1,21 @@ error[E0382]: use of moved value: `x` --> $DIR/binop-move-semantics.rs:8:5 | -LL | fn double_move<T: Add<Output=()>>(x: T) { - | - move occurs because `x` has type `T`, which does not implement the `Copy` trait -LL | x - | - value moved here -LL | + -LL | x; - | ^ value used here after move +LL | fn double_move<T: Add<Output=()>>(x: T) { + | - move occurs because `x` has type `T`, which does not implement the `Copy` trait +LL | / x +LL | | + +LL | | x; + | | ^ + | | | + | |_____value used here after move + | `x` moved due to usage in operator + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn double_move<T: Add<Output=()> + Copy>(x: T) { diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr index a51cda548efd7..bc1721944fbbb 100644 --- a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr +++ b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr @@ -22,10 +22,15 @@ error[E0382]: use of moved value: `f` LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) { | - move occurs because `f` has type `F`, which does not implement the `Copy` trait LL | f(1, 2); - | - value moved here + | ------- `f` moved due to this call LL | f(1, 2); | ^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/borrowck-unboxed-closures.rs:11:5 + | +LL | f(1, 2); + | ^ help: consider further restricting this bound | LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) { diff --git a/src/test/ui/closure_context/issue-42065.stderr b/src/test/ui/closure_context/issue-42065.stderr index 69d98654048cb..896bb6dc6bee8 100644 --- a/src/test/ui/closure_context/issue-42065.stderr +++ b/src/test/ui/closure_context/issue-42065.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/issue-42065.rs:11:5 | LL | debug_dump_dict(); - | --------------- value moved here + | ----------------- `debug_dump_dict` moved due to this call LL | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `di | LL | for (key, value) in dict { | ^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/issue-42065.rs:10:5 + | +LL | debug_dump_dict(); + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index 97816a76004d0..614e69e89f6ec 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -4,10 +4,16 @@ error[E0382]: borrow of moved value: `some_vec` LL | let some_vec = vec!["hi"]; | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait LL | some_vec.into_iter(); - | -------- value moved here + | ----------- `some_vec` moved due to this method call LL | { LL | println!("{:?}", some_vec); | ^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues-71798.rs b/src/test/ui/issues-71798.rs index 08b10463d3927..fecba721ac9fd 100644 --- a/src/test/ui/issues-71798.rs +++ b/src/test/ui/issues-71798.rs @@ -1,5 +1,5 @@ fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { - *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied + *x //~^ ERROR `u32` is not a future } fn main() { diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr index 85da87914e768..b3b29a7264131 100644 --- a/src/test/ui/issues-71798.stderr +++ b/src/test/ui/issues-71798.stderr @@ -4,14 +4,15 @@ error[E0425]: cannot find value `u` in this scope LL | let _ = test_ref & u; | ^ not found in this scope -error[E0277]: the trait bound `u32: std::future::Future` is not satisfied +error[E0277]: `u32` is not a future --> $DIR/issues-71798.rs:1:25 | LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future LL | *x | -- this returned value is of type `u32` | + = help: the trait `std::future::Future` is not implemented for `u32` = note: the return type of a function must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr index 2283b1275d018..b759aa45e3eb7 100644 --- a/src/test/ui/issues/issue-12127.stderr +++ b/src/test/ui/issues/issue-12127.stderr @@ -2,10 +2,15 @@ error[E0382]: use of moved value: `f` --> $DIR/issue-12127.rs:11:9 | LL | f(); - | - value moved here + | --- `f` moved due to this call LL | f(); | ^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/issue-12127.rs:10:9 + | +LL | f(); + | ^ = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box<isize>]`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index ccaa6334856b4..4fb805b37e03f 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,4 +3,5 @@ use std::collections::HashMap; fn main() { for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch //~^ ERROR type mismatch + //~| ERROR type mismatch } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 734ae78f362db..20335d2cdd684 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -17,6 +17,16 @@ LL | for _ in HashMap::new().iter().cloned() {} found reference `&_` = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>` -error: aborting due to 2 previous errors +error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_` + --> $DIR/issue-33941.rs:4:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | + = note: expected tuple `(&_, &_)` + found reference `&_` + = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr index 6cfed20f43a04..b4cc1a0aa7eb2 100644 --- a/src/test/ui/issues/issue-34721.stderr +++ b/src/test/ui/issues/issue-34721.stderr @@ -5,14 +5,19 @@ LL | pub fn baz<T: Foo>(x: T) -> T { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait LL | if 0 == 1 { LL | bar::bar(x.zero()) - | - value moved here + | ------ `x` moved due to this method call LL | } else { LL | x.zero() - | - value moved here + | ------ `x` moved due to this method call LL | }; LL | x.zero() | ^ value used here after move | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $DIR/issue-34721.rs:4:13 + | +LL | fn zero(self) -> Self; + | ^^^^ help: consider further restricting this bound | LL | pub fn baz<T: Foo + Copy>(x: T) -> T { diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index 8523a6f6548a6..ba43f2d33ee44 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -6,11 +6,17 @@ LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; LL | for l in bad_letters { | ----------- | | - | value moved here + | `bad_letters` moved due to this implicit call to `.into_iter()` | help: consider borrowing to avoid moving into the for loop: `&bad_letters` ... LL | bad_letters.push('s'); | ^^^^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index 3c685dc8d089a..2c337bae13017 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -6,12 +6,18 @@ LL | let orig = vec![true]; LL | for _val in orig {} | ---- | | - | value moved here + | `orig` moved due to this implicit call to `.into_iter()` | help: consider borrowing to avoid moving into the for loop: `&orig` LL | let _closure = || orig; | ^^ ---- use occurs due to use in closure | | | value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `orig` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs new file mode 100644 index 0000000000000..6107f53fa1960 --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.rs @@ -0,0 +1,74 @@ +use std::pin::Pin; +use std::rc::Rc; +use std::ops::Add; + +struct Foo; + +impl Add for Foo { + type Output = (); + fn add(self, _rhs: Self) -> () {} +} + +impl Foo { + fn use_self(self) {} + fn use_box_self(self: Box<Self>) {} + fn use_pin_box_self(self: Pin<Box<Self>>) {} + fn use_rc_self(self: Rc<Self>) {} + fn use_mut_self(&mut self) -> &mut Self { self } +} + +struct Container(Vec<bool>); + +impl Container { + fn custom_into_iter(self) -> impl Iterator<Item = bool> { + self.0.into_iter() + } +} + +fn move_out(val: Container) { + val.0.into_iter().next(); + val.0; //~ ERROR use of moved + + let foo = Foo; + foo.use_self(); + foo; //~ ERROR use of moved + + let second_foo = Foo; + second_foo.use_self(); + second_foo; //~ ERROR use of moved + + let boxed_foo = Box::new(Foo); + boxed_foo.use_box_self(); + boxed_foo; //~ ERROR use of moved + + let pin_box_foo = Box::pin(Foo); + pin_box_foo.use_pin_box_self(); + pin_box_foo; //~ ERROR use of moved + + let mut mut_foo = Foo; + let ret = mut_foo.use_mut_self(); + mut_foo; //~ ERROR cannot move out + ret; + + let rc_foo = Rc::new(Foo); + rc_foo.use_rc_self(); + rc_foo; //~ ERROR use of moved + + let foo_add = Foo; + foo_add + Foo; + foo_add; //~ ERROR use of moved + + let implicit_into_iter = vec![true]; + for _val in implicit_into_iter {} + implicit_into_iter; //~ ERROR use of moved + + let explicit_into_iter = vec![true]; + for _val in explicit_into_iter.into_iter() {} + explicit_into_iter; //~ ERROR use of moved + + let container = Container(vec![]); + for _val in container.custom_into_iter() {} + container; //~ ERROR use of moved +} + +fn main() {} diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr new file mode 100644 index 0000000000000..4333e8a23e866 --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -0,0 +1,158 @@ +error[E0382]: use of moved value: `val.0` + --> $DIR/move-fn-self-receiver.rs:30:5 + | +LL | val.0.into_iter().next(); + | ----------- `val.0` moved due to this method call +LL | val.0; + | ^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + = note: move occurs because `val.0` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo` + --> $DIR/move-fn-self-receiver.rs:34:5 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo.use_self(); + | ---------- `foo` moved due to this method call +LL | foo; + | ^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `foo` + --> $DIR/move-fn-self-receiver.rs:13:17 + | +LL | fn use_self(self) {} + | ^^^^ + +error[E0382]: use of moved value: `second_foo` + --> $DIR/move-fn-self-receiver.rs:38:5 + | +LL | let second_foo = Foo; + | ---------- move occurs because `second_foo` has type `Foo`, which does not implement the `Copy` trait +LL | second_foo.use_self(); + | ---------- `second_foo` moved due to this method call +LL | second_foo; + | ^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:42:5 + | +LL | let boxed_foo = Box::new(Foo); + | --------- move occurs because `boxed_foo` has type `std::boxed::Box<Foo>`, which does not implement the `Copy` trait +LL | boxed_foo.use_box_self(); + | -------------- `boxed_foo` moved due to this method call +LL | boxed_foo; + | ^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:14:21 + | +LL | fn use_box_self(self: Box<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:46:5 + | +LL | let pin_box_foo = Box::pin(Foo); + | ----------- move occurs because `pin_box_foo` has type `std::pin::Pin<std::boxed::Box<Foo>>`, which does not implement the `Copy` trait +LL | pin_box_foo.use_pin_box_self(); + | ------------------ `pin_box_foo` moved due to this method call +LL | pin_box_foo; + | ^^^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:15:25 + | +LL | fn use_pin_box_self(self: Pin<Box<Self>>) {} + | ^^^^ + +error[E0505]: cannot move out of `mut_foo` because it is borrowed + --> $DIR/move-fn-self-receiver.rs:50:5 + | +LL | let ret = mut_foo.use_mut_self(); + | ------- borrow of `mut_foo` occurs here +LL | mut_foo; + | ^^^^^^^ move out of `mut_foo` occurs here +LL | ret; + | --- borrow later used here + +error[E0382]: use of moved value: `rc_foo` + --> $DIR/move-fn-self-receiver.rs:55:5 + | +LL | let rc_foo = Rc::new(Foo); + | ------ move occurs because `rc_foo` has type `std::rc::Rc<Foo>`, which does not implement the `Copy` trait +LL | rc_foo.use_rc_self(); + | ------------- `rc_foo` moved due to this method call +LL | rc_foo; + | ^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo` + --> $DIR/move-fn-self-receiver.rs:16:20 + | +LL | fn use_rc_self(self: Rc<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `foo_add` + --> $DIR/move-fn-self-receiver.rs:59:5 + | +LL | let foo_add = Foo; + | ------- move occurs because `foo_add` has type `Foo`, which does not implement the `Copy` trait +LL | foo_add + Foo; + | ------------- `foo_add` moved due to usage in operator +LL | foo_add; + | ^^^^^^^ value used here after move + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ + +error[E0382]: use of moved value: `implicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:63:5 + | +LL | let implicit_into_iter = vec![true]; + | ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait +LL | for _val in implicit_into_iter {} + | ------------------ + | | + | `implicit_into_iter` moved due to this implicit call to `.into_iter()` + | help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter` +LL | implicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `explicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:67:5 + | +LL | let explicit_into_iter = vec![true]; + | ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait +LL | for _val in explicit_into_iter.into_iter() {} + | ----------- `explicit_into_iter` moved due to this method call +LL | explicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `container` + --> $DIR/move-fn-self-receiver.rs:71:5 + | +LL | let container = Container(vec![]); + | --------- move occurs because `container` has type `Container`, which does not implement the `Copy` trait +LL | for _val in container.custom_into_iter() {} + | ------------------ `container` moved due to this method call +LL | container; + | ^^^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `container` + --> $DIR/move-fn-self-receiver.rs:23:25 + | +LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> { + | ^^^^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index 71a3c4506eaf2..142feb280d153 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | consume(x.into_iter().next().unwrap()); - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x[0]); | ^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 67fae606c4e43..ff98aab50c9f8 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -104,9 +104,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | let _y = x.into_iter().next().unwrap(); - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:83:11 @@ -114,9 +120,15 @@ error[E0382]: borrow of moved value: `x` LL | let x = vec!["hi".to_string()]; | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait LL | let _y = [x.into_iter().next().unwrap(); 1]; - | - value moved here + | ----------- `x` moved due to this method call LL | touch(&x); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `x` + --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr index 7133a32431a67..8761b5261d51b 100644 --- a/src/test/ui/once-cant-call-twice-on-heap.stderr +++ b/src/test/ui/once-cant-call-twice-on-heap.stderr @@ -4,10 +4,15 @@ error[E0382]: use of moved value: `blk` LL | fn foo<F:FnOnce()>(blk: F) { | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); - | --- value moved here + | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/once-cant-call-twice-on-heap.rs:8:5 + | +LL | blk(); + | ^^^ help: consider further restricting this bound | LL | fn foo<F:FnOnce() + Copy>(blk: F) { diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 99ba4e2a646e5..11372494772d0 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied +error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9 | LL | async fn foo() {} @@ -8,14 +8,15 @@ LL | fn bar(f: impl Future<Output=()>) {} | ----------------- required by this bound in `bar` ... LL | bar(foo); - | ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` + | ^^^ `fn() -> impl std::future::Future {foo}` is not a future | + = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` help: use parentheses to call the function | LL | bar(foo()); | ^^ -error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied +error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9 | LL | fn bar(f: impl Future<Output=()>) {} @@ -24,8 +25,9 @@ LL | fn bar(f: impl Future<Output=()>) {} LL | let async_closure = async || (); | -------- consider calling this closure LL | bar(async_closure); - | ^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` + | ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future | + = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` help: use parentheses to call the closure | LL | bar(async_closure()); diff --git a/src/test/ui/terminal-width/flag-human.rs b/src/test/ui/terminal-width/flag-human.rs new file mode 100644 index 0000000000000..e445a84fd012e --- /dev/null +++ b/src/test/ui/terminal-width/flag-human.rs @@ -0,0 +1,9 @@ +// compile-flags: -Z terminal-width=20 + +// This test checks that `-Z terminal-width` effects the human error output by restricting it to an +// arbitrarily low value so that the effect is visible. + +fn main() { + let _: () = 42; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/flag-human.stderr b/src/test/ui/terminal-width/flag-human.stderr new file mode 100644 index 0000000000000..393dcf2b82845 --- /dev/null +++ b/src/test/ui/terminal-width/flag-human.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/flag-human.rs:7:17 + | +LL | ..._: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/flag-json.rs b/src/test/ui/terminal-width/flag-json.rs new file mode 100644 index 0000000000000..eabdc59ddedd5 --- /dev/null +++ b/src/test/ui/terminal-width/flag-json.rs @@ -0,0 +1,9 @@ +// compile-flags: -Z terminal-width=20 --error-format=json + +// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an +// arbitrarily low value so that the effect is visible. + +fn main() { + let _: () = 42; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/flag-json.stderr b/src/test/ui/terminal-width/flag-json.stderr new file mode 100644 index 0000000000000..29730ccdd4ed7 --- /dev/null +++ b/src/test/ui/terminal-width/flag-json.stderr @@ -0,0 +1,32 @@ +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. + +Erroneous code example: + +```compile_fail,E0308 +let x: i32 = \"I am not a number!\"; +// ~~~ ~~~~~~~~~~~~~~~~~~~~ +// | | +// | initializing expression; +// | compiler infers type `&str` +// | +// type `i32` assigned to variable `x` +``` + +This error occurs when the compiler is unable to infer the concrete type of a +variable. It can occur in several cases, the most common being a mismatch +between two types: the type the author explicitly assigned, and the type the +compiler inferred. +"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types + --> $DIR/flag-json.rs:7:17 + | +LL | ..._: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +"} +{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error + +"} +{"message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`. +"} diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr index 0b9aa61a765fa..ab6f06518467c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick` --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:10:5 | LL | tick(); - | ---- value moved here + | ------ `tick` moved due to this call LL | tick(); | ^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co | LL | let tick = || mem::drop(counter); | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr index 20773d561f9f2..8d70a2b17602b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick` --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:10:5 | LL | tick(); - | ---- value moved here + | ------ `tick` moved due to this call LL | tick(); | ^^^^ value used here after move | @@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co | LL | let tick = move || mem::drop(counter); | ^^^^^^^ +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:9:5 + | +LL | tick(); + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index e0499cfe95ce9..dd54c222f64bb 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -4,11 +4,16 @@ error[E0382]: borrow of moved value: `x` LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) { | - move occurs because `x` has type `T`, which does not implement the `Copy` trait LL | !x; - | - value moved here + | -- `x` moved due to usage in operator LL | LL | x.clone(); | ^ value borrowed here after move | +note: calling this operator moves the left-hand side + --> $SRC_DIR/libcore/ops/bit.rs:LL:COL + | +LL | fn not(self) -> Self::Output; + | ^^^^ help: consider further restricting this bound | LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) { diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 110edab69be87..906b543e42122 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -37,10 +37,16 @@ error[E0382]: borrow of moved value: `y` LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); - | - value moved here + | ----- `y` moved due to this method call ... LL | println!("{}", &y); | ^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `y` + --> $DIR/borrow-after-move.rs:4:12 + | +LL | fn foo(self) -> String; + | ^^^^ error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 5b936fb64474f..49b2031c6b9d9 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -34,9 +34,15 @@ error[E0382]: use of moved value: `y` LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait LL | y.foo(); - | - value moved here + | ----- `y` moved due to this method call LL | y.foo(); | ^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `y` + --> $DIR/double-move.rs:4:12 + | +LL | fn foo(self) -> String; + | ^^^^ error[E0382]: use of moved value: `x` --> $DIR/double-move.rs:45:9 diff --git a/src/test/ui/use/use-after-move-self-based-on-type.stderr b/src/test/ui/use/use-after-move-self-based-on-type.stderr index 9bf1175430c84..b9440f4de07a9 100644 --- a/src/test/ui/use/use-after-move-self-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-self-based-on-type.stderr @@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self` LL | pub fn foo(self) -> isize { | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); - | ---- value moved here + | ----- `self` moved due to this method call LL | return self.x; | ^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `self` + --> $DIR/use-after-move-self-based-on-type.rs:15:16 + | +LL | pub fn bar(self) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-self.stderr b/src/test/ui/use/use-after-move-self.stderr index 3be0a65550b7f..3da53b024db44 100644 --- a/src/test/ui/use/use-after-move-self.stderr +++ b/src/test/ui/use/use-after-move-self.stderr @@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self` LL | pub fn foo(self) -> isize { | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait LL | self.bar(); - | ---- value moved here + | ----- `self` moved due to this method call LL | return *self.x; | ^^^^^^^ value used here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `self` + --> $DIR/use-after-move-self.rs:13:16 + | +LL | pub fn bar(self) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr index eeb594a21f38c..ece63a2b81947 100644 --- a/src/test/ui/walk-struct-literal-with.stderr +++ b/src/test/ui/walk-struct-literal-with.stderr @@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `start` LL | let start = Mine{test:"Foo".to_string(), other_val:0}; | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait LL | let end = Mine{other_val:1, ..start.make_string_bar()}; - | ----- value moved here + | ----------------- `start` moved due to this method call LL | println!("{}", start.test); | ^^^^^^^^^^ value borrowed here after move + | +note: this function consumes the receiver `self` by taking ownership of it, which moves `start` + --> $DIR/walk-struct-literal-with.rs:7:28 + | +LL | fn make_string_bar(mut self) -> Mine{ + | ^^^^ error: aborting due to previous error diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7d2c83881d13b..571e7a59113ad 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -263,7 +263,7 @@ impl EarlyProps { } fn version_to_int(version: &str) -> u32 { - let version_without_suffix = version.split('-').next().unwrap(); + let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap(); let components: Vec<u32> = version_without_suffix .split('.') .map(|s| s.parse().expect("Malformed version component"))