diff options
Diffstat (limited to 'compiler')
92 files changed, 897 insertions, 531 deletions
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs index 96277950cfe..739c6fd0a43 100644 --- a/compiler/rustc_apfloat/src/ieee.rs +++ b/compiler/rustc_apfloat/src/ieee.rs @@ -389,6 +389,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> { let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize); // Change the exponent from 2^e to 10^e. + #[allow(clippy::comparison_chain)] if exp == 0 { // Nothing to do. } else if exp > 0 { @@ -2526,6 +2527,7 @@ mod sig { if *a_sign ^ b_sign { let (reverse, loss); + #[allow(clippy::comparison_chain)] if bits == 0 { reverse = cmp(a_sig, b_sig) == Ordering::Less; loss = Loss::ExactlyZero; diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index a6167773003..e3c610585d9 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -20,16 +20,6 @@ #[macro_use] extern crate rustc_macros; -#[macro_export] -macro_rules! unwrap_or { - ($opt:expr, $default:expr) => { - match $opt { - Some(x) => x, - None => $default, - } - }; -} - pub mod util { pub mod classify; pub mod comments; diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 7165b3bcb9f..957b14f3487 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -202,39 +202,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut used_input_regs = FxHashMap::default(); let mut used_output_regs = FxHashMap::default(); - let mut required_features: Vec<&str> = vec![]; + for (idx, &(ref op, op_sp)) in operands.iter().enumerate() { if let Some(reg) = op.reg() { - // Make sure we don't accidentally carry features from the - // previous iteration. - required_features.clear(); - let reg_class = reg.reg_class(); if reg_class == asm::InlineAsmRegClass::Err { continue; } - // We ignore target feature requirements for clobbers: if the - // feature is disabled then the compiler doesn't care what we - // do with the registers. - // - // Note that this is only possible for explicit register - // operands, which cannot be used in the asm string. - let is_clobber = matches!( - op, - hir::InlineAsmOperand::Out { - reg: asm::InlineAsmRegOrRegClass::Reg(_), - late: _, - expr: None - } - ); - // Some register classes can only be used as clobbers. This // means that we disallow passing a value in/out of the asm and // require that the operand name an explicit register, not a // register class. if reg_class.is_clobber_only(asm_arch.unwrap()) - && !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_))) + && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_))) { let msg = format!( "register class `{}` can only be used as a clobber, \ @@ -245,47 +226,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { continue; } - if !is_clobber { - // Validate register classes against currently enabled target - // features. We check that at least one type is available for - // the current target. - for &(_, feature) in reg_class.supported_types(asm_arch.unwrap()) { - if let Some(feature) = feature { - if self.sess.target_features.contains(&Symbol::intern(feature)) { - required_features.clear(); - break; - } else { - required_features.push(feature); - } - } else { - required_features.clear(); - break; - } - } - // We are sorting primitive strs here and can use unstable sort here - required_features.sort_unstable(); - required_features.dedup(); - match &required_features[..] { - [] => {} - [feature] => { - let msg = format!( - "register class `{}` requires the `{}` target feature", - reg_class.name(), - feature - ); - sess.struct_span_err(op_sp, &msg).emit(); - } - features => { - let msg = format!( - "register class `{}` requires at least one target feature: {}", - reg_class.name(), - features.join(", ") - ); - sess.struct_span_err(op_sp, &msg).emit(); - } - } - } - // Check for conflicts between explicit register operands. if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg { let (input, output) = match op { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ea9eb0cf274..a5a4de81f12 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1345,8 +1345,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics .params .iter() - .find(|p| def_id == self.resolver.local_def_id(p.id).to_def_id()) - .is_some() + .any(|p| def_id == self.resolver.local_def_id(p.id).to_def_id()) } // Either the `bounded_ty` is not a plain type parameter, or // it's not found in the generic type parameters list. diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 1e660ece908..7db8d4520d4 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -201,7 +201,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { let bb_data = &self.body[bb]; debug_assert!(hi == bb_data.statements.len()); for &succ_bb in bb_data.terminator().successors() { - if self.visited.insert(succ_bb) == false { + if !self.visited.insert(succ_bb) { if succ_bb == location.block && first_lo > 0 { // `succ_bb` has been seen before. If it wasn't // fully processed, add its first part to `stack` diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7ca72cbed8d..246d2e3208c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -972,8 +972,7 @@ fn suggest_ampmut<'tcx>( if let Some(assignment_rhs_span) = opt_assignment_rhs_span { if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { let is_mutbl = |ty: &str| -> bool { - if ty.starts_with("mut") { - let rest = &ty[3..]; + if let Some(rest) = ty.strip_prefix("mut") { match rest.chars().next() { // e.g. `&mut x` Some(c) if c.is_whitespace() => true, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 55790bd2daa..07eadce1773 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1153,28 +1153,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .convert_all(data); } - /// Convenient wrapper around `relate_tys::relate_types` -- see - /// that fn for docs. - fn relate_types( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - relate_tys::relate_types( - self.infcx, - self.param_env, - a, - v, - b, - locations, - category, - self.borrowck_context, - ) - } - /// Try to relate `sub <: sup` fn sub_types( &mut self, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b788529dc1c..415d1abaa8b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Const, Ty}; @@ -7,48 +7,38 @@ use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; -use crate::type_check::{BorrowCheckContext, Locations}; - -/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: -/// -/// - "Covariant" `a <: b` -/// - "Invariant" `a == b` -/// - "Contravariant" `a :> b` -/// -/// N.B., the type `a` is permitted to have unresolved inference -/// variables, but not the type `b`. -#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")] -pub(super) fn relate_types<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - borrowck_context: &mut BorrowCheckContext<'_, 'tcx>, -) -> Fallible<()> { - TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new( - infcx, - borrowck_context, - param_env, - locations, - category, - UniverseInfo::relate(a, b), - ), - v, - ) - .relate(a, b)?; - Ok(()) +use crate::type_check::{Locations, TypeChecker}; + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: + /// + /// - "Covariant" `a <: b` + /// - "Invariant" `a == b` + /// - "Contravariant" `a :> b` + /// + /// N.B., the type `a` is permitted to have unresolved inference + /// variables, but not the type `b`. + #[instrument(skip(self), level = "debug")] + pub(super) fn relate_types( + &mut self, + a: Ty<'tcx>, + v: ty::Variance, + b: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + TypeRelating::new( + self.infcx, + NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), + v, + ) + .relate(a, b)?; + Ok(()) + } } struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - - param_env: ty::ParamEnv<'tcx>, + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, /// Where (and why) is this relation taking place? locations: Locations, @@ -63,25 +53,24 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, category: ConstraintCategory, universe_info: UniverseInfo<'tcx>, ) -> Self { - Self { infcx, borrowck_context, param_env, locations, category, universe_info } + Self { type_checker, locations, category, universe_info } } } impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + self.type_checker.param_env } fn create_next_universe(&mut self) -> ty::UniverseIndex { - let universe = self.infcx.create_next_universe(); - self.borrowck_context + let universe = self.type_checker.infcx.create_next_universe(); + self.type_checker + .borrowck_context .constraints .universe_causes .insert(universe, self.universe_info.clone()); @@ -90,15 +79,18 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.infcx.next_nll_region_var(origin) + self.type_checker.infcx.next_nll_region_var(origin) } fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder) + self.type_checker + .borrowck_context + .constraints + .placeholder_region(self.type_checker.infcx, placeholder) } fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx.next_nll_region_var_in_universe( + self.type_checker.infcx.next_nll_region_var_in_universe( NllRegionVariableOrigin::Existential { from_forall: false }, universe, ) @@ -110,15 +102,17 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { sub: ty::Region<'tcx>, info: ty::VarianceDiagInfo<'tcx>, ) { - let sub = self.borrowck_context.universal_regions.to_region_vid(sub); - let sup = self.borrowck_context.universal_regions.to_region_vid(sup); - self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint { - sup, - sub, - locations: self.locations, - category: self.category, - variance_info: info, - }); + let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); + let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); + self.type_checker.borrowck_context.constraints.outlives_constraints.push( + OutlivesConstraint { + sup, + sub, + locations: self.locations, + category: self.category, + variance_info: info, + }, + ); } // We don't have to worry about the equality of consts during borrow checking diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 0f88995846c..cd78c016caa 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -594,7 +594,7 @@ impl<'a> TraitDef<'a> { GenericParamKind::Const { ty, kw_span, .. } => { let const_nodefault_kind = GenericParamKind::Const { ty: ty.clone(), - kw_span: kw_span.clone(), + kw_span: *kw_span, // We can't have default values inside impl block default: None, diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 4d3b4f04bad..31959fa19c5 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -2,7 +2,7 @@ use gccjit::RValue; use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; use rustc_middle::mir; -use rustc_middle::ty::{Instance, Ty}; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; use rustc_target::abi::Size; use rustc_target::abi::call::FnAbi; @@ -31,7 +31,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _vtable: Self::Value) { + fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) { // TODO(antoyo) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index e2b33509b40..97780de9ba4 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -596,7 +596,7 @@ pub(crate) fn run_pass_manager( // tools/lto/LTOCodeGenerator.cpp debug!("running the pass manager"); unsafe { - if write::should_use_new_llvm_pass_manager(config) { + if write::should_use_new_llvm_pass_manager(cgcx, config) { let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); write::optimize_with_new_llvm_pass_manager( diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ca78254f0c8..380dfd38723 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -377,10 +377,19 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> { .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) } -pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { +pub(crate) fn should_use_new_llvm_pass_manager( + cgcx: &CodegenContext<LlvmCodegenBackend>, + config: &ModuleConfig, +) -> bool { // The new pass manager is enabled by default for LLVM >= 13. // This matches Clang, which also enables it since Clang 13. - config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0)) + + // FIXME: There are some perf issues with the new pass manager + // when targeting s390x, so it is temporarily disabled for that + // arch, see https://github.com/rust-lang/rust/issues/89609 + config + .new_llvm_pass_manager + .unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0)) } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( @@ -482,7 +491,7 @@ pub(crate) unsafe fn optimize( } if let Some(opt_level) = config.opt_level { - if should_use_new_llvm_pass_manager(config) { + if should_use_new_llvm_pass_manager(cgcx, config) { let opt_stage = match cgcx.lto { Lto::Fat => llvm::OptStage::PreLinkFatLTO, Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9f7b8616d78..d5deacf3811 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -828,6 +828,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + let op = llvm::RealPredicate::from_generic(op); unsafe { llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 5d68d2b77d4..1bc924d3b90 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -175,7 +175,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value // should use dllimport for functions. if cx.use_dll_storage_attrs && tcx.is_dllimport_foreign_item(instance_def_id) - && tcx.sess.target.env != "gnu" + && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc") { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 8e6a66a6175..cd29f2af016 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -2,7 +2,7 @@ use self::MemberDescriptionFactory::*; use self::RecursiveTypeDescription::*; use super::namespace::mangled_name_of_instance; -use super::type_names::compute_debuginfo_type_name; +use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name}; use super::utils::{ create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB, }; @@ -29,8 +29,9 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES, +}; use rustc_middle::{bug, span_bug}; use rustc_query_system::ich::NodeIdHashingMode; use rustc_session::config::{self, DebugInfo}; @@ -2591,11 +2592,45 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global } } +/// Generates LLVM debuginfo for a vtable. +fn vtable_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, +) -> &'ll DIType { + let tcx = cx.tcx; + + let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { + let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); + let trait_ref = tcx.erase_regions(trait_ref); + + tcx.vtable_entries(trait_ref) + } else { + COMMON_VTABLE_ENTRIES + }; + + // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is + // correct - but we could create a more accurate description, e.g. by describing it + // as a struct where each field has a name that corresponds to the name of the method + // it points to. + // However, this is not entirely straightforward because there might be multiple + // methods with the same name if the vtable is for multiple traits. So for now we keep + // things simple instead of adding some ad-hoc disambiguation scheme. + let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64); + + type_metadata(cx, vtable_type, rustc_span::DUMMY_SP) +} + /// Creates debug information for the given vtable, which is for the /// given type. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) { +pub fn create_vtable_metadata( + cx: &CodegenCx<'ll, 'tcx>, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + vtable: &'ll Value, +) { if cx.dbg_cx.is_none() { return; } @@ -2605,42 +2640,16 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & return; } - let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP); + let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref); + let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref); unsafe { - // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in `llvm/lib/IR/Value.cpp`. - let empty_array = create_DIArray(DIB(cx), &[]); - let name = "vtable"; - - // Create a new one each time. We don't want metadata caching - // here, because each vtable will refer to a unique containing - // type. - let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - NO_SCOPE_METADATA, - name.as_ptr().cast(), - name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - Size::ZERO.bits(), - cx.tcx.data_layout.pointer_align.abi.bits() as u32, - DIFlags::FlagArtificial, - None, - empty_array, - 0, - Some(type_metadata), - name.as_ptr().cast(), - name.len(), - ); - let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr().cast(), - name.len(), + vtable_name.as_ptr().cast(), + vtable_name.len(), linkage_name.as_ptr().cast(), linkage_name.len(), unknown_file_metadata(cx), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 894320a7982..1f1bd73c7d0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -550,8 +550,13 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) } } - fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) { - metadata::create_vtable_metadata(self, ty, vtable) + fn create_vtable_metadata( + &self, + ty: Ty<'tcx>, + trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + vtable: Self::Value, + ) { + metadata::create_vtable_metadata(self, ty, trait_ref, vtable) } fn extend_scope_to_file( diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 63eca00de2a..4c9ae4faf72 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -223,6 +223,33 @@ pub enum RealPredicate { RealPredicateTrue = 15, } +impl RealPredicate { + pub fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self { + match realp { + rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => { + RealPredicate::RealPredicateFalse + } + rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ, + rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT, + rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE, + rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT, + rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE, + rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE, + rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD, + rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO, + rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ, + rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT, + rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE, + rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT, + rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE, + rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE, + rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => { + RealPredicate::RealPredicateTrue + } + } + } +} + /// LLVMTypeKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 3fdfb08f584..cf1c6058897 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -843,19 +843,18 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( let msg_bus = "clang: error: unable to execute command: Bus error: 10"; if out.contains(msg_segv) || out.contains(msg_bus) { warn!( + ?cmd, %out, "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again. cmd = {:?}, out = {}.", - cmd, out, + automatically retrying again", ); continue; } if is_illegal_instruction(&output.status) { warn!( + ?cmd, %out, status = %output.status, "looks like the linker hit an illegal instruction when we \ - tried to call it, automatically retrying again. cmd = {:?}, ]\ - out = {}, status = {}.", - cmd, out, output.status, + tried to call it, automatically retrying again.", ); continue; } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 6e7b2968597..609316ea69f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -446,6 +446,62 @@ fn push_debuginfo_type_name<'tcx>( } } +/// Computes a name for the global variable storing a vtable. +/// +/// The name is of the form: +/// +/// `<path::to::SomeType as path::to::SomeTrait>::{vtable}` +/// +/// or, when generating C++-like names: +/// +/// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$` +pub fn compute_debuginfo_vtable_name<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, +) -> String { + let cpp_like_names = cpp_like_names(tcx); + + let mut vtable_name = String::with_capacity(64); + + if cpp_like_names { + vtable_name.push_str("impl$<"); + } else { + vtable_name.push('<'); + } + + let mut visited = FxHashSet::default(); + push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited); + + if cpp_like_names { + vtable_name.push_str(", "); + } else { + vtable_name.push_str(" as "); + } + + if let Some(trait_ref) = trait_ref { + push_item_name(tcx, trait_ref.skip_binder().def_id, true, &mut vtable_name); + visited.clear(); + push_generic_params_internal( + tcx, + trait_ref.skip_binder().substs, + &mut vtable_name, + &mut visited, + ); + } else { + vtable_name.push_str("_"); + } + + push_close_angle_bracket(cpp_like_names, &mut vtable_name); + + let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" }; + + vtable_name.reserve_exact(suffix.len()); + vtable_name.push_str(suffix); + + vtable_name +} + pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { let def_key = tcx.def_key(def_id); if qualified { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 3267d3206f7..6ab429669c8 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -78,7 +78,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); - cx.create_vtable_metadata(ty, vtable); + cx.create_vtable_metadata(ty, trait_ref, vtable); cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 3e66d711d2e..e700afc448f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -1,13 +1,18 @@ use super::BackendTypes; use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc_middle::mir; -use rustc_middle::ty::{Instance, Ty}; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; pub trait DebugInfoMethods<'tcx>: BackendTypes { - fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value); + fn create_vtable_metadata( + &self, + ty: Ty<'tcx>, + trait_ref: Option<PolyExistentialTraitRef<'tcx>>, + vtable: Self::Value, + ); /// Creates the function-specific debug context. /// diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs index 3c7bea27124..81e2501ecbe 100644 --- a/compiler/rustc_data_structures/src/base_n.rs +++ b/compiler/rustc_data_structures/src/base_n.rs @@ -14,7 +14,7 @@ const BASE_64: &[u8; MAX_BASE as usize] = #[inline] pub fn push_str(mut n: u128, base: usize, output: &mut String) { - debug_assert!(base >= 2 && base <= MAX_BASE); + debug_assert!((2..=MAX_BASE).contains(&base)); let mut s = [0u8; 128]; let mut index = 0; diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 1aa7ac024d9..9ff401c3c7a 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -206,17 +206,11 @@ impl<N: Debug, E: Debug> Graph<N, E> { AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator<Item = NodeIndex> + 'a { + pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator<Item = NodeIndex> + 'a { + pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ { self.incoming_edges(target).sources() } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index a9db3497b23..1c6979dc489 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -48,7 +48,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>( let node = frame.node; visited[node] = true; - while let Some(successor) = frame.iter.next() { + for successor in frame.iter.by_ref() { if !visited[successor] { stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }); continue 'recurse; @@ -112,7 +112,7 @@ where /// This is equivalent to just invoke `next` repeatedly until /// you get a `None` result. pub fn complete_search(&mut self) { - while let Some(_) = self.next() {} + for _ in self {} } /// Returns true if node has been visited thus far. diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 25b7a84b3a0..caf515b0d19 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -390,7 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> { .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); - self.compress(|_| assert!(false)); + self.compress(|_| unreachable!()); errors } @@ -612,7 +612,7 @@ impl<O: ForestObligation> ObligationForest<O> { fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { let orig_nodes_len = self.nodes.len(); let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); - debug_assert!(node_rewrites.is_empty()); + assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; @@ -623,13 +623,13 @@ impl<O: ForestObligation> ObligationForest<O> { // self.nodes[0..index - dead_nodes] are the first remaining nodes // self.nodes[index - dead_nodes..index] are all dead // self.nodes[index..] are unchanged - for index in 0..orig_nodes_len { + for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() { let node = &self.nodes[index]; match node.state.get() { NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; + *node_rewrite -= dead_nodes; } } NodeState::Done => { @@ -646,7 +646,7 @@ impl<O: ForestObligation> ObligationForest<O> { } // Extract the success stories. outcome_cb(&node.obligation); - node_rewrites[index] = orig_nodes_len; + *node_rewrite = orig_nodes_len; dead_nodes += 1; } NodeState::Error => { @@ -655,7 +655,7 @@ impl<O: ForestObligation> ObligationForest<O> { // check against. self.active_cache.remove(&node.obligation.as_cache_key()); self.insert_into_error_cache(index); - node_rewrites[index] = orig_nodes_len; + *node_rewrite = orig_nodes_len; dead_nodes += 1; } NodeState::Success => unreachable!(), diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 20e2a3b9696..e80db0845a7 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -205,10 +205,10 @@ impl<K: Ord, V> SortedMap<K, V> { R: RangeBounds<K>, { let start = match range.start_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, @@ -216,11 +216,11 @@ impl<K: Ord, V> SortedMap<K, V> { }; let end = match range.end_bound() { - Bound::Included(ref k) => match self.lookup_index_for(k) { + Bound::Included(k) => match self.lookup_index_for(k) { Ok(index) => index + 1, Err(index) => index, }, - Bound::Excluded(ref k) => match self.lookup_index_for(k) { + Bound::Excluded(k) => match self.lookup_index_for(k) { Ok(index) | Err(index) => index, }, Bound::Unbounded => self.data.len(), diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index e92db9ea128..1395bb16e87 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -75,7 +75,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> { + pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> { self.get_by_key_enumerated(key).map(|(_, v)| v) } @@ -84,7 +84,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { /// /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. - pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> { + pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> { let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key); self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| { let (k, v) = &self.items[i]; diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 2de05cd4e56..d4274e99f1c 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -257,11 +257,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> { pub fn remove(&mut self, key: &K) -> Option<V> { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k == key) { - Some(array.swap_remove(index).1) - } else { - None - } + array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1) } SsoHashMap::Map(map) => map.remove(key), } @@ -272,11 +268,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> { pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { match self { SsoHashMap::Array(array) => { - if let Some(index) = array.iter().position(|(k, _v)| k == key) { - Some(array.swap_remove(index)) - } else { - None - } + array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index)) } SsoHashMap::Map(map) => map.remove_entry(key), } @@ -423,14 +415,14 @@ impl<K, V> IntoIterator for SsoHashMap<K, V> { /// adapts Item of array reference iterator to Item of hashmap reference iterator. #[inline(always)] -fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) { +fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) { let (a, b) = pair; (a, b) } /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. #[inline(always)] -fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) { +fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) { let (a, b) = pair; (a, b) } diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index 29baf4e1ddb..f71522d3714 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -75,7 +75,7 @@ impl<T> SsoHashSet<T> { /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. #[inline] - pub fn iter(&'a self) -> impl Iterator<Item = &'a T> { + pub fn iter(&self) -> impl Iterator<Item = &T> { self.into_iter() } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 354f9dd93cc..2e992e76227 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -229,14 +229,14 @@ impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize { impl<CTX> HashStable<CTX> for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = unsafe { ::std::mem::transmute(*self) }; + let val: u32 = self.to_bits(); val.hash_stable(ctx, hasher); } } impl<CTX> HashStable<CTX> for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = unsafe { ::std::mem::transmute(*self) }; + let val: u64 = self.to_bits(); val.hash_stable(ctx, hasher); } } diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index a4964b7aa0c..ba22c7f9b97 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,6 +5,7 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. +#[allow(clippy::identity_op)] const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index a1ffbae8b15..a3ece655047 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -34,7 +34,7 @@ impl<T> Steal<T> { #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { let borrow = self.value.borrow(); - if let None = &*borrow { + if borrow.is_none() { panic!("attempted to read from stolen value: {}", std::any::type_name::<T>()); } ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs index 9b07f86846e..9e605ea2d98 100644 --- a/compiler/rustc_data_structures/src/tiny_list.rs +++ b/compiler/rustc_data_structures/src/tiny_list.rs @@ -48,7 +48,7 @@ impl<T: PartialEq> TinyList<T> { #[inline] pub fn contains(&self, data: &T) -> bool { let mut elem = self.head.as_ref(); - while let Some(ref e) = elem { + while let Some(e) = elem { if &e.data == data { return true; } diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs index 1cf030d852e..ce60d40b24b 100644 --- a/compiler/rustc_data_structures/src/vec_linked_list.rs +++ b/compiler/rustc_data_structures/src/vec_linked_list.rs @@ -2,8 +2,8 @@ use rustc_index::vec::{Idx, IndexVec}; pub fn iter<Ls>( first: Option<Ls::LinkIndex>, - links: &'a Ls, -) -> impl Iterator<Item = Ls::LinkIndex> + 'a + links: &Ls, +) -> impl Iterator<Item = Ls::LinkIndex> + '_ where Ls: Links, { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index ab7ee03b643..9a57ec99144 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1253,12 +1253,16 @@ pub fn init_rustc_env_logger() { /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) { - // Don't register a dispatcher if there's no filter to print anything - match std::env::var(env) { - Err(_) => return, - Ok(s) if s.is_empty() => return, - Ok(_) => {} - } + use tracing_subscriber::{ + filter::{self, EnvFilter, LevelFilter}, + layer::SubscriberExt, + }; + + let filter = match std::env::var(env) { + Ok(env) => EnvFilter::new(env), + _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)), + }; + let color_logs = match std::env::var(String::from(env) + "_COLOR") { Ok(value) => match value.as_ref() { "always" => true, @@ -1278,7 +1282,7 @@ pub fn init_env_logger(env: &str) { "non-Unicode log color value: expected one of always, never, or auto", ), }; - let filter = tracing_subscriber::EnvFilter::from_env(env); + let layer = tracing_tree::HierarchicalLayer::default() .with_writer(io::stderr) .with_indent_lines(true) @@ -1288,7 +1292,6 @@ pub fn init_env_logger(env: &str) { #[cfg(parallel_compiler)] let layer = layer.with_thread_ids(true).with_thread_names(true); - use tracing_subscriber::layer::SubscriberExt; let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); tracing::subscriber::set_global_default(subscriber).unwrap(); } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 45d91c2047d..1b4b58314b3 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -242,6 +242,7 @@ E0468: include_str!("./error_codes/E0468.md"), E0469: include_str!("./error_codes/E0469.md"), E0477: include_str!("./error_codes/E0477.md"), E0478: include_str!("./error_codes/E0478.md"), +E0482: include_str!("./error_codes/E0482.md"), E0491: include_str!("./error_codes/E0491.md"), E0492: include_str!("./error_codes/E0492.md"), E0493: include_str!("./error_codes/E0493.md"), @@ -599,7 +600,6 @@ E0785: include_str!("./error_codes/E0785.md"), // E0479, // the type `..` (provided as the value of a type parameter) is... // E0480, // lifetime of method receiver does not outlive the method call // E0481, // lifetime of function argument does not outlive the function call - E0482, // lifetime of return value does not outlive the function call // E0483, // lifetime of operand does not outlive the operation // E0484, // reference is not valid at the time of borrow // E0485, // automatically reference is not valid at the time of borrow diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md new file mode 100644 index 00000000000..58ebf43cc98 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0482.md @@ -0,0 +1,73 @@ +A lifetime of a returned value does not outlive the function call. + +Erroneous code example: + +```compile_fail,E0482 +fn prefix<'a>( + words: impl Iterator<Item = &'a str> +) -> impl Iterator<Item = String> { // error! + words.map(|v| format!("foo-{}", v)) +} +``` + +To fix this error, make the lifetime of the returned value explicit: + +``` +fn prefix<'a>( + words: impl Iterator<Item = &'a str> + 'a +) -> impl Iterator<Item = String> + 'a { // ok! + words.map(|v| format!("foo-{}", v)) +} +``` + +The [`impl Trait`] feature in this example uses an implicit `'static` lifetime +restriction in the returned type. However the type implementing the `Iterator` +passed to the function lives just as long as `'a`, which is not long enough. + +The solution involves adding lifetime bound to both function argument and +the return value to make sure that the values inside the iterator +are not dropped when the function goes out of the scope. + +An alternative solution would be to guarantee that the `Item` references +in the iterator are alive for the whole lifetime of the program. + +``` +fn prefix( + words: impl Iterator<Item = &'static str> +) -> impl Iterator<Item = String> { // ok! + words.map(|v| format!("foo-{}", v)) +} +``` + +A similar lifetime problem might arise when returning closures: + +```compile_fail,E0482 +fn foo( + x: &mut Vec<i32> +) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error! + |y| { + y.append(x); + y + } +} +``` + +Analogically, a solution here is to use explicit return lifetime +and move the ownership of the variable to the closure. + +``` +fn foo<'a>( + x: &'a mut Vec<i32> +) -> impl FnMut(&mut Vec<i32>) -> &[i32] + 'a { // ok! + move |y| { + y.append(x); + y + } +} +``` + +To better understand the lifetime treatment in the [`impl Trait`], +please see the [RFC 1951]. + +[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html +[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 29f352ae585..778d58eeadc 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2308,7 +2308,7 @@ pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool { let found = match sm.span_to_snippet(sp) { Ok(snippet) => snippet, Err(e) => { - warn!("Invalid span {:?}. Err={:?}", sp, e); + warn!(error = ?e, "Invalid span {:?}", sp); return false; } }; diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 2ef0e0f6b1e..55ec3703df8 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -288,7 +288,7 @@ declare_features! ( (accepted, member_constraints, "1.54.0", Some(61997), None), /// Allows bindings in the subpattern of a binding pattern. /// For example, you can write `x @ Some(y)`. - (accepted, bindings_after_at, "1.54.0", Some(65490), None), + (accepted, bindings_after_at, "1.56.0", Some(65490), None), /// Allows calling `transmute` in const fn (accepted, const_fn_transmute, "1.56.0", Some(53605), None), /// Allows accessing fields of unions inside `const` functions. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ec2c703ad49..a2fadb13a57 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -678,6 +678,9 @@ declare_features! ( /// Allows `#[doc(cfg_hide(...))]`. (active, doc_cfg_hide, "1.57.0", Some(43781), None), + /// Allows using the `non_exhaustive_omitted_patterns` lint. + (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 27390fd2e4d..e69289b71f9 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -512,7 +512,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match *self { LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), + EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)), HtmlStr(ref s) => format!("<{}>", s), } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fdd52bd7495..5264f7cc326 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2293,6 +2293,13 @@ impl<'hir> InlineAsmOperand<'hir> { Self::Const { .. } | Self::Sym { .. } => None, } } + + pub fn is_clobber(&self) -> bool { + matches!( + self, + InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None } + ) + } } #[derive(Debug, HashStable_Generic)] diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 5b1add4cfc6..1995fd64e6f 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -990,9 +990,8 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { pub fn insert_all_into_row(&mut self, row: R) { assert!(row.index() < self.num_rows); let (start, end) = self.range(row); - let words = &mut self.words[..]; - for index in start..end { - words[index] = !0; + for word in self.words[start..end].iter_mut() { + *word = !0; } self.clear_excess_bits(row); } @@ -1144,7 +1143,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a { + pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ { self.row(row).into_iter().flat_map(|r| r.iter()) } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 88315246834..69578e85f27 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -634,18 +634,15 @@ impl<I: Idx, T> IndexVec<I, T> { } #[inline] - pub fn drain<'a, R: RangeBounds<usize>>( - &'a mut self, - range: R, - ) -> impl Iterator<Item = T> + 'a { + pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeBounds<usize>>( - &'a mut self, + pub fn drain_enumerated<R: RangeBounds<usize>>( + &mut self, range: R, - ) -> impl Iterator<Item = (I, T)> + 'a { + ) -> impl Iterator<Item = (I, T)> + '_ { self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t)) } @@ -741,6 +738,12 @@ impl<I: Idx, T> IndexVec<I, Option<T>> { self.ensure_contains_elem(index, || None); self[index].get_or_insert_with(value) } + + #[inline] + pub fn remove(&mut self, index: I) -> Option<T> { + self.ensure_contains_elem(index, || None); + self[index].take() + } } impl<I: Idx, T: Clone> IndexVec<I, T> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c44d4361f03..056709cd314 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2060,14 +2060,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(pretty_exp_found) + match self.expected_found_str(pretty_exp_found) { + Some((expected, found)) if expected == found => { + self.expected_found_str(exp_found) + } + ret => ret, + } } infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(pretty_exp_found) + match self.expected_found_str(pretty_exp_found) { + Some((expected, found)) if expected == found => { + self.expected_found_str(exp_found) + } + ret => ret, + } } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 43aa8a6efce..0efe5a56436 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -130,8 +130,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name)); - err.span_label(impl_sp, &format!("found")); - err.span_label(trait_sp, &format!("expected")); + err.span_label(impl_sp, "found"); + err.span_label(trait_sp, "expected"); err.emit(); } diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index b970c9e4911..804dc657f2d 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -68,11 +68,10 @@ pub enum EscapeError { impl EscapeError { /// Returns true for actual errors, as opposed to warnings. pub fn is_fatal(&self) -> bool { - match self { - EscapeError::UnskippedWhitespaceWarning => false, - EscapeError::MultipleSkippedLinesWarning => false, - _ => true, - } + !matches!( + self, + EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning + ) } } @@ -330,7 +329,7 @@ where callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning)); } let tail = &tail[first_non_space..]; - if let Some(c) = tail.chars().nth(0) { + if let Some(c) = tail.chars().next() { // For error reporting, we would like the span to contain the character that was not // skipped. The +1 is necessary to account for the leading \ that started the escape. let end = start + first_non_space + c.len_utf8() + 1; diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs new file mode 100644 index 00000000000..876245747f6 --- /dev/null +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -0,0 +1,106 @@ +use crate::{context::LintContext, LateContext, LateLintPass}; +use rustc_hir as hir; +use rustc_middle::ty::{fold::TypeFoldable, Ty}; +use rustc_span::{symbol::sym, Span}; + +declare_lint! { + /// The `enum_intrinsics_non_enums` lint detects calls to + /// intrinsic functions that require an enum ([`core::mem::discriminant`], + /// [`core::mem::variant_count`]), but are called with a non-enum type. + /// + /// [`core::mem::discriminant`]: https://doc.rust-lang.org/core/mem/fn.discriminant.html + /// [`core::mem::variant_count`]: https://doc.rust-lang.org/core/mem/fn.variant_count.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(enum_intrinsics_non_enums)] + /// core::mem::discriminant::<i32>(&123); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order to accept any enum, the `mem::discriminant` and + /// `mem::variant_count` functions are generic over a type `T`. + /// This makes it technically possible for `T` to be a non-enum, + /// in which case the return value is unspecified. + /// + /// This lint prevents such incorrect usage of these functions. + ENUM_INTRINSICS_NON_ENUMS, + Deny, + "detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types" +} + +declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]); + +/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where +/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is. +fn is_non_enum(t: Ty<'_>) -> bool { + !t.is_enum() && !t.potentially_needs_subst() +} + +fn enforce_mem_discriminant( + cx: &LateContext<'_>, + func_expr: &hir::Expr<'_>, + expr_span: Span, + args_span: Span, +) { + let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); + if is_non_enum(ty_param) { + cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { + builder + .build( + "the return value of `mem::discriminant` is \ + unspecified when called with a non-enum type", + ) + .span_note( + args_span, + &format!( + "the argument to `discriminant` should be a \ + reference to an enum, but it was passed \ + a reference to a `{}`, which is not an enum.", + ty_param, + ), + ) + .emit(); + }); + } +} + +fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) { + let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); + if is_non_enum(ty_param) { + cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { + builder + .build( + "the return value of `mem::variant_count` is \ + unspecified when called with a non-enum type", + ) + .note(&format!( + "the type parameter of `variant_count` should \ + be an enum, but it was instantiated with \ + the type `{}`, which is not an enum.", + ty_param, + )) + .emit(); + }); + } +} + +impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + if let hir::ExprKind::Call(ref func, ref args) = expr.kind { + if let hir::ExprKind::Path(ref qpath) = func.kind { + if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() { + if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) { + enforce_mem_discriminant(cx, func, expr.span, args[0].span); + } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) { + enforce_mem_variant_count(cx, func, expr.span); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 66966e589e4..b6d66eb12d0 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,7 +1,6 @@ use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; use rustc_ast as ast; -use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -233,7 +232,10 @@ impl<'s> LintLevelsBuilder<'s> { Some(lvl) => lvl, }; - let mut metas = unwrap_or!(attr.meta_item_list(), continue); + let mut metas = match attr.meta_item_list() { + Some(x) => x, + None => continue, + }; if metas.is_empty() { // FIXME (#55112): issue unused-attributes lint for `#[level()]` diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 17eb0054584..6f684a0fe51 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -47,6 +47,7 @@ mod array_into_iter; pub mod builtin; mod context; mod early; +mod enum_intrinsics_non_enums; mod internal; mod late; mod levels; @@ -76,6 +77,7 @@ use rustc_span::Span; use array_into_iter::ArrayIntoIter; use builtin::*; +use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use internal::*; use methods::*; use non_ascii_idents::*; @@ -168,6 +170,7 @@ macro_rules! late_lint_passes { TemporaryCStringAsPtr: TemporaryCStringAsPtr, NonPanicFmt: NonPanicFmt, NoopMethodCall: NoopMethodCall, + EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, InvalidAtomicOrdering: InvalidAtomicOrdering, NamedAsmLabels: NamedAsmLabels, ] diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 103555a6752..f2ad72f97ec 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -230,8 +230,7 @@ fn check_panic_str<'tcx>( Err(_) => (None, None), }; - let mut fmt_parser = - Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format); + let mut fmt_parser = Parser::new(fmt, style, snippet.clone(), false, ParseMode::Format); let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count(); if n_arguments > 0 && fmt_parser.errors.is_empty() { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7a51e1e321a..a93d18950db 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -6,6 +6,7 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; use rustc_span::edition::Edition; +use rustc_span::symbol::sym; declare_lint! { /// The `forbidden_lint_groups` lint detects violations of @@ -3476,6 +3477,8 @@ declare_lint! { /// } /// /// // in crate B + /// #![feature(non_exhaustive_omitted_patterns_lint)] + /// /// match Bar::A { /// Bar::A => {}, /// #[warn(non_exhaustive_omitted_patterns)] @@ -3512,6 +3515,7 @@ declare_lint! { pub NON_EXHAUSTIVE_OMITTED_PATTERNS, Allow, "detect when patterns of types marked `non_exhaustive` are missed", + @feature_gate = sym::non_exhaustive_omitted_patterns_lint; } declare_lint! { diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index dba885a27fe..63bdcea87f8 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -24,11 +24,9 @@ fn parse_attributes(field: &syn::Field) -> Attributes { } if meta.path().is_ident("project") { if let Meta::List(list) = meta { - if let Some(nested) = list.nested.iter().next() { - if let NestedMeta::Meta(meta) = nested { - attrs.project = meta.path().get_ident().cloned(); - any_attr = true; - } + if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() { + attrs.project = meta.path().get_ident().cloned(); + any_attr = true; } } } diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 80dcf99da62..c8959dc86ad 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -349,14 +349,14 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> { let field_binding = &info.binding.binding; - let option_ty = option_inner_ty(&info.ty); + let option_ty = option_inner_ty(info.ty); let generated_code = self.generate_non_option_field_code( attr, FieldInfo { vis: info.vis, binding: info.binding, - ty: option_ty.unwrap_or(&info.ty), + ty: option_ty.unwrap_or(info.ty), span: info.span, }, )?; @@ -388,7 +388,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { let formatted_str = self.build_format(&s.value(), attr.span()); match name { "message" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty, &["rustc_span", "Span"]) { quote! { #diag.set_span(*#field_binding); #diag.set_primary_message(#formatted_str); @@ -401,7 +401,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { } } "label" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty, &["rustc_span", "Span"]) { quote! { #diag.span_label(*#field_binding, #formatted_str); } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index a7446765900..2431b819a3f 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -363,7 +363,7 @@ impl Collector<'tcx> { .collect::<Vec<_>>(); if existing.is_empty() { // Add if not found - let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str> + let new_name: Option<&str> = passed_lib.new_name.as_deref(); let lib = NativeLib { name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))), kind: passed_lib.kind, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 07d42902be5..23d475a5953 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -63,6 +63,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::DefPathHash; use rustc_hir::HirId; +use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; use std::hash::Hash; @@ -89,9 +90,9 @@ pub struct DepKindStruct { /// Whether the query key can be recovered from the hashed fingerprint. /// See [DepNodeParams] trait for the behaviour of each key type. - // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key + // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style // can be made a specialized associated const. - can_reconstruct_query_key: fn() -> bool, + fingerprint_style: fn() -> FingerprintStyle, } impl std::ops::Deref for DepKind { @@ -103,14 +104,14 @@ impl std::ops::Deref for DepKind { impl DepKind { #[inline(always)] - pub fn can_reconstruct_query_key(&self) -> bool { + pub fn fingerprint_style(&self) -> FingerprintStyle { // Only fetch the DepKindStruct once. let data: &DepKindStruct = &**self; if data.is_anon { - return false; + return FingerprintStyle::Opaque; } - (data.can_reconstruct_query_key)() + (data.fingerprint_style)() } } @@ -151,6 +152,7 @@ macro_rules! contains_eval_always_attr { pub mod dep_kind { use super::*; use crate::ty::query::query_keys; + use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. pub const Null: DepKindStruct = DepKindStruct { @@ -158,7 +160,7 @@ pub mod dep_kind { is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || true, + fingerprint_style: || FingerprintStyle::Unit, }; pub const TraitSelect: DepKindStruct = DepKindStruct { @@ -166,7 +168,7 @@ pub mod dep_kind { is_anon: true, is_eval_always: false, - can_reconstruct_query_key: || true, + fingerprint_style: || FingerprintStyle::Unit, }; pub const CompileCodegenUnit: DepKindStruct = DepKindStruct { @@ -174,7 +176,7 @@ pub mod dep_kind { is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || false, + fingerprint_style: || FingerprintStyle::Opaque, }; pub const CompileMonoItem: DepKindStruct = DepKindStruct { @@ -182,7 +184,7 @@ pub mod dep_kind { is_anon: false, is_eval_always: false, - can_reconstruct_query_key: || false, + fingerprint_style: || FingerprintStyle::Opaque, }; macro_rules! define_query_dep_kinds { @@ -196,16 +198,16 @@ pub mod dep_kind { const is_eval_always: bool = contains_eval_always_attr!($($attrs)*); #[inline(always)] - fn can_reconstruct_query_key() -> bool { + fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle { <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>> - ::can_reconstruct_query_key() + ::fingerprint_style() } DepKindStruct { has_params, is_anon, is_eval_always, - can_reconstruct_query_key, + fingerprint_style, } };)* ); @@ -320,7 +322,7 @@ impl DepNodeExt for DepNode { /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params); + debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } @@ -335,7 +337,7 @@ impl DepNodeExt for DepNode { /// refers to something from the previous compilation session that /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> { - if self.kind.can_reconstruct_query_key() { + if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash { Some( tcx.on_disk_cache .as_ref()? @@ -350,14 +352,16 @@ impl DepNodeExt for DepNode { fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> { let kind = dep_kind_from_label_string(label)?; - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) + match kind.fingerprint_style() { + FingerprintStyle::Opaque => Err(()), + FingerprintStyle::Unit => { + if !kind.has_params { + Ok(DepNode::new_no_params(kind)) + } else { + Err(()) + } + } + FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)), } } @@ -369,8 +373,8 @@ impl DepNodeExt for DepNode { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Unit } fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { @@ -384,8 +388,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { @@ -403,8 +407,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { @@ -422,8 +426,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - true + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::DefPathHash } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { @@ -442,8 +446,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - false + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } // We actually would not need to specialize the implementation of this @@ -467,8 +471,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { #[inline(always)] - fn can_reconstruct_query_key() -> bool { - false + fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } // We actually would not need to specialize the implementation of this diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 70895f7b98e..cda99639074 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -25,8 +25,8 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; #[inline(always)] - fn can_reconstruct_query_key(&self) -> bool { - DepKind::can_reconstruct_query_key(self) + fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle { + DepKind::fingerprint_style(self) } #[inline(always)] diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 87495a2d5b3..6720493cd3c 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -264,14 +264,14 @@ impl EvaluationResult { /// Indicates that trait evaluation caused overflow and in which pass. #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] pub enum OverflowError { - Cannonical, + Canonical, ErrorReporting, } impl<'tcx> From<OverflowError> for SelectionError<'tcx> { fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { match overflow_error { - OverflowError::Cannonical => SelectionError::Overflow, + OverflowError::Canonical => SelectionError::Overflow, OverflowError::ErrorReporting => SelectionError::ErrorReporting, } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index fee13fd2e2e..d0c7379c2d9 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -986,7 +986,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let niche = if def.repr.hide_niche() { None } else { - Niche::from_scalar(dl, Size::ZERO, scalar.clone()) + Niche::from_scalar(dl, Size::ZERO, *scalar) }; if let Some(niche) = niche { match st.largest_niche { @@ -2273,7 +2273,7 @@ where ) -> TyMaybeWithLayout<'tcx> { let tcx = cx.tcx(); let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> { - let layout = Layout::scalar(cx, tag.clone()); + let layout = Layout::scalar(cx, tag); TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) } }; @@ -3012,7 +3012,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let target = &self.tcx.sess.target; - let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl"); + let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc"); let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu"; let linux_s390x_gnu_like = target.os == "linux" && target.arch == "s390x" && target_env_gnu_like; @@ -3110,7 +3110,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. - // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl}. + // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}. if is_return || rust_abi || (!win_x64_gnu diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 1464ea58ad0..9a86d465f98 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Call { func: exchange_malloc, args: vec![Operand::Move(size), Operand::Move(align)], - destination: Some((Place::from(storage), success)), + destination: Some((storage, success)), cleanup: None, from_hir_call: false, fn_span: expr_span, @@ -153,7 +153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Transmute `*mut u8` to the box (thus far, uninitialized): - let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty); + let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index dfcbd0da3a6..9e961f7ba5d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1068,9 +1068,7 @@ impl<'tcx> SplitWildcard<'tcx> { Missing { nonexhaustive_enum_missing_real_variants: self .iter_missing(pcx) - .filter(|c| !c.is_non_exhaustive()) - .next() - .is_some(), + .any(|c| !c.is_non_exhaustive()), } } else { Missing { nonexhaustive_enum_missing_real_variants: false } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 29ffed99344..c0bf4b659aa 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -289,7 +289,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { flow_state: &BitSet<Local>, call: PeekCall, ) { - warn!("peek_at: place={:?}", place); + info!(?place, "peek_at"); let local = if let Some(l) = place.as_local() { l } else { @@ -311,7 +311,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { flow_state: &BitSet<Local>, call: PeekCall, ) { - warn!("peek_at: place={:?}", place); + info!(?place, "peek_at"); let local = if let Some(l) = place.as_local() { l } else { diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index d7f1ad7f696..f191911a6c7 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { } // check that the value being matched on is the same. The - if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() { + if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) { trace!("NO: values being matched on are not the same"); return None; } diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 60e71130cd1..76f0e83c8c3 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -111,8 +111,7 @@ impl<'a, 'tcx> Patcher<'a, 'tcx> { Operand::Copy(place) | Operand::Move(place) => { // create new local let ty = operand.ty(self.local_decls, self.tcx); - let local_decl = - LocalDecl::with_source_info(ty, statement.source_info.clone()); + let local_decl = LocalDecl::with_source_info(ty, statement.source_info); let local = self.local_decls.push(local_decl); // make it live let mut make_live_statement = statement.clone(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 79f46be73f6..3d29d305021 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1096,7 +1096,7 @@ impl<'a> Parser<'a> { (Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => { let name = pprust::path_to_string(&path); snapshot.bump(); // `(` - match snapshot.parse_struct_fields(path.clone(), false, token::Paren) { + match snapshot.parse_struct_fields(path, false, token::Paren) { Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => { // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1815302101f..e5fbddda744 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1767,8 +1767,7 @@ impl CheckAttrVisitor<'tcx> { fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!("`#[macro_export]` only has an effect on macro definitions")) - .emit(); + lint.build("`#[macro_export]` only has an effect on macro definitions").emit(); }); } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 4a82252a32b..a0ceb567f25 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -83,30 +82,39 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< let _: Option<_> = try { if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::Constness::Const = imp.constness { - let did = imp.of_trait.as_ref()?.trait_def_id()?; - let mut to_implement = FxHashSet::default(); - - for did in self.tcx.associated_item_def_ids(did) { + let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; + let ancestors = self + .tcx + .trait_def(trait_def_id) + .ancestors(self.tcx, item.def_id.to_def_id()) + .ok()?; + let mut to_implement = Vec::new(); + + for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() + { if let ty::AssocItem { kind: ty::AssocKind::Fn, ident, defaultness, .. - } = self.tcx.associated_item(*did) + } = trait_item { // we can ignore functions that do not have default bodies: // if those are unimplemented it will be catched by typeck. - if defaultness.has_value() - && !self.tcx.has_attr(*did, sym::default_method_body_is_const) + if !defaultness.has_value() + || self + .tcx + .has_attr(trait_item.def_id, sym::default_method_body_is_const) { - to_implement.insert(ident); + continue; } - } - } - for it in imp - .items - .iter() - .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. })) - { - to_implement.remove(&it.ident); + let is_implemented = ancestors + .leaf_def(self.tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented { + to_implement.push(ident.to_string()); + } + } } // all nonconst trait functions (not marked with #[default_method_body_is_const]) @@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< item.span, "const trait implementations may not use non-const default functions", ) - .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `"))) + .note(&format!("`{}` not implemented", to_implement.join("`, `"))) .emit(); } } diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 96e9a40df36..008b856ebf2 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -141,6 +141,7 @@ impl ExprVisitor<'tcx> { template: &[InlineAsmTemplatePiece], is_input: bool, tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>, + target_features: &[Symbol], ) -> Option<InlineAsmType> { // Check the type against the allowed types for inline asm. let ty = self.typeck_results.expr_ty_adjusted(expr); @@ -283,17 +284,20 @@ impl ExprVisitor<'tcx> { }; // Check whether the selected type requires a target feature. Note that - // this is different from the feature check we did earlier in AST - // lowering. While AST lowering checked that this register class is - // usable at all with the currently enabled features, some types may - // only be usable with a register class when a certain feature is - // enabled. We check this here since it depends on the results of typeck. + // this is different from the feature check we did earlier. While the + // previous check checked that this register class is usable at all + // with the currently enabled features, some types may only be usable + // with a register class when a certain feature is enabled. We check + // this here since it depends on the results of typeck. // // Also note that this check isn't run when the operand type is never - // (!). In that case we still need the earlier check in AST lowering to - // verify that the register class is usable at all. + // (!). In that case we still need the earlier check to verify that the + // register class is usable at all. if let Some(feature) = feature { - if !self.tcx.sess.target_features.contains(&Symbol::intern(feature)) { + let feat_sym = Symbol::intern(feature); + if !self.tcx.sess.target_features.contains(&feat_sym) + && !target_features.contains(&feat_sym) + { let msg = &format!("`{}` target feature is not enabled", feature); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!( @@ -349,23 +353,122 @@ impl ExprVisitor<'tcx> { Some(asm_ty) } - fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { - for (idx, (op, _)) in asm.operands.iter().enumerate() { + fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) { + let hir = self.tcx.hir(); + let enclosing_id = hir.enclosing_body_owner(hir_id); + let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id(); + let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id); + for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { + // Validate register classes against currently enabled target + // features. We check that at least one type is available for + // the enabled features. + // + // We ignore target feature requirements for clobbers: if the + // feature is disabled then the compiler doesn't care what we + // do with the registers. + // + // Note that this is only possible for explicit register + // operands, which cannot be used in the asm string. + if let Some(reg) = op.reg() { + if !op.is_clobber() { + let mut missing_required_features = vec![]; + let reg_class = reg.reg_class(); + for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap()) + { + match feature { + Some(feature) => { + let feat_sym = Symbol::intern(feature); + if self.tcx.sess.target_features.contains(&feat_sym) + || attrs.target_features.contains(&feat_sym) + { + missing_required_features.clear(); + break; + } else { + missing_required_features.push(feature); + } + } + None => { + missing_required_features.clear(); + break; + } + } + } + + // We are sorting primitive strs here and can use unstable sort here + missing_required_features.sort_unstable(); + missing_required_features.dedup(); + match &missing_required_features[..] { + [] => {} + [feature] => { + let msg = format!( + "register class `{}` requires the `{}` target feature", + reg_class.name(), + feature + ); + self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + // register isn't enabled, don't do more checks + continue; + } + features => { + let msg = format!( + "register class `{}` requires at least one of the following target features: {}", + reg_class.name(), + features.join(", ") + ); + self.tcx.sess.struct_span_err(*op_sp, &msg).emit(); + // register isn't enabled, don't do more checks + continue; + } + } + } + } + match *op { hir::InlineAsmOperand::In { reg, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + true, + None, + &attrs.target_features, + ); } hir::InlineAsmOperand::Out { reg, late: _, ref expr } => { if let Some(expr) = expr { - self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + false, + None, + &attrs.target_features, + ); } } hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); + self.check_asm_operand_type( + idx, + reg, + expr, + asm.template, + false, + None, + &attrs.target_features, + ); } hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => { - let in_ty = - self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); + let in_ty = self.check_asm_operand_type( + idx, + reg, + in_expr, + asm.template, + true, + None, + &attrs.target_features, + ); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, @@ -374,6 +477,7 @@ impl ExprVisitor<'tcx> { asm.template, false, Some((in_expr, in_ty)), + &attrs.target_features, ); } } @@ -422,7 +526,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> { } } - hir::ExprKind::InlineAsm(asm) => self.check_asm(asm), + hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id), _ => {} } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index b71a1722036..4d1e39db0ed 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -428,6 +428,7 @@ macro_rules! define_queries { use rustc_middle::ty::query::query_keys; use rustc_query_system::dep_graph::DepNodeParams; use rustc_query_system::query::{force_query, QueryDescription}; + use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. pub const Null: QueryStruct = QueryStruct { @@ -454,9 +455,9 @@ macro_rules! define_queries { const is_anon: bool = is_anon!([$($modifiers)*]); #[inline(always)] - fn can_reconstruct_query_key() -> bool { + fn fingerprint_style() -> FingerprintStyle { <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>> - ::can_reconstruct_query_key() + ::fingerprint_style() } fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> { @@ -472,7 +473,7 @@ macro_rules! define_queries { return } - if !can_reconstruct_query_key() { + if !fingerprint_style().reconstructible() { return } diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs index fa48df3ed45..c3bbd51f3d3 100644 --- a/compiler/rustc_query_impl/src/stats.rs +++ b/compiler/rustc_query_impl/src/stats.rs @@ -5,8 +5,6 @@ use rustc_query_system::query::{QueryCache, QueryCacheStore}; use std::any::type_name; use std::mem; -#[cfg(debug_assertions)] -use std::sync::atomic::Ordering; trait KeyStats { fn key_stats(&self, stats: &mut QueryStats); @@ -27,7 +25,6 @@ impl KeyStats for DefId { #[derive(Clone)] struct QueryStats { name: &'static str, - cache_hits: usize, key_size: usize, key_type: &'static str, value_size: usize, @@ -42,10 +39,6 @@ where { let mut stats = QueryStats { name, - #[cfg(debug_assertions)] - cache_hits: map.cache_hits.load(Ordering::Relaxed), - #[cfg(not(debug_assertions))] - cache_hits: 0, key_size: mem::size_of::<C::Key>(), key_type: type_name::<C::Key>(), value_size: mem::size_of::<C::Value>(), @@ -63,12 +56,6 @@ where pub fn print_stats(tcx: TyCtxt<'_>) { let queries = query_stats(tcx); - if cfg!(debug_assertions) { - let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); - let results: usize = queries.iter().map(|s| s.entry_count).sum(); - eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); - } - let mut query_key_sizes = queries.clone(); query_key_sizes.sort_by_key(|q| q.key_size); eprintln!("\nLarge query keys:"); @@ -83,20 +70,6 @@ pub fn print_stats(tcx: TyCtxt<'_>) { eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); } - if cfg!(debug_assertions) { - let mut query_cache_hits = queries.clone(); - query_cache_hits.sort_by_key(|q| q.cache_hits); - eprintln!("\nQuery cache hits:"); - for q in query_cache_hits.iter().rev() { - eprintln!( - " {} - {} ({}%)", - q.name, - q.cache_hits, - q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 - ); - } - } - let mut query_value_count = queries.clone(); query_value_count.sort_by_key(|q| q.entry_count); eprintln!("\nQuery value count:"); diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index dd500015374..8602219a7f3 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -42,7 +42,7 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -use super::{DepContext, DepKind}; +use super::{DepContext, DepKind, FingerprintStyle}; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; @@ -75,7 +75,7 @@ impl<K: DepKind> DepNode<K> { #[cfg(debug_assertions)] { - if !kind.can_reconstruct_query_key() + if !kind.fingerprint_style().reconstructible() && (tcx.sess().opts.debugging_opts.incremental_info || tcx.sess().opts.debugging_opts.query_dep_graph) { @@ -94,7 +94,7 @@ impl<K: DepKind> fmt::Debug for DepNode<K> { } pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized { - fn can_reconstruct_query_key() -> bool; + fn fingerprint_style() -> FingerprintStyle; /// This method turns the parameters of a DepNodeConstructor into an opaque /// Fingerprint to be used in DepNode. @@ -111,7 +111,7 @@ pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized { /// This method tries to recover the query key from the given `DepNode`, /// something which is needed when forcing `DepNode`s during red-green /// evaluation. The query system will only call this method if - /// `can_reconstruct_query_key()` is `true`. + /// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>; @@ -122,8 +122,8 @@ where T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug, { #[inline] - default fn can_reconstruct_query_key() -> bool { - false + default fn fingerprint_style() -> FingerprintStyle { + FingerprintStyle::Opaque } default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 2afef210254..dcda5728334 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -50,6 +50,27 @@ impl<T: DepContext> HasDepContext for T { } } +/// Describes the contents of the fingerprint generated by a given query. +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum FingerprintStyle { + /// The fingerprint is actually a DefPathHash. + DefPathHash, + /// Query key was `()` or equivalent, so fingerprint is just zero. + Unit, + /// Some opaque hash. + Opaque, +} + +impl FingerprintStyle { + #[inline] + pub fn reconstructible(self) -> bool { + match self { + FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true, + FingerprintStyle::Opaque => false, + } + } +} + /// Describe the different families of dependency nodes. pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static { const NULL: Self; @@ -73,5 +94,5 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> where OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>); - fn can_reconstruct_query_key(&self) -> bool; + fn fingerprint_style(&self) -> FingerprintStyle; } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3534c324295..07d72059975 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -26,24 +26,15 @@ use std::hash::{Hash, Hasher}; use std::mem; use std::num::NonZeroU32; use std::ptr; -#[cfg(debug_assertions)] -use std::sync::atomic::{AtomicUsize, Ordering}; pub struct QueryCacheStore<C: QueryCache> { cache: C, shards: Sharded<C::Sharded>, - #[cfg(debug_assertions)] - pub cache_hits: AtomicUsize, } impl<C: QueryCache + Default> Default for QueryCacheStore<C> { fn default() -> Self { - Self { - cache: C::default(), - shards: Default::default(), - #[cfg(debug_assertions)] - cache_hits: AtomicUsize::new(0), - } + Self { cache: C::default(), shards: Default::default() } } } @@ -377,10 +368,6 @@ where if unlikely!(tcx.profiler().enabled()) { tcx.profiler().query_cache_hit(index.into()); } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } tcx.dep_graph().read_index(index); on_hit(value) }) @@ -429,10 +416,6 @@ where if unlikely!(tcx.dep_context().profiler().enabled()) { tcx.dep_context().profiler().query_cache_hit(index.into()); } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } query_blocked_prof_timer.finish_with_query_invocation_id(index.into()); (v, Some(index)) @@ -540,7 +523,7 @@ where // We always expect to find a cached result for things that // can be forced from `DepNode`. debug_assert!( - !dep_node.kind.can_reconstruct_query_key() || result.is_some(), + !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(), "missing on-disk cache entry for {:?}", dep_node ); @@ -705,10 +688,6 @@ where if unlikely!(tcx.dep_context().profiler().enabled()) { tcx.dep_context().profiler().query_cache_hit(index.into()); } - #[cfg(debug_assertions)] - { - cache.cache_hits.fetch_add(1, Ordering::Relaxed); - } }); let lookup = match cached { @@ -778,7 +757,7 @@ where return false; } - if !<Q::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() { + if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() { return false; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9be568b2cf1..515b2c3fd27 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -9,7 +9,6 @@ use crate::{BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak}; use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding}; -use rustc_ast::unwrap_or; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::ptr_key::PtrKey; @@ -349,10 +348,10 @@ impl<'a> Resolver<'a> { if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { continue; } - let module = unwrap_or!( - single_import.imported_module.get(), - return Err((Undetermined, Weak::No)) - ); + let module = match single_import.imported_module.get() { + Some(x) => x, + None => return Err((Undetermined, Weak::No)), + }; let ident = match single_import.kind { ImportKind::Single { source, .. } => source, _ => unreachable!(), diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index e32e4493726..6671c7c0fa6 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -500,8 +500,8 @@ impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] { d.read_seq(|d, len| { assert!(len == N); let mut v = [0u8; N]; - for i in 0..len { - v[i] = d.read_seq_elt(|d| Decodable::decode(d))?; + for x in &mut v { + *x = d.read_seq_elt(|d| Decodable::decode(d))?; } Ok(v) }) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0e30e154ee5..6c889e88a59 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -816,6 +816,7 @@ symbols! { mem_size_of, mem_size_of_val, mem_uninitialized, + mem_variant_count, mem_zeroed, member_constraints, memory, @@ -893,6 +894,7 @@ symbols! { nomem, non_ascii_idents, non_exhaustive, + non_exhaustive_omitted_patterns_lint, non_modrs_mods, none_error, nontemporal_store, diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs new file mode 100644 index 00000000000..d230f77bde2 --- /dev/null +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs @@ -0,0 +1,24 @@ +use crate::spec::{Target, TargetOptions}; + +// This target is for uclibc Linux on ARMv7 without NEON or +// thumb-mode. See the thumbv7neon variant for enabling both. + +pub fn target() -> Target { + let base = super::linux_uclibc_base::opts(); + Target { + llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + + options: TargetOptions { + // Info about features at https://wiki.debian.org/ArmHardFloatPort + features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(), + cpu: "generic".to_string(), + max_atomic_width: Some(64), + mcount: "_mcount".to_string(), + abi: "eabihf".to_string(), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5276da1ba5a..ff5dfa3f746 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -952,6 +952,8 @@ supported_targets! { ("bpfel-unknown-none", bpfel_unknown_none), ("armv6k-nintendo-3ds", armv6k_nintendo_3ds), + + ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf), } /// Warnings encountered when parsing the target `json`. diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 25ec9682d84..1193d10d6a7 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -278,14 +278,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); - if self.is_poly == false { + if !self.is_poly { visit::walk_expr(self, expr) } } fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); - if self.is_poly == false { + if !self.is_poly { visit::walk_pat(self, pat); } } @@ -298,7 +298,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; visit::walk_expr(&mut is_poly_vis, &body[body_id]); debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); - if is_poly_vis.is_poly == false { + if !is_poly_vis.is_poly { return Ok(None); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a73d2285d45..1a8f863952e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -704,7 +704,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) .collect(); - never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::Send).unwrap()); + if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { + never_suggest_borrow.push(def_id); + } let param_env = obligation.param_env; let trait_ref = poly_trait_ref.skip_binder(); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 31254a0534d..2fa6c0c0259 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -83,10 +83,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ) -> EvaluationResult { match self.evaluate_obligation(obligation) { Ok(result) => result, - Err(OverflowError::Cannonical) => { + Err(OverflowError::Canonical) => { let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r { - OverflowError::Cannonical => { + OverflowError::Canonical => { span_bug!( obligation.cause.span, "Overflow should be caught earlier in standard query mode: {:?}, {:?}", diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d68ae079077..0f6e2e0be52 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -161,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } Ok(_) => Ok(None), - Err(OverflowError::Cannonical) => Err(Overflow), + Err(OverflowError::Canonical) => Err(Overflow), Err(OverflowError::ErrorReporting) => Err(ErrorReporting), }) .flat_map(Result::transpose) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3818e75a1de..85502a399de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -900,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow) => Err(OverflowError::Cannonical), + Err(Overflow) => Err(OverflowError::Canonical), Err(ErrorReporting) => Err(OverflowError::ErrorReporting), Err(..) => Ok(EvaluatedToErr), } @@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.report_overflow_error(error_obligation, true); } TraitQueryMode::Canonical => { - return Err(OverflowError::Cannonical); + return Err(OverflowError::Canonical); } } } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 1d4196e5747..e24f699adf6 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -892,7 +892,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { ty::BoundRegionKind::BrNamed(def_id, _name) => { - if self.named_parameters.iter().find(|d| **d == def_id).is_none() { + if !self.named_parameters.iter().any(|d| *d == def_id) { self.named_parameters.push(def_id); } } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 4ffb061f7b4..51bbcbebcdc 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -329,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let obligation = Obligation::new( ObligationCause::dummy_with_span(callee_expr.span), self.param_env, - predicate.clone(), + *predicate, ); let result = self.infcx.evaluate_obligation(&obligation); self.tcx diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 51c766fe57c..78849b276d6 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -431,7 +431,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .sess .source_map() .span_to_snippet(self.expr.span) - .map_or(false, |snip| snip.starts_with("(")); + .map_or(false, |snip| snip.starts_with('(')); // Very crude check to see whether the expression must be wrapped // in parentheses for the suggestion to work (issue #89497). diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 676e751376a..3846aad2cfc 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1887,7 +1887,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let expr_snippet = self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); - let is_wrapped = expr_snippet.starts_with("(") && expr_snippet.ends_with(")"); + let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')'); let after_open = expr.span.lo() + rustc_span::BytePos(1); let before_close = expr.span.hi() - rustc_span::BytePos(1); diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 44d6f076f5d..6eeb28e32f1 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -753,17 +753,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); let impl_ty = impl_ty.subst(self.tcx, impl_substs); + debug!("impl_ty: {:?}", impl_ty); + // Determine the receiver type that the method itself expects. - let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs); + let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs); + debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); // We can't use normalize_associated_types_in as it will pollute the // fcx's fulfillment context after this probe is over. + // Note: we only normalize `xform_self_ty` here since the normalization + // of the return type can lead to inference results that prohibit + // valid canidates from being found, see issue #85671 + // FIXME Postponing the normalization of the return type likely only hides a deeper bug, + // which might be caused by the `param_env` itself. The clauses of the `param_env` + // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, + // see isssue #89650 let cause = traits::ObligationCause::misc(self.span, self.body_id); let selcx = &mut traits::SelectionContext::new(self.fcx); - let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } = - traits::normalize(selcx, self.param_env, cause, xform_tys); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, self.param_env, cause, xform_self_ty); debug!( - "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}", + "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}", xform_self_ty, xform_ret_ty ); @@ -1420,6 +1430,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let mut result = ProbeResult::Match; + let mut xform_ret_ty = probe.xform_ret_ty; + debug!(?xform_ret_ty); + let selcx = &mut traits::SelectionContext::new(self); let cause = traits::ObligationCause::misc(self.span, self.body_id); @@ -1428,7 +1441,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(substs, ref ref_obligations) => { + InherentImplCandidate(ref substs, ref ref_obligations) => { + // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, + // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` + // for why this is necessary + let traits::Normalized { + value: normalized_xform_ret_ty, + obligations: normalization_obligations, + } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty); + xform_ret_ty = normalized_xform_ret_ty; + debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); + // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container.id(); let impl_bounds = self.tcx.predicates_of(impl_def_id); @@ -1442,7 +1465,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let candidate_obligations = impl_obligations .chain(norm_obligations.into_iter()) - .chain(ref_obligations.iter().cloned()); + .chain(ref_obligations.iter().cloned()) + .chain(normalization_obligations.into_iter()); + // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { let o = self.resolve_vars_if_possible(o); @@ -1527,9 +1552,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } if let ProbeResult::Match = result { - if let (Some(return_ty), Some(xform_ret_ty)) = - (self.return_type, probe.xform_ret_ty) - { + if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) { let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty); debug!( "comparing return_ty {:?} with xform ret ty {:?}", @@ -1669,6 +1692,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.static_candidates.push(source); } + #[instrument(level = "debug", skip(self))] fn xform_self_ty( &self, item: &ty::AssocItem, @@ -1683,9 +1707,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { let fn_sig = self.tcx.fn_sig(method); - debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs); + debug!(?fn_sig); assert!(!substs.has_escaping_bound_vars()); diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 693246a3433..79443010fbb 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { } hir::ExprKind::Match(ref discr, arms, _) => { - self.link_match(discr, &arms[..]); + self.link_match(discr, arms); intravisit::walk_expr(self, expr); } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index b7c042a08cf..3a10988bba0 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -65,6 +65,7 @@ use std::iter; enum PlaceAncestryRelation { Ancestor, Descendant, + SamePlace, Divergent, } @@ -564,7 +565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for possible_ancestor in min_cap_list.iter_mut() { match determine_place_ancestry_relation(&place, &possible_ancestor.place) { // current place is descendant of possible_ancestor - PlaceAncestryRelation::Descendant => { + PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => { ancestor_found = true; let backup_path_expr_id = possible_ancestor.info.path_expr_id; @@ -2278,15 +2279,17 @@ fn determine_place_ancestry_relation( let projections_b = &place_b.projections; let same_initial_projections = - iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a == proj_b); + iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a.kind == proj_b.kind); if same_initial_projections { + use std::cmp::Ordering; + // First min(n, m) projections are the same // Select Ancestor/Descendant - if projections_b.len() >= projections_a.len() { - PlaceAncestryRelation::Ancestor - } else { - PlaceAncestryRelation::Descendant + match projections_b.len().cmp(&projections_a.len()) { + Ordering::Greater => PlaceAncestryRelation::Ancestor, + Ordering::Equal => PlaceAncestryRelation::SamePlace, + Ordering::Less => PlaceAncestryRelation::Descendant, } } else { PlaceAncestryRelation::Divergent diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index b5eb74f708d..0373035a09a 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -3,6 +3,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_index::vec::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; use rustc_trait_selection::traits::{self, SkipLeakCheck}; @@ -158,14 +159,18 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { // This is advantageous to running the algorithm over the // entire graph when there are many connected regions. + rustc_index::newtype_index! { + pub struct RegionId { + ENCODABLE = custom + } + } struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, impl_blocks: FxHashSet<usize>, } - // Highest connected region id - let mut highest_region_id = 0; + let mut connected_regions: IndexVec<RegionId, _> = Default::default(); + // Reverse map from the Symbol to the connected region id. let mut connected_region_ids = FxHashMap::default(); - let mut connected_regions = FxHashMap::default(); for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { if impl_items.len() == 0 { @@ -173,7 +178,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { } // First obtain a list of existing connected region ids let mut idents_to_add = SmallVec::<[Symbol; 8]>::new(); - let ids = impl_items + let mut ids = impl_items .in_definition_order() .filter_map(|item| { let entry = connected_region_ids.entry(item.ident.name); @@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { None } }) - .collect::<FxHashSet<usize>>(); - match ids.len() { - 0 | 1 => { - let id_to_set = if ids.is_empty() { - // Create a new connected region - let region = ConnectedRegion { + .collect::<SmallVec<[RegionId; 8]>>(); + // Sort the id list so that the algorithm is deterministic + ids.sort_unstable(); + let ids = ids; + match &ids[..] { + // Create a new connected region + [] => { + let id_to_set = connected_regions.next_index(); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + connected_regions.insert( + id_to_set, + ConnectedRegion { idents: idents_to_add, impl_blocks: std::iter::once(i).collect(), - }; - connected_regions.insert(highest_region_id, region); - (highest_region_id, highest_region_id += 1).0 - } else { - // Take the only id inside the list - let id_to_set = *ids.iter().next().unwrap(); - let region = connected_regions.get_mut(&id_to_set).unwrap(); - region.impl_blocks.insert(i); - region.idents.extend_from_slice(&idents_to_add); - id_to_set - }; - let (_id, region) = connected_regions.iter().next().unwrap(); + }, + ); + } + // Take the only id inside the list + &[id_to_set] => { + let region = connected_regions[id_to_set].as_mut().unwrap(); + region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); // Update the connected region ids - for ident in region.idents.iter() { + for ident in &idents_to_add { connected_region_ids.insert(*ident, id_to_set); } } - _ => { - // We have multiple connected regions to merge. - // In the worst case this might add impl blocks - // one by one and can thus be O(n^2) in the size - // of the resulting final connected region, but - // this is no issue as the final step to check - // for overlaps runs in O(n^2) as well. - - // Take the smallest id from the list - let id_to_set = *ids.iter().min().unwrap(); - - // Sort the id list so that the algorithm is deterministic - let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>(); - ids.sort_unstable(); - - let mut region = connected_regions.remove(&id_to_set).unwrap(); - region.idents.extend_from_slice(&idents_to_add); + // We have multiple connected regions to merge. + // In the worst case this might add impl blocks + // one by one and can thus be O(n^2) in the size + // of the resulting final connected region, but + // this is no issue as the final step to check + // for overlaps runs in O(n^2) as well. + &[id_to_set, ..] => { + let mut region = connected_regions.remove(id_to_set).unwrap(); region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + // Remove other regions from ids. for &id in ids.iter() { if id == id_to_set { continue; } - let r = connected_regions.remove(&id).unwrap(); - // Update the connected region ids + let r = connected_regions.remove(id).unwrap(); for ident in r.idents.iter() { connected_region_ids.insert(*ident, id_to_set); } region.idents.extend_from_slice(&r.idents); region.impl_blocks.extend(r.impl_blocks); } + connected_regions.insert(id_to_set, region); } } @@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { let avg = impls.len() / connected_regions.len(); let s = connected_regions .iter() - .map(|r| r.1.impl_blocks.len() as isize - avg as isize) + .flatten() + .map(|r| r.impl_blocks.len() as isize - avg as isize) .map(|v| v.abs() as usize) .sum::<usize>(); s / connected_regions.len() }, - connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap() + connected_regions + .iter() + .flatten() + .map(|r| r.impl_blocks.len()) + .max() + .unwrap() ); // List of connected regions is built. Now, run the overlap check // for each pair of impl blocks in the same connected region. - for (_id, region) in connected_regions.into_iter() { + for region in connected_regions.into_iter().flatten() { let mut impl_blocks = region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>(); impl_blocks.sort_unstable(); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 65eedd2daaf..971776c882a 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -63,6 +63,7 @@ This API is completely unstable and subject to change. #![feature(in_band_lifetimes)] #![feature(is_sorted)] #![feature(iter_zip)] +#![feature(min_specialization)] #![feature(nll)] #![feature(try_blocks)] #![feature(never_type)] |
