diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm_util.rs | 75 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/place.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 33 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/print/pretty.rs | 109 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/generator.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/lifetimes.rs | 193 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/coercion.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs | 8 |
13 files changed, 385 insertions, 144 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 70f78c07c65..54a8249b175 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2128,7 +2128,13 @@ extern "C" { pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine); - pub fn LLVMRustPrintTargetFeatures(T: &TargetMachine); + pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t; + pub fn LLVMRustGetTargetFeature( + T: &TargetMachine, + Index: size_t, + Feature: &mut *const c_char, + Desc: &mut *const c_char, + ); pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char; pub fn LLVMRustCreateTargetMachine( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e80de2bc902..b44553e4f6d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -10,6 +10,7 @@ use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use std::ffi::{CStr, CString}; +use std::ptr; use std::slice; use std::str; use std::sync::atomic::{AtomicBool, Ordering}; @@ -192,15 +193,77 @@ pub fn print_passes() { } } +fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { + let len = unsafe { llvm::LLVMRustGetTargetFeaturesCount(tm) }; + let mut ret = Vec::with_capacity(len); + for i in 0..len { + unsafe { + let mut feature = ptr::null(); + let mut desc = ptr::null(); + llvm::LLVMRustGetTargetFeature(tm, i, &mut feature, &mut desc); + if feature.is_null() || desc.is_null() { + bug!("LLVM returned a `null` target feature string"); + } + let feature = CStr::from_ptr(feature).to_str().unwrap_or_else(|e| { + bug!("LLVM returned a non-utf8 feature string: {}", e); + }); + let desc = CStr::from_ptr(desc).to_str().unwrap_or_else(|e| { + bug!("LLVM returned a non-utf8 feature string: {}", e); + }); + ret.push((feature, desc)); + } + } + ret +} + +fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { + let mut target_features = llvm_target_features(tm); + let mut rustc_target_features = supported_target_features(sess) + .iter() + .filter_map(|(feature, _gate)| { + let llvm_feature = to_llvm_feature(sess, *feature); + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| { + let (_f, desc) = target_features.remove(index); + (*feature, desc) + }) + }) + .collect::<Vec<_>>(); + rustc_target_features.extend_from_slice(&[( + "crt-static", + "Enables C Run-time Libraries to be statically linked", + )]); + let max_feature_len = target_features + .iter() + .chain(rustc_target_features.iter()) + .map(|(feature, _desc)| feature.len()) + .max() + .unwrap_or(0); + + println!("Features supported by rustc for this target:"); + for (feature, desc) in &rustc_target_features { + println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + } + println!("\nCode-generation features supported by LLVM for this target:"); + for (feature, desc) in &target_features { + println!(" {1:0$} - {2}.", max_feature_len, feature, desc); + } + if target_features.len() == 0 { + println!(" Target features listing is not supported by this LLVM version."); + } + println!("\nUse +feature to enable a feature, or -feature to disable it."); + println!("For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); + println!("Code-generation features cannot be used in cfg or #[target_feature],"); + println!("and may be renamed or removed in a future version of LLVM or rustc.\n"); +} + pub(crate) fn print(req: PrintRequest, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); - unsafe { - match req { - PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), - PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm), - _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), - } + match req { + PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) }, + PrintRequest::TargetFeatures => print_target_features(sess, tm), + _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index a3f20abc82d..6bb20545f07 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -265,33 +265,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => continue, }; - let mut layout = base.layout; let mut direct_offset = Size::ZERO; // FIXME(eddyb) use smallvec here. let mut indirect_offsets = vec![]; + let mut place = base; for elem in &var.projection[..] { match *elem { mir::ProjectionElem::Deref => { indirect_offsets.push(Size::ZERO); - layout = bx.cx().layout_of( - layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| { - span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty) - }) - .ty, - ); + place = place.project_deref(bx); } mir::ProjectionElem::Field(field, _) => { let i = field.index(); let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); - *offset += layout.fields.offset(i); - layout = layout.field(bx.cx(), i); + *offset += place.layout.fields.offset(i); + place = place.project_field(bx, i); } mir::ProjectionElem::Downcast(_, variant) => { - layout = layout.for_variant(bx.cx(), variant); + place = place.project_downcast(bx, variant); } _ => span_bug!( var.source_info.span, @@ -301,7 +293,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); + // When targeting MSVC, create extra allocas for arguments instead of pointing multiple + // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records + // not DWARF and LLVM doesn't support translating the resulting + // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. + // Creating extra allocas on the stack makes the resulting debug info simple enough + // that LLVM can generate correct CodeView records and thus the values appear in the + // debugger. (#83709) + let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc + && self.mir.local_kind(local) == mir::LocalKind::Arg + // LLVM can handle simple things but anything more complex than just a direct + // offset or one indirect offset of 0 is too complex for it to generate CV records + // correctly. + && (direct_offset != Size::ZERO + || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); + + if should_create_individual_allocas { + // Create a variable which will be a pointer to the actual value + let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut { + mutbl: mir::Mutability::Mut, + ty: place.layout.ty, + })); + let ptr_layout = bx.layout_of(ptr_ty); + let alloca = PlaceRef::alloca(bx, ptr_layout); + bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); + + // Write the pointer to the variable + bx.store(place.llval, alloca.llval, alloca.align); + + // Point the debug info to `*alloca` for the current variable + bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]); + } else { + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 66d9d1a1e0c..a9e7ebf6d43 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -402,6 +402,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { downcast } + pub fn project_deref<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) -> Self { + let target_ty = self.layout.ty.builtin_deref(true).expect("failed to deref"); + let layout = bx.layout_of(target_ty.ty); + + PlaceRef { + llval: bx.load(self.llval, self.align), + llextra: None, + layout, + align: layout.align.abi, + } + } + pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { bx.lifetime_start(self.llval, self.layout.size); } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b8d5b50dcb5..617b2ed970e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -404,26 +404,21 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) { printf("\n"); } -extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { +extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { const TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable(); - unsigned MaxFeatLen = getLongestEntryLength(FeatTable); - - printf("Available features for this target:\n"); - for (auto &Feature : FeatTable) - printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); - printf("\nRust-specific features:\n"); - printf(" %-*s - %s.\n", - MaxFeatLen, - "crt-static", - "Enables libraries with C Run-time Libraries(CRT) to be statically linked" - ); - printf("\n"); + return FeatTable.size(); +} - printf("Use +feature to enable a feature, or -feature to disable it.\n" - "For example, rustc -C -target-cpu=mycpu -C " - "target-feature=+feature1,-feature2\n\n"); +extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, + const char** Feature, const char** Desc) { + const TargetMachine *Target = unwrap(TM); + const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); + const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable(); + const SubtargetFeatureKV Feat = FeatTable[Index]; + *Feature = Feat.Key; + *Desc = Feat.Desc; } #else @@ -432,9 +427,11 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) { printf("Target CPU help is not supported by this LLVM version.\n\n"); } -extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) { - printf("Target features help is not supported by this LLVM version.\n\n"); +extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) { + return 0; } + +extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {} #endif extern "C" const char* LLVMRustGetHostCPUName(size_t *len) { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f697cd51930..1989c91a879 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1804,29 +1804,94 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { define_scoped_cx!(self); let mut region_index = self.region_index; - let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { - let _ = start_or_continue(&mut self, "for<", ", "); - let kind = match br.kind { - ty::BrNamed(_, name) => { - let _ = write!(self, "{}", name); - br.kind - } - ty::BrAnon(_) | ty::BrEnv => { - let name = loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !self.used_region_names.contains(&name) { - break name; - } - }; - let _ = write!(self, "{}", name); - ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) + // If we want to print verbosly, then print *all* binders, even if they + // aren't named. Eventually, we might just want this as the default, but + // this is not *quite* right and changes the ordering of some output + // anyways. + let new_value = if self.tcx().sess.verbose() { + // anon index + 1 (BrEnv takes 0) -> name + let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default(); + let bound_vars = value.bound_vars(); + for var in bound_vars { + match var { + ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => { + let _ = start_or_continue(&mut self, "for<", ", "); + let _ = write!(self, "{}", name); + } + ty::BoundVariableKind::Region(ty::BrAnon(i)) => { + let _ = start_or_continue(&mut self, "for<", ", "); + let name = loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !self.used_region_names.contains(&name) { + break name; + } + }; + let _ = write!(self, "{}", name); + region_map.insert(i + 1, name); + } + ty::BoundVariableKind::Region(ty::BrEnv) => { + let _ = start_or_continue(&mut self, "for<", ", "); + let name = loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !self.used_region_names.contains(&name) { + break name; + } + }; + let _ = write!(self, "{}", name); + region_map.insert(0, name); + } + _ => continue, } - }; - self.tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind })) - }); - start_or_continue(&mut self, "", "> ")?; + } + start_or_continue(&mut self, "", "> ")?; + + self.tcx.replace_late_bound_regions(value.clone(), |br| { + let kind = match br.kind { + ty::BrNamed(_, _) => br.kind, + ty::BrAnon(i) => { + let name = region_map[&(i + 1)]; + ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) + } + ty::BrEnv => { + let name = region_map[&0]; + ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) + } + }; + self.tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + )) + }) + } else { + let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { + let _ = start_or_continue(&mut self, "for<", ", "); + let kind = match br.kind { + ty::BrNamed(_, name) => { + let _ = write!(self, "{}", name); + br.kind + } + ty::BrAnon(_) | ty::BrEnv => { + let name = loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !self.used_region_names.contains(&name) { + break name; + } + }; + let _ = write!(self, "{}", name); + ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) + } + }; + self.tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + )) + }); + start_or_continue(&mut self, "", "> ")?; + new_value + }; self.binder_depth += 1; self.region_index = region_index; diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index c85e9b9b932..003003a8abb 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -751,9 +751,10 @@ fn sanitize_witness<'tcx>( span_bug!( body.span, "Broken MIR: generator contains type {} in MIR, \ - but typeck only knows about {}", - decl.ty, - witness, + but typeck only knows about {} and {:?}", + decl_ty, + allowed, + allowed_upvars ); } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 748a8e2bb49..2fa25e40c6b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -703,6 +703,8 @@ impl<'a> Parser<'a> { let mut recovered = false; let mut trailing = false; let mut v = vec![]; + let unclosed_delims = !self.unclosed_delims.is_empty(); + while !self.expect_any_with_type(kets, expect) { if let token::CloseDelim(..) | token::Eof = self.token.kind { break; @@ -723,7 +725,7 @@ impl<'a> Parser<'a> { // Attempt to keep parsing if it was a similar separator. if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token.kind) { + if tokens.contains(&self.token.kind) && !unclosed_delims { self.bump(); } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index b89ad867f46..91bc8ab5ef4 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -72,8 +72,8 @@ impl RegionExt for Region { let def_id = hir_map.local_def_id(param.hir_id); let origin = LifetimeDefOrigin::from_param(param); debug!( - "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", - param, depth, def_id, origin, + "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}", + idx, param, depth, def_id, origin, ); ( param.name.normalize_to_macros_2_0(), @@ -326,6 +326,10 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + TraitRefBoundary { + s: ScopeRef<'a>, + }, + Root, } @@ -374,6 +378,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("lifetimes", lifetimes) .field("s", &"..") .finish(), + Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), Scope::Root => f.debug_struct("Root").finish(), } } @@ -877,9 +882,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } hir::TyKind::TraitObject(bounds, ref lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } + let scope = Scope::TraitRefBoundary { s: self.scope }; + self.with(scope, |_, this| { + for bound in bounds { + this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + }); match lifetime.name { LifetimeName::Implicit => { // For types like `dyn Foo`, we should @@ -1058,9 +1066,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; this.with(scope, |_old_scope, this| { this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |_, this| { + for bound in bounds { + this.visit_param_bound(bound); + } + }) }); }); } else { @@ -1074,10 +1085,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { from_poly_trait_ref: false, }; self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |_, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }) }); } } @@ -1131,13 +1145,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - if let Some(ty) = ty { - this.visit_ty(ty); - } + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |_, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + if let Some(ty) = ty { + this.visit_ty(ty); + } + }) }); self.missing_named_lifetime_spots.pop(); } @@ -1197,8 +1214,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); - this.visit_generics(generics); - this.visit_ty(ty); + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |_, this| { + this.visit_generics(generics); + this.visit_ty(ty); + }) }); self.missing_named_lifetime_spots.pop(); } @@ -1292,29 +1312,31 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .unzip(); self.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); - if !lifetimes.is_empty() { - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - hir_id: bounded_ty.hir_id, - lifetimes, - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - from_poly_trait_ref: true, - }; - let result = self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &bound_generic_params); + let scope = Scope::TraitRefBoundary { s: self.scope }; + self.with(scope, |_, this| { + if !lifetimes.is_empty() { + let next_early_index = this.next_early_index(); + let scope = Scope::Binder { + hir_id: bounded_ty.hir_id, + lifetimes, + s: this.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + from_poly_trait_ref: true, + }; + this.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &bound_generic_params); + this.visit_ty(&bounded_ty); + this.trait_ref_hack = Some(bounded_ty.hir_id); + walk_list!(this, visit_param_bound, bounds); + this.trait_ref_hack = None; + }) + } else { this.visit_ty(&bounded_ty); - this.trait_ref_hack = Some(bounded_ty.hir_id); walk_list!(this, visit_param_bound, bounds); - this.trait_ref_hack = None; - }); - result - } else { - self.visit_ty(&bounded_ty); - walk_list!(self, visit_param_bound, bounds); - } + } + }) } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { ref lifetime, @@ -1438,6 +1460,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope = s; } + Scope::TraitRefBoundary { .. } => { + // We should only see super trait lifetimes if there is a `Binder` above + assert!(supertrait_lifetimes.is_empty()); + break vec![]; + } + Scope::Binder { hir_id, from_poly_trait_ref, .. } => { if !from_poly_trait_ref { // We should only see super trait lifetimes if there is a `Binder` above @@ -1653,7 +1681,8 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::TraitRefHackInner { s, .. } - | Scope::Supertrait { s, .. } => { + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => { scope = s; } @@ -2261,7 +2290,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::TraitRefHackInner { s, .. } - | Scope::Supertrait { s, .. } => scope = s, + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => scope = s, } } } @@ -2311,6 +2341,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break None; } + Scope::TraitRefBoundary { s, .. } => { + // We've exited nested poly trait refs; mark that we are no longer in nested trait refs. + // We don't increase the late depth because this isn't a `Binder` scope. + // + // This came up in #83737, which boiled down to a case like this: + // + // ``` + // F: for<> Fn(&()) -> Box<dyn for<> Future<Output = ()> + Unpin>, + // // ^^^^^ + + // ``` + // + // Here, as we traverse upwards from the `dyn for<>` binder, we want to reset `in_poly_trait_ref` + // to false, so that we avoid excess contaenation when we encounter the outer `for<>` binder. + in_poly_trait_ref = false; + scope = s; + } + Scope::Binder { ref lifetimes, from_poly_trait_ref, s, .. } => { match lifetime_ref.name { LifetimeName::Param(param_name) => { @@ -2332,6 +2380,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // We've already seen a binder that is a poly trait ref and this one is too, // that means that they are nested and we are concatenating the bound vars; // don't increase the late depth. + // + // This happens specifically with associated trait bounds like the following: + // + // ``` + // for<'a> T: Iterator<Item: for<'b> Foo<'a, 'b>> + // ``` + // + // In this case, as we traverse `for<'b>`, we would increment `late_depth` but + // set `in_poly_trait_ref` to true. Then when we traverse `for<'a>`, we would + // not increment `late_depth` again. (NB: Niko thinks this logic is actually + // wrong.) (true, true) => {} // We've exited nested poly trait refs; add one to the late depth and mark // that we are no longer in nested trait refs @@ -2504,7 +2563,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::TraitRefHackInner { s, .. } - | Scope::Supertrait { s, .. } => { + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => { scope = s; } } @@ -2700,7 +2760,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Body { id, .. } => break id.hir_id, Scope::ObjectLifetimeDefault { ref s, .. } | Scope::Elision { ref s, .. } - | Scope::Supertrait { ref s, .. } => { + | Scope::Supertrait { ref s, .. } + | Scope::TraitRefBoundary { ref s, .. } => { scope = *s; } Scope::Root => bug!("In fn_like_elision without appropriate scope above"), @@ -2982,6 +3043,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.have_bound_regions = true; } _ => { + // FIXME(jackh726): nested trait refs? self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); } } @@ -3047,6 +3109,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Root => break None, + Scope::TraitRefBoundary { s, .. } => { + // We've exited nested poly trait refs; mark that we are no longer in nested trait refs. + // We don't increase the late depth because this isn't a `Binder` scope + in_poly_trait_ref = false; + scope = s; + } + Scope::Binder { s, ref lifetimes, from_poly_trait_ref, .. } => { // collect named lifetimes for suggestions for name in lifetimes.keys() { @@ -3100,7 +3169,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope = s; } Scope::ObjectLifetimeDefault { ref s, .. } - | Scope::Elision { ref s, .. } => { + | Scope::Elision { ref s, .. } + | Scope::TraitRefBoundary { ref s, .. } => { scope = s; } _ => break, @@ -3228,6 +3298,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut scope = self.scope; let lifetime = loop { match *scope { + Scope::TraitRefBoundary { s, .. } => { + // We've exited nested poly trait refs; mark that we are no longer in nested trait refs. + // We don't increase the late depth because this isn't a `Binder` scope + in_poly_trait_ref = false; + scope = s; + } + Scope::Binder { s, from_poly_trait_ref, .. } => { match (from_poly_trait_ref, in_poly_trait_ref) { (true, false) => { @@ -3380,7 +3457,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::TraitRefHackInner { s, .. } - | Scope::Supertrait { s, .. } => { + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => { old_scope = s; } @@ -3438,7 +3516,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::ObjectLifetimeDefault { s, .. } | Scope::TraitRefHackInner { s, .. } - | Scope::Supertrait { s, .. } => scope = s, + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => scope = s, } } } @@ -3492,13 +3571,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "Constrained" basically means that it appears in any type but /// not amongst the inputs to a projection. In other words, `<&'a /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. +#[tracing::instrument(level = "debug", skip(map))] fn insert_late_bound_lifetimes( map: &mut NamedRegionMap, decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>, ) { - debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); - let mut constrained_by_input = ConstrainedCollector::default(); for arg_ty in decl.inputs { constrained_by_input.visit_ty(arg_ty); @@ -3507,7 +3585,7 @@ fn insert_late_bound_lifetimes( let mut appears_in_output = AllCollector::default(); intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); - debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions); + debug!(?constrained_by_input.regions); // Walk the lifetimes that appear in where clauses. // @@ -3527,10 +3605,7 @@ fn insert_late_bound_lifetimes( } } - debug!( - "insert_late_bound_lifetimes: appears_in_where_clause={:?}", - appears_in_where_clause.regions - ); + debug!(?appears_in_where_clause.regions); // Late bound regions are those that: // - appear in the inputs @@ -3557,11 +3632,7 @@ fn insert_late_bound_lifetimes( continue; } - debug!( - "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", - param.name.ident(), - param.hir_id - ); + debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); let inserted = map.late_bound.insert(param.hir_id); assert!(inserted, "visited lifetime {:?} twice", param.hir_id); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 75bd8880b34..b6b349e4a80 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -18,7 +18,7 @@ use rustc_serialize::json; use crate::parse::CrateConfig; use rustc_feature::UnstableFeatures; -use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST}; +use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::{FileName, FilePathMapping}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::SourceFileHashAlgorithm; @@ -1320,13 +1320,16 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { }; if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { - early_error( - ErrorOutputType::default(), - &format!( - "edition {} is unstable and only available with -Z unstable-options.", - edition, - ), - ) + let is_nightly = nightly_options::match_is_nightly_build(matches); + let msg = if !is_nightly { + format!( + "the crate requires edition {}, but the latest edition supported by this Rust version is {}", + edition, LATEST_STABLE_EDITION + ) + } else { + format!("edition {} is unstable and only available with -Z unstable-options", edition) + }; + early_error(ErrorOutputType::default(), &msg) } edition diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 68a923a55eb..37538267b86 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1440,9 +1440,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // as prior return coercions would not be relevant (#57664). let parent_id = fcx.tcx.hir().get_parent_node(id); let fn_decl = if let Some((expr, blk_id)) = expression { - pointing_at_return_type = fcx.suggest_mismatched_types_on_tail( - &mut err, expr, expected, found, cause.span, blk_id, - ); + pointing_at_return_type = + fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); let parent = fcx.tcx.hir().get(parent_id); if let (Some(cond_expr), true, false) = ( fcx.tcx.hir().get_if_cause(expr.hir_id), diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 60c40da8f31..991c2ba693d 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, &mut |mut err| { self.suggest_mismatched_types_on_tail( - &mut err, expr, ty, e_ty, cause.span, target_id, + &mut err, expr, ty, e_ty, target_id, ); if let Some(val) = ty_kind_suggestion(ty) { let label = destination diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index c87a808243d..b7583344845 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -41,15 +41,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, - cause_span: Span, blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); // If the expression is from an external macro, then do not suggest // adding a semicolon, because there's nowhere to put it. // See issue #81943. - if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, cause_span) { - self.suggest_missing_semicolon(err, expr, expected, cause_span); + if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, expr.span) { + self.suggest_missing_semicolon(err, expr, expected); } let mut pointing_at_return_type = false; if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { @@ -389,7 +388,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, expression: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, - cause_span: Span, ) { if expected.is_unit() { // `BlockTailExpression` only relevant if the tail expr would be @@ -404,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if expression.can_have_side_effects() => { err.span_suggestion( - cause_span.shrink_to_hi(), + expression.span.shrink_to_hi(), "consider using a semicolon here", ";".to_string(), Applicability::MachineApplicable, |
