diff options
Diffstat (limited to 'compiler')
158 files changed, 2945 insertions, 2369 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6d5f47aceeb..e54fcaf6fc1 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -19,7 +19,6 @@ #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] -use rustc_data_structures::sync; use smallvec::SmallVec; use std::alloc::Layout; @@ -517,130 +516,12 @@ impl DroplessArena { } } -/// Calls the destructor for an object when dropped. -struct DropType { - drop_fn: unsafe fn(*mut u8), - obj: *mut u8, -} - -// SAFETY: we require `T: Send` before type-erasing into `DropType`. -#[cfg(parallel_compiler)] -unsafe impl sync::Send for DropType {} - -impl DropType { - #[inline] - unsafe fn new<T: sync::Send>(obj: *mut T) -> Self { - unsafe fn drop_for_type<T>(to_drop: *mut u8) { - std::ptr::drop_in_place(to_drop as *mut T) - } - - DropType { drop_fn: drop_for_type::<T>, obj: obj as *mut u8 } - } -} - -impl Drop for DropType { - fn drop(&mut self) { - unsafe { (self.drop_fn)(self.obj) } - } -} - -/// An arena which can be used to allocate any type. -/// -/// # Safety -/// -/// Allocating in this arena is unsafe since the type system -/// doesn't know which types it contains. In order to -/// allocate safely, you must store a `PhantomData<T>` -/// alongside this arena for each type `T` you allocate. -#[derive(Default)] -pub struct DropArena { - /// A list of destructors to run when the arena drops. - /// Ordered so `destructors` gets dropped before the arena - /// since its destructor can reference memory in the arena. - destructors: RefCell<Vec<DropType>>, - arena: DroplessArena, -} - -impl DropArena { - #[inline] - pub unsafe fn alloc<T>(&self, object: T) -> &mut T - where - T: sync::Send, - { - let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T; - // Write into uninitialized memory. - ptr::write(mem, object); - let result = &mut *mem; - // Record the destructor after doing the allocation as that may panic - // and would cause `object`'s destructor to run twice if it was recorded before. - self.destructors.borrow_mut().push(DropType::new(result)); - result - } - - #[inline] - pub unsafe fn alloc_from_iter<T, I>(&self, iter: I) -> &mut [T] - where - T: sync::Send, - I: IntoIterator<Item = T>, - { - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); - if vec.is_empty() { - return &mut []; - } - let len = vec.len(); - - let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T; - - let mut destructors = self.destructors.borrow_mut(); - // Reserve space for the destructors so we can't panic while adding them. - destructors.reserve(len); - - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec. - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - mem::forget(vec.drain(..)); - - // Record the destructors after doing the allocation as that may panic - // and would cause `object`'s destructor to run twice if it was recorded before. - for i in 0..len { - destructors.push(DropType::new(start_ptr.add(i))); - } - - slice::from_raw_parts_mut(start_ptr, len) - } -} - -pub macro arena_for_type { - ([][$ty:ty]) => { - $crate::TypedArena<$ty> - }, - ([few $(, $attrs:ident)*][$ty:ty]) => { - ::std::marker::PhantomData<$ty> - }, - ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { - $crate::arena_for_type!([$($attrs),*]$args) - }, -} - -pub macro which_arena_for_type { - ([][$arena:expr]) => { - ::std::option::Option::Some($arena) - }, - ([few$(, $attrs:ident)*][$arena:expr]) => { - ::std::option::Option::None - }, - ([$ignore:ident$(, $attrs:ident)*]$args:tt) => { - $crate::which_arena_for_type!([$($attrs),*]$args) - }, -} - #[rustc_macro_transparency = "semitransparent"] pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) { #[derive(Default)] pub struct Arena<$tcx> { pub dropless: $crate::DroplessArena, - drop: $crate::DropArena, - $($name: $crate::arena_for_type!($a[$ty]),)* + $($name: $crate::TypedArena<$ty>,)* } pub trait ArenaAllocatable<'tcx, T = Self>: Sized { @@ -670,13 +551,9 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) { #[inline] fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self { if !::std::mem::needs_drop::<Self>() { - return arena.dropless.alloc(self); - } - match $crate::which_arena_for_type!($a[&arena.$name]) { - ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => { - ty_arena.alloc(self) - } - ::std::option::Option::None => unsafe { arena.drop.alloc(self) }, + arena.dropless.alloc(self) + } else { + arena.$name.alloc(self) } } @@ -686,13 +563,9 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) { iter: impl ::std::iter::IntoIterator<Item = Self>, ) -> &'a mut [Self] { if !::std::mem::needs_drop::<Self>() { - return arena.dropless.alloc_from_iter(iter); - } - match $crate::which_arena_for_type!($a[&arena.$name]) { - ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => { - ty_arena.alloc_from_iter(iter) - } - ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) }, + arena.dropless.alloc_from_iter(iter) + } else { + arena.$name.alloc_from_iter(iter) } } } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f9e19d30fcc..abfe8360987 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2058,7 +2058,7 @@ pub struct InlineAsm { pub template: Vec<InlineAsmTemplatePiece>, pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>, pub operands: Vec<(InlineAsmOperand, Span)>, - pub clobber_abi: Option<(Symbol, Span)>, + pub clobber_abis: Vec<(Symbol, Span)>, pub options: InlineAsmOptions, pub line_spans: Vec<Span>, } @@ -2715,7 +2715,7 @@ pub enum ItemKind { /// E.g., `extern {}` or `extern "C" {}`. ForeignMod(ForeignMod), /// Module-level inline assembly (from `global_asm!()`). - GlobalAsm(InlineAsm), + GlobalAsm(Box<InlineAsm>), /// A type alias (`type`). /// /// E.g., `type Foo = Bar<u8>;`. diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index c40aec4b671..80a06fa5943 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -169,7 +169,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme if let Some(mut idx) = token_text.find('\n') { code_to_the_left = false; while let Some(next_newline) = &token_text[idx + 1..].find('\n') { - idx = idx + 1 + next_newline; + idx += 1 + next_newline; comments.push(Comment { style: CommentStyle::BlankLine, lines: vec![], diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 95997a37d84..cfa97ff84ec 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -2,6 +2,7 @@ use super::LoweringContext; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_session::parse::feature_err; @@ -49,22 +50,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } - let mut clobber_abi = None; + let mut clobber_abis = FxHashMap::default(); if let Some(asm_arch) = asm_arch { - if let Some((abi_name, abi_span)) = asm.clobber_abi { - match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) { - Ok(abi) => clobber_abi = Some((abi, abi_span)), + for (abi_name, abi_span) in &asm.clobber_abis { + match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) { + Ok(abi) => { + // If the abi was already in the list, emit an error + match clobber_abis.get(&abi) { + Some((prev_name, prev_sp)) => { + let mut err = self.sess.struct_span_err( + *abi_span, + &format!("`{}` ABI specified multiple times", prev_name), + ); + err.span_label(*prev_sp, "previously specified here"); + + // Multiple different abi names may actually be the same ABI + // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI + let source_map = self.sess.source_map(); + if source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span) + { + err.note("these ABIs are equivalent on the current target"); + } + + err.emit(); + } + None => { + clobber_abis.insert(abi, (abi_name, *abi_span)); + } + } + } Err(&[]) => { self.sess .struct_span_err( - abi_span, + *abi_span, "`clobber_abi` is not supported on this target", ) .emit(); } Err(supported_abis) => { let mut err = - self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`"); + self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); @@ -348,8 +374,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If a clobber_abi is specified, add the necessary clobbers to the // operands list. - if let Some((abi, abi_span)) = clobber_abi { + let mut clobbered = FxHashSet::default(); + for (abi, (_, abi_span)) in clobber_abis { for &clobber in abi.clobbered_regs() { + // Don't emit a clobber for a register already clobbered + if clobbered.contains(&clobber) { + continue; + } + let mut output_used = false; clobber.overlapping_regs(|reg| { if used_output_regs.contains_key(®) { @@ -366,6 +398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, self.lower_span(abi_span), )); + clobbered.insert(clobber); } } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index f45a79f026f..b011a2e8117 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -3,7 +3,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd, VariantData}; use rustc_errors::struct_span_err; -use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{Features, GateIssue}; use rustc_session::parse::{feature_err, feature_err_issue}; use rustc_session::Session; @@ -301,11 +301,14 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); + let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); // Check feature gates for built-in attributes. - if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info { - gate_feature_fn!(self, has_feature, attr.span, name, descr); + if let Some(BuiltinAttribute { + gate: AttributeGate::Gated(_, name, descr, has_feature), + .. + }) = attr_info + { + gate_feature_fn!(self, has_feature, attr.span, *name, descr); } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b59e49926ad..f1f2387866d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2235,8 +2235,8 @@ impl<'a> State<'a> { let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))]; args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); - if let Some((abi, _)) = asm.clobber_abi { - args.push(AsmArg::ClobberAbi(abi)); + for (abi, _) in &asm.clobber_abis { + args.push(AsmArg::ClobberAbi(*abi)); } if !asm.options.is_empty() { args.push(AsmArg::Options(asm.options)); diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 15309ccd8df..1bc9f8cf3cc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( // We generally shouldn't have errors here because the query was // already run, but there's no point using `delay_span_bug` // when we're going to emit an error here anyway. - let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); + let _errors = fulfill_cx.select_all_or_error(infcx); let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { debug!("{:#?}", region_constraints); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 439c728798d..46a3c0fa101 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let param = generics.type_param(¶m_ty, tcx); if let Some(generics) = tcx .hir() - .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id())) + .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id())) { suggest_constraining_type_param( tcx, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index aca7d3174f6..76d3a83b48d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,7 +3,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(crate_visibility_modifier)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(let_else)] diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index e5924f9d084..6ffab165779 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( errors_buffer: &mut Vec<Diagnostic>, ) { let tcx = infcx.tcx; - let base_def_id = tcx.closure_base_def_id(body.source.def_id()); + let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); if !tcx.has_attr(base_def_id, sym::rustc_regions) { return; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f4a5da1fe36..b39a28f79aa 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new); + let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); @@ -2229,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx tcx, closure_substs, self.num_external_vids, - tcx.closure_base_def_id(closure_def_id), + tcx.typeck_root_def_id(closure_def_id), ); debug!("apply_requirements: closure_mapping={:?}", closure_mapping); diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 24332690bec..92d2d04f23f 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,13 +7,16 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). +use crate::type_check::constraint_conversion::ConstraintConversion; use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; +use rustc_trait_selection::traits::query::Fallible; +use type_op::TypeOpOutput; use crate::universal_regions::UniversalRegions; @@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); + debug!(?normalized_output_ty); + debug!(?normalized_input_tys); + let mir_def_id = body.source.def_id().expect_local(); // If the user explicitly annotated the input types, extract @@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); break; } + // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( normalized_input_ty, @@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the user explicitly annotated the input types, enforce those. let user_provided_input_ty = self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); + self.equate_normalized_input_or_output( user_provided_input_ty, mir_input_ty, @@ -167,30 +176,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd // like to normalize *before* inserting into `local_decls`, but // doing so ends up causing some other trouble. - let b = match self - .infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(b) - { - Ok(n) => { - debug!("equate_inputs_and_outputs: {:?}", n); - if n.obligations.iter().all(|o| { - matches!( - o.predicate.kind().skip_binder(), - ty::PredicateKind::RegionOutlives(_) - | ty::PredicateKind::TypeOutlives(_) - ) - }) { - n.value - } else { - b - } - } + let b = match self.normalize_and_add_constraints(b) { + Ok(n) => n, Err(_) => { debug!("equate_inputs_and_outputs: NoSolution"); b } }; + // Note: if we have to introduce new placeholders during normalization above, then we won't have // added those universes to the universe info, which we would want in `relate_tys`. if let Err(terr) = @@ -207,4 +200,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + + pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> { + let TypeOpOutput { output: norm_ty, constraints, .. } = + self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?; + + debug!("{:?} normalized to {:?}", t, norm_ty); + + for data in constraints.into_iter().collect::<Vec<_>>() { + ConstraintConversion::new( + self.infcx, + &self.borrowck_context.universal_regions, + &self.region_bound_pairs, + Some(self.implicit_region_bound), + self.param_env, + Locations::All(DUMMY_SP), + ConstraintCategory::Internal, + &mut self.borrowck_context.constraints, + ) + .convert_all(&*data); + } + + Ok(norm_ty) + } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 06e34bdce3f..da26d9c7b87 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::vec_map::VecMap; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; @@ -892,11 +893,11 @@ struct TypeChecker<'a, 'tcx> { } struct BorrowCheckContext<'a, 'tcx> { - universal_regions: &'a UniversalRegions<'tcx>, + pub(crate) universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, all_facts: &'a mut Option<AllFacts>, borrow_set: &'a BorrowSet<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, upvars: &'a [Upvar<'tcx>], } @@ -1156,6 +1157,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) } + #[instrument(skip(self, category), level = "debug")] fn eq_types( &mut self, expected: Ty<'tcx>, @@ -1343,13 +1345,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // though. let category = match place.as_local() { Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { + let defining_ty = &self.borrowck_context.universal_regions.defining_ty; + if defining_ty.is_const() { + if tcx.is_static(defining_ty.def_id()) { ConstraintCategory::UseAsStatic } else { ConstraintCategory::UseAsConst @@ -1527,6 +1525,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { + self.check_operand(discr, term_location); + let discr_ty = discr.ty(body, tcx); if let Err(terr) = self.sub_types( discr_ty, @@ -1549,6 +1549,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // FIXME: check the values } TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { + self.check_operand(func, term_location); + for arg in args { + self.check_operand(arg, term_location); + } + let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); let sig = match func_ty.kind() { @@ -1593,6 +1598,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); } TerminatorKind::Assert { ref cond, ref msg, .. } => { + self.check_operand(cond, term_location); + let cond_ty = cond.ty(body, tcx); if cond_ty != tcx.types.bool { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); @@ -1608,6 +1615,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::Yield { ref value, .. } => { + self.check_operand(value, term_location); + let value_ty = value.ty(body, tcx); match body.yield_ty() { None => span_mirbug!(self, term, "yield in non-generator"), @@ -1650,7 +1659,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + UniversalRegions { + defining_ty: + DefiningTy::Const(def_id, _) + | DefiningTy::InlineConst(def_id, _), + .. + }, .. } = self.borrowck_context { @@ -1931,15 +1945,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { + if let Operand::Constant(constant) = op { + let maybe_uneval = match constant.literal { + ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(uv) => Some(uv), + _ => None, + }, + _ => None, + }; + if let Some(uv) = maybe_uneval { + if uv.promoted.is_none() { + let tcx = self.tcx(); + let def_id = uv.def.def_id_for_type_of(); + if tcx.def_kind(def_id) == DefKind::InlineConst { + let predicates = self.prove_closure_bounds( + tcx, + def_id.expect_local(), + uv.substs(tcx), + location, + ); + self.normalize_and_prove_instantiated_predicates( + def_id, + predicates, + location.to_locations(), + ); + } + } + } + } + } + fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { let tcx = self.tcx(); match rvalue { Rvalue::Aggregate(ak, ops) => { + for op in ops { + self.check_operand(op, location); + } self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) } Rvalue::Repeat(operand, len) => { + self.check_operand(operand, location); + // If the length cannot be evaluated we must assume that the length can be larger // than 1. // If the length is larger than 1, the repeat expression will need to copy the @@ -1990,7 +2040,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { + Rvalue::NullaryOp(_, ty) => { + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + substs: tcx.mk_substs_trait(ty, &[]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); + } + + Rvalue::ShallowInitBox(operand, ty) => { + self.check_operand(operand, location); + let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2004,6 +2069,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::Cast(cast_kind, op, ty) => { + self.check_operand(op, location); + match cast_kind { CastKind::Pointer(PointerCast::ReifyFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); @@ -2250,6 +2317,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, box (left, right), ) => { + self.check_operand(left, location); + self.check_operand(right, location); + let ty_left = left.ty(body, tcx); match ty_left.kind() { // Types with regions are comparable if they have a common super-type. @@ -2300,13 +2370,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { + self.check_operand(operand, location); + } + + Rvalue::BinaryOp(_, box (left, right)) + | Rvalue::CheckedBinaryOp(_, box (left, right)) => { + self.check_operand(left, location); + self.check_operand(right, location); + } + Rvalue::AddressOf(..) | Rvalue::ThreadLocalRef(..) - | Rvalue::Use(..) | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) => {} } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 147e2aead64..b986df403f9 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; use std::iter; use crate::nll::ToRegionVid; @@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> { /// is that it has no inputs and a single return value, which is /// the value of the constant. Const(DefId, SubstsRef<'tcx>), + + /// The MIR represents an inline const. The signature has no inputs and a + /// single return value found via `InlineConstSubsts::ty`. + InlineConst(DefId, SubstsRef<'tcx>), } impl<'tcx> DefiningTy<'tcx> { @@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Generator(_, substs, _) => { Either::Right(Either::Left(substs.as_generator().upvar_tys())) } - DefiningTy::FnDef(..) | DefiningTy::Const(..) => { + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { Either::Right(Either::Right(iter::empty())) } } @@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn implicit_inputs(self) -> usize { match self { DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -142,7 +146,7 @@ impl<'tcx> DefiningTy<'tcx> { } pub fn is_const(&self) -> bool { - matches!(*self, DefiningTy::Const(..)) + matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..)) } pub fn def_id(&self) -> DefId { @@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(def_id, ..) | DefiningTy::Generator(def_id, ..) | DefiningTy::FnDef(def_id, ..) - | DefiningTy::Const(def_id, ..) => def_id, + | DefiningTy::Const(def_id, ..) + | DefiningTy::InlineConst(def_id, ..) => def_id, } } } @@ -242,7 +247,7 @@ impl<'tcx> UniversalRegions<'tcx> { tcx: TyCtxt<'tcx>, closure_substs: SubstsRef<'tcx>, expected_num_vars: usize, - closure_base_def_id: DefId, + typeck_root_def_id: DefId, ) -> IndexVec<RegionVid, ty::Region<'tcx>> { let mut region_mapping = IndexVec::with_capacity(expected_num_vars); region_mapping.push(tcx.lifetimes.re_static); @@ -250,7 +255,7 @@ impl<'tcx> UniversalRegions<'tcx> { region_mapping.push(fr); }); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { region_mapping.push(r); }); @@ -344,8 +349,8 @@ impl<'tcx> UniversalRegions<'tcx> { // tests, and the resulting print-outs include def-ids // and other things that are not stable across tests! // So we just include the region-vid. Annoying. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -359,8 +364,8 @@ impl<'tcx> UniversalRegions<'tcx> { // FIXME: As above, we'd like to print out the region // `r` but doing so is not stable across architectures // and so forth. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -376,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> { tcx.def_path_str_with_substs(def_id, substs), )); } + DefiningTy::InlineConst(def_id, substs) => { + err.note(&format!( + "defining inline constant type: {}", + tcx.def_path_str_with_substs(def_id, substs), + )); + } } } } @@ -411,7 +422,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); // If this is a closure or generator, then the late-bound regions from the enclosing // function are actually external regions to us. For example, here, 'a is not local @@ -419,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // fn foo<'a>() { // let c = || { let x: &'a u32 = ...; } // } - if self.mir_def.did.to_def_id() != closure_base_def_id { + if self.mir_def.did.to_def_id() != typeck_root_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) } @@ -437,7 +448,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ); // Converse of above, if this is a function then the late-bound regions declared on its // signature are local to the fn. - if self.mir_def.did.to_def_id() == closure_base_def_id { + if self.mir_def.did.to_def_id() == typeck_root_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); } @@ -502,12 +513,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); match tcx.hir().body_owner_kind(self.mir_hir_id) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { - tcx.type_of(closure_base_def_id) + let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { + tcx.type_of(typeck_root_def_id) } else { let tables = tcx.typeck(self.mir_def.did); tables.node_type(self.mir_hir_id) @@ -534,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); - DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); + if self.mir_def.did.to_def_id() == typeck_root_def_id { + let substs = + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); + DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + } else { + let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id); + let substs = InlineConstSubsts::new( + tcx, + InlineConstSubstsParts { parent_substs: identity_substs, ty }, + ) + .substs; + let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs); + DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs) + } } } } @@ -553,17 +574,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); let fr_substs = match defining_ty { - DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { + DefiningTy::Closure(_, ref substs) + | DefiningTy::Generator(_, ref substs, _) + | DefiningTy::InlineConst(_, ref substs) => { // In the case of closures, we rely on the fact that // the first N elements in the ClosureSubsts are - // inherited from the `closure_base_def_id`. + // inherited from the `typeck_root_def_id`. // Therefore, when we zip together (below) with // `identity_substs`, we will get only those regions // that correspond to early-bound regions declared on - // the `closure_base_def_id`. + // the `typeck_root_def_id`. assert!(substs.len() >= identity_substs.len()); assert_eq!(substs.regions().count(), identity_substs.regions().count()); substs @@ -648,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) } + + DefiningTy::InlineConst(def_id, substs) => { + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let ty = substs.as_inline_const().ty(); + ty::Binder::dummy(tcx.intern_type_list(&[ty])) + } } } } @@ -736,8 +765,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { indices: &mut UniversalRegionIndices<'tcx>, ) { debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); - let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); - for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { + let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id()); + for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| { debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 50127b5b15c..41662f46f11 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -19,7 +19,7 @@ struct AsmArgs { operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap<Symbol, usize>, reg_args: FxHashSet<usize>, - clobber_abi: Option<(Symbol, Span)>, + clobber_abis: Vec<(Symbol, Span)>, options: ast::InlineAsmOptions, options_spans: Vec<Span>, } @@ -64,7 +64,7 @@ fn parse_args<'a>( operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), - clobber_abi: None, + clobber_abis: Vec::new(), options: ast::InlineAsmOptions::empty(), options_spans: vec![], }; @@ -210,9 +210,9 @@ fn parse_args<'a>( .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); - } else if let Some((_, abi_span)) = args.clobber_abi { + } else if let Some((_, abi_span)) = args.clobber_abis.last() { ecx.struct_span_err(span, "arguments are not allowed after clobber_abi") - .span_label(abi_span, "clobber_abi") + .span_label(*abi_span, "clobber_abi") .span_label(span, "argument") .emit(); } @@ -322,10 +322,13 @@ fn parse_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } - if let Some((_, abi_span)) = args.clobber_abi { + + if args.clobber_abis.len() > 0 { if is_global_asm { - let err = - ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`"); + let err = ecx.struct_span_err( + args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(), + "`clobber_abi` cannot be used with `global_asm!`", + ); // Bail out now since this is likely to confuse later stages return Err(err); @@ -335,7 +338,10 @@ fn parse_args<'a>( regclass_outputs.clone(), "asm with `clobber_abi` must specify explicit registers for outputs", ) - .span_label(abi_span, "clobber_abi") + .span_labels( + args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(), + "clobber_abi", + ) .span_labels(regclass_outputs, "generic outputs") .emit(); } @@ -439,37 +445,61 @@ fn parse_clobber_abi<'a>( p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let clobber_abi = match p.parse_str_lit() { - Ok(str_lit) => str_lit.symbol_unescaped, - Err(opt_lit) => { - let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); - } - }; + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + let err = p.sess.span_diagnostic.struct_span_err( + p.token.span, + "at least one abi must be provided as an argument to `clobber_abi`", + ); + return Err(err); + } - p.expect(&token::CloseDelim(token::DelimToken::Paren))?; + let mut new_abis = Vec::new(); + loop { + match p.parse_str_lit() { + Ok(str_lit) => { + new_abis.push((str_lit.symbol_unescaped, str_lit.span)); + } + Err(opt_lit) => { + // If the non-string literal is a closing paren then it's the end of the list and is fine + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + let span = opt_lit.map_or(p.token.span, |lit| lit.span); + let mut err = + p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); + return Err(err); + } + }; - let new_span = span_start.to(p.prev_token.span); + // Allow trailing commas + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + p.expect(&token::Comma)?; + } - if let Some((_, prev_span)) = args.clobber_abi { - let mut err = p - .sess - .span_diagnostic - .struct_span_err(new_span, "clobber_abi specified multiple times"); - err.span_label(prev_span, "clobber_abi previously specified here"); - return Err(err); - } else if !args.options_spans.is_empty() { + let full_span = span_start.to(p.prev_token.span); + + if !args.options_spans.is_empty() { let mut err = p .sess .span_diagnostic - .struct_span_err(new_span, "clobber_abi is not allowed after options"); + .struct_span_err(full_span, "clobber_abi is not allowed after options"); err.span_labels(args.options_spans.clone(), "options"); return Err(err); } - args.clobber_abi = Some((clobber_abi, new_span)); + match &new_abis[..] { + // should have errored above during parsing + [] => unreachable!(), + [(abi, _span)] => args.clobber_abis.push((*abi, full_span)), + [abis @ ..] => { + for (abi, span) in abis { + args.clobber_abis.push((*abi, *span)); + } + } + } Ok(()) } @@ -770,7 +800,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl template, template_strs: template_strs.into_boxed_slice(), operands: args.operands, - clobber_abi: args.clobber_abi, + clobber_abis: args.clobber_abis, options: args.options, line_spans, }) @@ -815,7 +845,7 @@ pub fn expand_global_asm<'cx>( ident: Ident::empty(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(inline_asm), + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), vis: ast::Visibility { span: sp.shrink_to_lo(), kind: ast::VisibilityKind::Inherited, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f0056cb7976..097eaddb874 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -527,17 +527,9 @@ impl<'a, 'b> Context<'a, 'b> { self.verify_arg_type(Exact(idx), ty) } None => { - let capture_feature_enabled = self - .ecx - .ecfg - .features - .map_or(false, |features| features.format_args_capture); - // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - let can_capture = capture_feature_enabled && self.is_literal; - - if can_capture { + if self.is_literal { // Treat this name as a variable to capture from the surrounding scope let idx = self.args.len(); self.arg_types.push(Vec::new()); @@ -559,23 +551,15 @@ impl<'a, 'b> Context<'a, 'b> { }; let mut err = self.ecx.struct_span_err(sp, &msg[..]); - if capture_feature_enabled && !self.is_literal { - err.note(&format!( - "did you intend to capture a variable `{}` from \ - the surrounding scope?", - name - )); - err.note( - "to avoid ambiguity, `format_args!` cannot capture variables \ - when the format string is expanded from a macro", - ); - } else if self.ecx.parse_sess().unstable_features.is_nightly_build() { - err.help(&format!( - "if you intended to capture `{}` from the surrounding scope, add \ - `#![feature(format_args_capture)]` to the crate attributes", - name - )); - } + err.note(&format!( + "did you intend to capture a variable `{}` from \ + the surrounding scope?", + name + )); + err.note( + "to avoid ambiguity, `format_args!` cannot capture variables \ + when the format string is expanded from a macro", + ); err.emit(); } @@ -760,16 +744,11 @@ impl<'a, 'b> Context<'a, 'b> { /// Actually builds the expression which the format_args! block will be /// expanded to. fn into_expr(self) -> P<ast::Expr> { - let mut locals = - Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum()); - let mut counts = Vec::with_capacity(self.count_args.len()); - let mut pats = Vec::with_capacity(self.args.len()); + let mut args = Vec::with_capacity( + self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(), + ); let mut heads = Vec::with_capacity(self.args.len()); - let names_pos: Vec<_> = (0..self.args.len()) - .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp)) - .collect(); - // First, build up the static array which will become our precompiled // format "string" let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces); @@ -787,11 +766,8 @@ impl<'a, 'b> Context<'a, 'b> { // of each variable because we don't want to move out of the arguments // passed to this function. for (i, e) in self.args.into_iter().enumerate() { - let name = names_pos[i]; - let span = self.ecx.with_def_site_ctxt(e.span); - pats.push(self.ecx.pat_ident(span, name)); for arg_ty in self.arg_unique_types[i].iter() { - locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); + args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i)); } heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -800,15 +776,11 @@ impl<'a, 'b> Context<'a, 'b> { Exact(i) => i, _ => panic!("should never happen"), }; - let name = names_pos[index]; let span = spans_pos[index]; - counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name)); + args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index)); } - // Now create a vector containing all the arguments - let args = locals.into_iter().chain(counts.into_iter()); - - let args_array = self.ecx.expr_vec(self.macsp, args.collect()); + let args_array = self.ecx.expr_vec(self.macsp, args); // Constructs an AST equivalent to: // @@ -838,7 +810,7 @@ impl<'a, 'b> Context<'a, 'b> { // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. let args_match = { - let pat = self.ecx.pat_tuple(self.macsp, pats); + let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp)); let arm = self.ecx.arm(self.macsp, pat, args_array); let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads)); self.ecx.expr_match(self.macsp, head, vec![arm]) @@ -877,10 +849,11 @@ impl<'a, 'b> Context<'a, 'b> { macsp: Span, mut sp: Span, ty: &ArgumentType, - arg: Ident, + arg_index: usize, ) -> P<ast::Expr> { sp = ecx.with_def_site_ctxt(sp); - let arg = ecx.expr_ident(sp, arg); + let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp)); + let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp))); let trait_ = match *ty { Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true), Placeholder(trait_) => trait_, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 64bd586662d..f3a2382ef32 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -316,7 +316,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { extended_asm.add_input_operand(None, "r", result.llval); extended_asm.add_clobber("memory"); extended_asm.set_volatile_flag(true); - + // We have copied the value to `result` already. return; } @@ -363,10 +363,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { cond } - fn sideeffect(&mut self) { - // TODO(antoyo) - } - fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value { // Unsupported. self.context.new_rvalue_from_int(self.int_type, 0) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 82c3c2006eb..3d05fc15b38 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -17,6 +17,7 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; @@ -53,6 +54,7 @@ pub fn write_output_file( output: &Path, dwo_output: Option<&Path>, file_type: llvm::FileType, + self_profiler_ref: &SelfProfilerRef, ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); @@ -76,6 +78,19 @@ pub fn write_output_file( file_type, ) }; + + // Record artifact sizes for self-profiling + if result == llvm::LLVMRustResult::Success { + let artifact_kind = match file_type { + llvm::FileType::ObjectFile => "object_file", + llvm::FileType::AssemblyFile => "assembly_file", + }; + record_artifact_size(self_profiler_ref, artifact_kind, output); + if let Some(dwo_file) = dwo_output { + record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); + } + } + result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -286,7 +301,7 @@ fn report_inline_asm( cookie = 0; } let level = match level { - llvm::DiagnosticLevel::Error => Level::Error, + llvm::DiagnosticLevel::Error => Level::Error { lint: false }, llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; @@ -752,6 +767,14 @@ pub(crate) unsafe fn codegen( let thin = ThinBuffer::new(llmod); let data = thin.data(); + if let Some(bitcode_filename) = bc_out.file_name() { + cgcx.prof.artifact_size( + "llvm_bitcode", + bitcode_filename.to_string_lossy(), + data.len() as u64, + ); + } + if config.emit_bc || config.emit_obj == EmitObj::Bitcode { let _timer = cgcx.prof.generic_activity_with_arg( "LLVM_module_codegen_emit_bitcode", @@ -812,6 +835,11 @@ pub(crate) unsafe fn codegen( } let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback); + + if result == llvm::LLVMRustResult::Success { + record_artifact_size(&cgcx.prof, "llvm_ir", &out); + } + result.into_result().map_err(|()| { let msg = format!("failed to write LLVM IR to {}", out.display()); llvm_err(diag_handler, &msg) @@ -842,6 +870,7 @@ pub(crate) unsafe fn codegen( &path, None, llvm::FileType::AssemblyFile, + &cgcx.prof, ) })?; } @@ -875,6 +904,7 @@ pub(crate) unsafe fn codegen( &obj_out, dwo_out, llvm::FileType::ObjectFile, + &cgcx.prof, ) })?; } @@ -1131,3 +1161,19 @@ fn create_msvc_imps( symbol_name.starts_with(b"__llvm_profile_") } } + +fn record_artifact_size( + self_profiler_ref: &SelfProfilerRef, + artifact_kind: &'static str, + path: &Path, +) { + // Don't stat the file if we are not going to record its size. + if !self_profiler_ref.enabled() { + return; + } + + if let Some(artifact_name) = path.file_name() { + let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0); + self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size); + } +} diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1dba264a961..613a8df891c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -597,7 +597,6 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.trap", fn() -> void); ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> i8p); - ifn!("llvm.sideeffect", fn() -> void); ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1f1bd73c7d0..2a6bf7d9b1a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_item_name(self.tcx(), def_id, false, &mut name); // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id); + let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e63fb22829a..a7e34b08059 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; -use rustc_target::abi::{self, HasDataLayout, Primitive}; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; @@ -392,15 +392,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)]) } - fn sideeffect(&mut self) { - // This kind of check would make a ton of sense in the caller, but currently the only - // caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM - // codegen backend being used, and so is unable to check the LLVM version. - if unsafe { llvm::LLVMRustVersionMajor() } < 12 { - self.call_intrinsic("llvm.sideeffect", &[]); - } - } - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time // optimization pass replaces calls to this intrinsic with code to test type membership. @@ -857,28 +848,39 @@ fn generic_simd_intrinsic( let arg_tys = sig.inputs(); if name == sym::simd_select_bitmask { - let in_ty = arg_tys[0]; - let m_len = match in_ty.kind() { - // Note that this `.unwrap()` crashes for isize/usize, that's sort - // of intentional as there's not currently a use case for that. - ty::Int(i) => i.bit_width().unwrap(), - ty::Uint(i) => i.bit_width().unwrap(), - _ => return_error!("`{}` is not an integral type", in_ty), - }; require_simd!(arg_tys[1], "argument"); - let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); - require!( - // Allow masks for vectors with fewer than 8 elements to be - // represented with a u8 or i8. - m_len == v_len || (m_len == 8 && v_len < 8), - "mismatched lengths: mask length `{}` != other vector length `{}`", - m_len, - v_len - ); + let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + + let expected_int_bits = (len.max(8) - 1).next_power_of_two(); + let expected_bytes = len / 8 + ((len % 8 > 0) as u64); + + let mask_ty = arg_tys[0]; + let mask = match mask_ty.kind() { + ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(), + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(), + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + let place = PlaceRef::alloca(bx, args[0].layout); + args[0].val.store(bx, place); + let int_ty = bx.type_ix(expected_bytes * 8); + let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty)); + bx.load(int_ty, ptr, Align::ONE) + } + _ => return_error!( + "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`", + mask_ty, + expected_int_bits, + expected_bytes + ), + }; + let i1 = bx.type_i1(); - let im = bx.type_ix(v_len); - let i1xn = bx.type_vector(i1, v_len); - let m_im = bx.trunc(args[0].immediate(), im); + let im = bx.type_ix(len); + let i1xn = bx.type_vector(i1, len); + let m_im = bx.trunc(mask, im); let m_i1s = bx.bitcast(m_im, i1xn); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } @@ -1056,16 +1058,16 @@ fn generic_simd_intrinsic( if name == sym::simd_bitmask { // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a - // vector mask and returns an unsigned integer containing the most - // significant bit (MSB) of each lane. - - // If the vector has less than 8 lanes, a u8 is returned with zeroed - // trailing bits. + // vector mask and returns the most significant bit (MSB) of each lane in the form + // of either: + // * an unsigned integer + // * an array of `u8` + // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. + // + // The bit order of the result depends on the byte endianness, LSB-first for little + // endian and MSB-first for big endian. let expected_int_bits = in_len.max(8); - match ret_ty.kind() { - ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), - _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits), - } + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); // Integer vector <i{in_bitwidth} x in_len>: let (i_xn, in_elem_bitwidth) = match in_elem.kind() { @@ -1095,8 +1097,34 @@ fn generic_simd_intrinsic( let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len)); // Bitcast <i1 x N> to iN: let i_ = bx.bitcast(i1xn, bx.type_ix(in_len)); - // Zero-extend iN to the bitmask type: - return Ok(bx.zext(i_, bx.type_ix(expected_int_bits))); + + match ret_ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => { + // Zero-extend iN to the bitmask type: + return Ok(bx.zext(i_, bx.type_ix(expected_int_bits))); + } + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + // Zero-extend iN to the array lengh: + let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8)); + + // Convert the integer to a byte array + let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE); + bx.store(ze, ptr, Align::ONE); + let array_ty = bx.type_array(bx.type_i8(), expected_bytes); + let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty)); + return Ok(bx.load(array_ty, ptr, Align::ONE)); + } + _ => return_error!( + "cannot return `{}`, expected `u{}` or `[u8; {}]`", + ret_ty, + expected_int_bits, + expected_bytes + ), + } } fn simd_simple_float_intrinsic( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 6c02543bd7c..638b2a7b5a9 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -121,6 +121,19 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( if sess.opts.json_artifact_notifications { sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link"); } + + if sess.prof.enabled() { + if let Some(artifact_name) = out_filename.file_name() { + // Record size for self-profiling + let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0); + + sess.prof.artifact_size( + "linked_artifact", + artifact_name.to_string_lossy(), + file_size, + ); + } + } } } @@ -1021,8 +1034,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename), } + let strip = strip_value(sess); + if sess.target.is_like_osx { - match sess.opts.debugging_opts.strip { + match strip { Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")), Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None), Strip::None => {} @@ -1030,6 +1045,14 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( } } +// Temporarily support both -Z strip and -C strip +fn strip_value(sess: &Session) -> Strip { + match (sess.opts.debugging_opts.strip, sess.opts.cg.strip) { + (s, Strip::None) => s, + (_, s) => s, + } +} + fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) { let mut cmd = Command::new("strip"); if let Some(option) = option { @@ -2001,7 +2024,7 @@ fn add_order_independent_options( cmd.optimize(); // Pass debuginfo and strip flags down to the linker. - cmd.debuginfo(sess.opts.debugging_opts.strip); + cmd.debuginfo(strip_value(sess)); // We want to prevent the compiler from accidentally leaking in any system libraries, // so by default we tell linkers not to link to any default libraries. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 429dc45d6a4..15d16e7d3d6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -219,19 +219,36 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - /// Argument that must be passed *directly* to the linker + /// Passes an argument directly to the linker. /// - /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used. - fn linker_arg<S>(&mut self, arg: S) -> &mut Self - where - S: AsRef<OsStr>, - { - if !self.is_ld { - let mut os = OsString::from("-Wl,"); - os.push(arg.as_ref()); - self.cmd.arg(os); + /// When the linker is not ld-like such as when using a compiler as a linker, the argument is + /// prepended by `-Wl,`. + fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + self.linker_args(&[arg]); + self + } + + /// Passes a series of arguments directly to the linker. + /// + /// When the linker is ld-like, the arguments are simply appended to the command. When the + /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by + /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a + /// single argument is appended to the command to ensure that the order of the arguments is + /// preserved by the compiler. + fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self { + if self.is_ld { + args.into_iter().for_each(|a| { + self.cmd.arg(a); + }); } else { - self.cmd.arg(arg); + if !args.is_empty() { + let mut s = OsString::from("-Wl"); + for a in args { + s.push(","); + s.push(a); + } + self.cmd.arg(s); + } } self } @@ -289,14 +306,19 @@ impl<'a> GccLinker<'a> { if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use { self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; - self.linker_arg(&format!("-plugin-opt={}", opt_level)); - self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu)); + self.linker_args(&[ + &format!("-plugin-opt={}", opt_level), + &format!("-plugin-opt=mcpu={}", self.target_cpu), + ]); } fn build_dylib(&mut self, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { - self.cmd.arg("-dynamiclib"); + if !self.is_ld { + self.cmd.arg("-dynamiclib"); + } + self.linker_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack @@ -304,10 +326,9 @@ impl<'a> GccLinker<'a> { // principled solution at some point to force the compiler to pass // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - self.linker_arg("-install_name"); - let mut v = OsString::from("@rpath/"); - v.push(out_filename.file_name().unwrap()); - self.linker_arg(&v); + let mut rpath = OsString::from("@rpath/"); + rpath.push(out_filename.file_name().unwrap()); + self.linker_args(&[OsString::from("-install_name"), rpath]); } } else { self.cmd.arg("-shared"); @@ -381,8 +402,7 @@ impl<'a> Linker for GccLinker<'a> { self.build_dylib(out_filename); } LinkOutputKind::WasiReactorExe => { - self.linker_arg("--entry"); - self.linker_arg("_initialize"); + self.linker_args(&["--entry", "_initialize"]); } } // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, @@ -454,8 +474,7 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg(path); } fn full_relro(&mut self) { - self.linker_arg("-zrelro"); - self.linker_arg("-znow"); + self.linker_args(&["-zrelro", "-znow"]); } fn partial_relro(&mut self) { self.linker_arg("-zrelro"); @@ -639,7 +658,6 @@ impl<'a> Linker for GccLinker<'a> { } let is_windows = self.sess.target.is_like_windows; - let mut arg = OsString::new(); let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); debug!("EXPORTED SYMBOLS:"); @@ -691,27 +709,18 @@ impl<'a> Linker for GccLinker<'a> { } if self.sess.target.is_like_osx { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-exported_symbols_list,"); + self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); } else if self.sess.target.is_like_solaris { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-M,"); + self.linker_args(&[OsString::from("-M"), path.into()]); } else { - if !self.is_ld { - arg.push("-Wl,") - } - // Both LD and LLD accept export list in *.def file form, there are no flags required - if !is_windows { - arg.push("--version-script=") + if is_windows { + self.linker_arg(path); + } else { + let mut arg = OsString::from("--version-script="); + arg.push(path); + self.linker_arg(arg); } } - - arg.push(&path); - self.cmd.arg(arg); } fn subsystem(&mut self, subsystem: &str) { @@ -769,8 +778,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("--as-needed"); } else if self.sess.target.is_like_solaris { // -z ignore is the Solaris equivalent to the GNU ld --as-needed option - self.linker_arg("-z"); - self.linker_arg("ignore"); + self.linker_args(&["-z", "ignore"]); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b2edc6c0183..85d51ea9a20 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1757,7 +1757,7 @@ impl SharedEmitterMain { let msg = msg.strip_prefix("error: ").unwrap_or(&msg); let mut err = match level { - Level::Error => sess.struct_err(&msg), + Level::Error { lint: false } => sess.struct_err(&msg), Level::Warning => sess.struct_warn(&msg), Level::Note => sess.struct_note_without_error(&msg), _ => bug!("Invalid inline asm diagnostic level"), diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a9471f7b771..c8f388bfa1d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -980,17 +980,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Goto { target } => { - if bb == target { - // This is an unconditional branch back to this same basic block. That means we - // have something like a `loop {}` statement. LLVM versions before 12.0 - // miscompile this because they assume forward progress. For older versions - // try to handle just this specific case which comes up commonly in practice - // (e.g., in embedded code). - // - // NB: the `sideeffect` currently checks for the LLVM version used internally. - bx.sideeffect(); - } - helper.funclet_br(self, &mut bx, target); } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index caeeb23feb4..b4420df5df4 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -20,6 +20,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("aes", Some(sym::arm_target_feature)), ("sha2", Some(sym::arm_target_feature)), ("i8mm", Some(sym::arm_target_feature)), + ("dotprod", Some(sym::arm_target_feature)), ("v5te", Some(sym::arm_target_feature)), ("v6", Some(sym::arm_target_feature)), ("v6k", Some(sym::arm_target_feature)), diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 78bf22ef9f2..02be6cd360c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -20,10 +20,6 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Emits a forced side effect. - /// - /// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend. - fn sideeffect(&mut self); /// Trait method used to test whether a given pointer is associated with a type identifier. fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value; /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 57af0ff0714..6d3a89c0a8a 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( | DefKind::Static | DefKind::ConstParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::AssocConst ), "Unexpected DefKind: {:?}", diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 323e102b872..51207828935 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -131,6 +131,10 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether to enforce validity (e.g., initialization and not having ptr provenance) + /// of integers and floats. + fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether function calls should be [ABI](Abi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { true @@ -427,6 +431,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] + fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + true + } + + #[inline(always)] fn call_extra_fn( _ecx: &mut InterpCx<$mir, $tcx, Self>, fn_val: !, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b8b6ff93753..4aa3c83cc02 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1057,20 +1057,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(dest_ptr) => dest_ptr, }; + // This checks relocation edges on the src, which needs to happen before + // `prepare_relocation_copy`. + let src_bytes = src_alloc + .get_bytes_with_uninit_and_ptr(&tcx, src_range) + .map_err(|e| e.to_interp_error(src_alloc_id))? + .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation // first copy the relocations to a temporary buffer, because // `get_bytes_mut` will clear the relocations, which is correct, // since we don't want to keep any relocations at the target. - // (`get_bytes_with_uninit_and_ptr` below checks that there are no - // relocations overlapping the edges; those would not be handled correctly). let relocations = src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies); // Prepare a copy of the initialization mask. let compressed = src_alloc.compress_uninit_range(src_range); - // This checks relocation edges on the src. - let src_bytes = src_alloc - .get_bytes_with_uninit_and_ptr(&tcx, src_range) - .map_err(|e| e.to_interp_error(src_alloc_id))? - .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation // Destination alloc preparations and access hooks. let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc69770bf6a..6be3e19a833 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -520,7 +520,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let value = self.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - if self.ctfe_mode.is_some() { + if M::enforce_number_validity(self.ecx) { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok()); if !is_bits { @@ -528,9 +528,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { "{}", value } expected { "initialized plain (non-pointer) bytes" } ) } - } else { - // At run-time, for now, we accept *anything* for these types, including - // uninit. We should fix that, but let's start low. } Ok(true) } @@ -855,9 +852,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } }; + let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx); match alloc.check_bytes( alloc_range(Size::ZERO, size), - /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(), + allow_uninit_and_ptr, ) { // In the happy case, we needn't check anything else. Ok(()) => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 3785c170f6b..2854e6fd396 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -722,7 +722,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { match elem { ProjectionElem::Deref => { let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; - if let ty::RawPtr(_) = base_ty.kind() { + if base_ty.is_unsafe_ptr() { if proj_base.is_empty() { let decl = &self.body.local_decls[place_local]; if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { @@ -731,7 +731,13 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { return; } } - self.check_op(ops::RawPtrDeref); + + // `*const T` is stable, `*mut T` is not + if !base_ty.is_mutable_ptr() { + return; + } + + self.check_op(ops::RawMutPtrDeref); } if context.is_mutating_use() { @@ -1054,8 +1060,9 @@ fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) let mut fulfillment_cx = traits::FulfillmentContext::new(); let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span)); fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause); - if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None, false); + let errors = fulfillment_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); } }); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 230d023efb9..6391c886009 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -400,18 +400,18 @@ impl NonConstOp for RawPtrComparison { } #[derive(Debug)] -pub struct RawPtrDeref; -impl NonConstOp for RawPtrDeref { +pub struct RawMutPtrDeref; +impl NonConstOp for RawMutPtrDeref { fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_raw_ptr_deref) + Status::Unstable(sym::const_mut_refs) } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_deref, + sym::const_mut_refs, span, - &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), + &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),), ) } } 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..61c7239c55f 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -34,39 +34,47 @@ pub struct SortedIndexMultiMap<I: Idx, K, V> { } impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { + #[inline] pub fn new() -> Self { SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() } } + #[inline] pub fn len(&self) -> usize { self.items.len() } + #[inline] pub fn is_empty(&self) -> bool { self.items.is_empty() } /// Returns an iterator over the items in the map in insertion order. + #[inline] pub fn into_iter(self) -> impl DoubleEndedIterator<Item = (K, V)> { self.items.into_iter() } /// Returns an iterator over the items in the map in insertion order along with their indices. + #[inline] pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator<Item = (I, (K, V))> { self.items.into_iter_enumerated() } /// Returns an iterator over the items in the map in insertion order. + #[inline] pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> { self.items.iter().map(|(ref k, ref v)| (k, v)) } /// Returns an iterator over the items in the map in insertion order along with their indices. + #[inline] pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> { self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v))) } /// Returns the item in the map with the given index. + #[inline] pub fn get(&self, idx: I) -> Option<&(K, V)> { self.items.get(idx) } @@ -75,6 +83,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. + #[inline] pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> { self.get_by_key_enumerated(key).map(|(_, v)| v) } @@ -84,6 +93,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. + #[inline] pub fn get_by_key_enumerated(&'a 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| { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 9a57ec99144..09fe3a552a0 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -267,6 +267,7 @@ fn run_compiler( None, compiler.output_dir(), compiler.output_file(), + compiler.temps_dir(), ); if should_stop == Compilation::Stop { @@ -295,6 +296,7 @@ fn run_compiler( Some(compiler.input()), compiler.output_dir(), compiler.output_file(), + compiler.temps_dir(), ) .and_then(|| { RustcDefaultCalls::list_metadata( @@ -647,6 +649,7 @@ impl RustcDefaultCalls { input: Option<&Input>, odir: &Option<PathBuf>, ofile: &Option<PathBuf>, + temps_dir: &Option<PathBuf>, ) -> Compilation { use rustc_session::config::PrintRequest::*; // PrintRequest::NativeStaticLibs is special - printed during linking @@ -685,7 +688,7 @@ impl RustcDefaultCalls { }); let attrs = attrs.as_ref().unwrap(); let t_outputs = rustc_interface::util::build_output_filenames( - input, odir, ofile, attrs, sess, + input, odir, ofile, temps_dir, attrs, sess, ); let id = rustc_session::output::find_crate_name(sess, attrs, input); if *req == PrintRequest::CrateName { diff --git a/compiler/rustc_error_codes/src/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md index da53b671ad0..4405a2149ce 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0206.md +++ b/compiler/rustc_error_codes/src/error_codes/E0206.md @@ -4,15 +4,12 @@ enum. Erroneous code example: ```compile_fail,E0206 -type Foo = [u8; 256]; -impl Copy for Foo { } // error! - #[derive(Copy, Clone)] struct Bar; impl Copy for &'static mut Bar { } // error! ``` -You can only implement `Copy` for a struct or an enum. Both of the previous -examples will fail, because neither `[u8; 256]` nor `&'static mut Bar` -(mutable reference to `Bar`) is a struct or enum. +You can only implement `Copy` for a struct or an enum. +The previous example will fail because `&'static mut Bar` +is not a struct or enum. diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 1eb497460e6..9db8f751390 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -66,7 +66,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error, Level::Warning => AnnotationType::Warning, Level::Note => AnnotationType::Note, Level::Help => AnnotationType::Help, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index f2381d75c56..e5116cd8dfe 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -114,7 +114,7 @@ impl Diagnostic { pub fn is_error(&self) -> bool { match self.level { - Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true, + Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true, Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false, } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b6cf332f511..bb3d3a415e7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,7 +6,7 @@ #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(if_let_guard)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(iter_zip)] #![feature(let_else)] #![feature(nll)] @@ -411,6 +411,8 @@ pub struct Handler { /// as well as inconsistent state observation. struct HandlerInner { flags: HandlerFlags, + /// The number of lint errors that have been emitted. + lint_err_count: usize, /// The number of errors that have been emitted, including duplicates. /// /// This is not necessarily the count that's reported to the user once @@ -550,6 +552,7 @@ impl Handler { flags, inner: Lock::new(HandlerInner { flags, + lint_err_count: 0, err_count: 0, warn_count: 0, deduplicated_err_count: 0, @@ -726,7 +729,13 @@ impl Handler { /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Level::Error, msg) + DiagnosticBuilder::new(self, Level::Error { lint: false }, msg) + } + + /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. + #[doc(hidden)] + pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> { + DiagnosticBuilder::new(self, Level::Error { lint: true }, msg) } /// Construct a builder at the `Error` level with the `msg` and the `code`. @@ -790,11 +799,14 @@ impl Handler { } pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) { - self.emit_diag_at_span(Diagnostic::new(Error, msg), span); + self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span); } pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) { - self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span); + self.emit_diag_at_span( + Diagnostic::new_with_code(Error { lint: false }, Some(code), msg), + span, + ); } pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) { @@ -862,6 +874,9 @@ impl Handler { pub fn has_errors(&self) -> bool { self.inner.borrow().has_errors() } + pub fn has_errors_or_lint_errors(&self) -> bool { + self.inner.borrow().has_errors_or_lint_errors() + } pub fn has_errors_or_delayed_span_bugs(&self) -> bool { self.inner.borrow().has_errors_or_delayed_span_bugs() } @@ -979,7 +994,11 @@ impl HandlerInner { } } if diagnostic.is_error() { - self.bump_err_count(); + if matches!(diagnostic.level, Level::Error { lint: true }) { + self.bump_lint_err_count(); + } else { + self.bump_err_count(); + } } else { self.bump_warn_count(); } @@ -1073,11 +1092,14 @@ impl HandlerInner { fn has_errors(&self) -> bool { self.err_count() > 0 } + fn has_errors_or_lint_errors(&self) -> bool { + self.has_errors() || self.lint_err_count > 0 + } fn has_errors_or_delayed_span_bugs(&self) -> bool { self.has_errors() || !self.delayed_span_bugs.is_empty() } fn has_any_message(&self) -> bool { - self.err_count() > 0 || self.warn_count > 0 + self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0 } fn abort_if_errors(&mut self) { @@ -1131,7 +1153,7 @@ impl HandlerInner { } fn err(&mut self, msg: &str) { - self.emit_error(Error, msg); + self.emit_error(Error { lint: false }, msg); } /// Emit an error; level should be `Error` or `Fatal`. @@ -1167,6 +1189,11 @@ impl HandlerInner { } } + fn bump_lint_err_count(&mut self) { + self.lint_err_count += 1; + self.panic_if_treat_err_as_bug(); + } + fn bump_err_count(&mut self) { self.err_count += 1; self.panic_if_treat_err_as_bug(); @@ -1210,7 +1237,10 @@ impl DelayedDiagnostic { pub enum Level { Bug, Fatal, - Error, + Error { + /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called. + lint: bool, + }, Warning, Note, Help, @@ -1229,7 +1259,7 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | Fatal | Error => { + Bug | Fatal | Error { .. } => { spec.set_fg(Some(Color::Red)).set_intense(true); } Warning => { @@ -1250,7 +1280,7 @@ impl Level { pub fn to_str(self) -> &'static str { match self { Bug => "error: internal compiler error", - Fatal | Error => "error", + Fatal | Error { .. } => "error", Warning => "warning", Note => "note", Help => "help", diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 521ca2135c6..4e84a9df6c9 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,7 @@ #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(if_let_guard)] #![feature(iter_zip)] #![feature(let_else)] diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 3f84979ac05..42c17a60a5d 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -24,8 +24,9 @@ impl base::ProcMacro for BangProcMacro { span: Span, input: TokenStream, ) -> Result<TokenStream, ErrorReported> { + let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let server = proc_macro_server::Rustc::new(ecx); - self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| { + self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| { let mut err = ecx.struct_span_err(span, "proc macro panicked"); if let Some(s) = e.as_str() { err.help(&format!("message: {}", s)); @@ -48,9 +49,10 @@ impl base::AttrProcMacro for AttrProcMacro { annotation: TokenStream, annotated: TokenStream, ) -> Result<TokenStream, ErrorReported> { + let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let server = proc_macro_server::Rustc::new(ecx); self.client - .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace) + .run(&EXEC_STRATEGY, server, annotation, annotated, proc_macro_backtrace) .map_err(|e| { let mut err = ecx.struct_span_err(span, "custom attribute panicked"); if let Some(s) = e.as_str() { @@ -97,19 +99,19 @@ impl MultiItemModifier for ProcMacroDerive { nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No) }; + let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let server = proc_macro_server::Rustc::new(ecx); - let stream = - match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) { - Ok(stream) => stream, - Err(e) => { - let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); - if let Some(s) = e.as_str() { - err.help(&format!("message: {}", s)); - } - err.emit(); - return ExpandResult::Ready(vec![]); + let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) { + Ok(stream) => stream, + Err(e) => { + let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); + if let Some(s) = e.as_str() { + err.help(&format!("message: {}", s)); } - }; + err.emit(); + return ExpandResult::Ready(vec![]); + } + }; let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); let mut parser = diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5cb97198765..fa9e98be9e8 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -1,4 +1,4 @@ -use crate::base::{ExtCtxt, ResolverExpand}; +use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token::{self, Nonterminal, NtIdent}; @@ -7,7 +7,7 @@ use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing} use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::Diagnostic; +use rustc_errors::{Diagnostic, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::lexer::nfc_normalize; @@ -53,11 +53,11 @@ impl ToInternal<token::DelimToken> for Delimiter { } } -impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)> +impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)> for TokenTree<Group, Punct, Ident, Literal> { fn from_internal( - ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_>), + ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>), ) -> Self { use rustc_ast::token::*; @@ -146,10 +146,10 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)> SingleQuote => op!('\''), Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()), - Ident(name, is_raw) => tt!(Ident::new(rustc.sess, name, is_raw)), + Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)), Lifetime(name) => { let ident = symbol::Ident::new(name, span).without_first_quote(); - stack.push(tt!(Ident::new(rustc.sess, ident.name, false))); + stack.push(tt!(Ident::new(rustc.sess(), ident.name, false))); tt!(Punct::new('\'', true)) } Literal(lit) => tt!(Literal { lit }), @@ -181,15 +181,15 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)> Interpolated(nt) if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) => { - TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span)) + TokenTree::Ident(Ident::new(rustc.sess(), name.name, is_raw, name.span)) } Interpolated(nt) => { - let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No); + let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No); TokenTree::Group(Group { delimiter: Delimiter::None, stream, span: DelimSpan::from_single(span), - flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess), + flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()), }) } @@ -273,7 +273,7 @@ impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> { impl ToInternal<rustc_errors::Level> for Level { fn to_internal(self) -> rustc_errors::Level { match self { - Level::Error => rustc_errors::Level::Error, + Level::Error => rustc_errors::Level::Error { lint: false }, Level::Warning => rustc_errors::Level::Warning, Level::Note => rustc_errors::Level::Note, Level::Help => rustc_errors::Level::Help, @@ -355,38 +355,38 @@ pub struct Literal { span: Span, } -pub(crate) struct Rustc<'a> { - resolver: &'a dyn ResolverExpand, - sess: &'a ParseSess, +pub(crate) struct Rustc<'a, 'b> { + ecx: &'a mut ExtCtxt<'b>, def_site: Span, call_site: Span, mixed_site: Span, - span_debug: bool, krate: CrateNum, rebased_spans: FxHashMap<usize, Span>, } -impl<'a> Rustc<'a> { - pub fn new(cx: &'a ExtCtxt<'_>) -> Self { - let expn_data = cx.current_expansion.id.expn_data(); +impl<'a, 'b> Rustc<'a, 'b> { + pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self { + let expn_data = ecx.current_expansion.id.expn_data(); Rustc { - resolver: cx.resolver, - sess: cx.parse_sess(), - def_site: cx.with_def_site_ctxt(expn_data.def_site), - call_site: cx.with_call_site_ctxt(expn_data.call_site), - mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site), - span_debug: cx.ecfg.span_debug, + def_site: ecx.with_def_site_ctxt(expn_data.def_site), + call_site: ecx.with_call_site_ctxt(expn_data.call_site), + mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site), krate: expn_data.macro_def_id.unwrap().krate, rebased_spans: FxHashMap::default(), + ecx, } } + fn sess(&self) -> &ParseSess { + self.ecx.parse_sess() + } + fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal { Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) } } } -impl server::Types for Rustc<'_> { +impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type TokenStreamBuilder = tokenstream::TokenStreamBuilder; @@ -401,17 +401,20 @@ impl server::Types for Rustc<'_> { type Span = Span; } -impl server::FreeFunctions for Rustc<'_> { +impl server::FreeFunctions for Rustc<'_, '_> { fn track_env_var(&mut self, var: &str, value: Option<&str>) { - self.sess.env_depinfo.borrow_mut().insert((Symbol::intern(var), value.map(Symbol::intern))); + self.sess() + .env_depinfo + .borrow_mut() + .insert((Symbol::intern(var), value.map(Symbol::intern))); } fn track_path(&mut self, path: &str) { - self.sess.file_depinfo.borrow_mut().insert(Symbol::intern(path)); + self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path)); } } -impl server::TokenStream for Rustc<'_> { +impl server::TokenStream for Rustc<'_, '_> { fn new(&mut self) -> Self::TokenStream { TokenStream::default() } @@ -422,13 +425,62 @@ impl server::TokenStream for Rustc<'_> { parse_stream_from_source_str( FileName::proc_macro_source_code(src), src.to_string(), - self.sess, + self.sess(), Some(self.call_site), ) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { pprust::tts_to_string(stream) } + fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> { + // Parse the expression from our tokenstream. + let expr: PResult<'_, _> = try { + let mut p = rustc_parse::stream_to_parser( + self.sess(), + stream.clone(), + Some("proc_macro expand expr"), + ); + let expr = p.parse_expr()?; + if p.token != token::Eof { + p.unexpected()?; + } + expr + }; + let expr = expr.map_err(|mut err| err.emit())?; + + // Perform eager expansion on the expression. + let expr = self + .ecx + .expander() + .fully_expand_fragment(crate::expand::AstFragment::Expr(expr)) + .make_expr(); + + // NOTE: For now, limit `expand_expr` to exclusively expand to literals. + // This may be relaxed in the future. + // We don't use `nt_to_tokenstream` as the tokenstream currently cannot + // be recovered in the general case. + match &expr.kind { + ast::ExprKind::Lit(l) => { + Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into()) + } + ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind { + ast::ExprKind::Lit(l) => match l.token { + token::Lit { kind: token::Integer | token::Float, .. } => { + Ok(std::array::IntoIter::new([ + // FIXME: The span of the `-` token is lost when + // parsing, so we cannot faithfully recover it here. + tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span), + tokenstream::TokenTree::token(token::Literal(l.token), l.span), + ]) + .collect()) + } + _ => Err(()), + }, + _ => Err(()), + }, + _ => Err(()), + } + } fn from_token_tree( &mut self, tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>, @@ -440,7 +492,7 @@ impl server::TokenStream for Rustc<'_> { } } -impl server::TokenStreamBuilder for Rustc<'_> { +impl server::TokenStreamBuilder for Rustc<'_, '_> { fn new(&mut self) -> Self::TokenStreamBuilder { tokenstream::TokenStreamBuilder::new() } @@ -452,7 +504,7 @@ impl server::TokenStreamBuilder for Rustc<'_> { } } -impl server::TokenStreamIter for Rustc<'_> { +impl server::TokenStreamIter for Rustc<'_, '_> { fn next( &mut self, iter: &mut Self::TokenStreamIter, @@ -477,7 +529,7 @@ impl server::TokenStreamIter for Rustc<'_> { } } -impl server::Group for Rustc<'_> { +impl server::Group for Rustc<'_, '_> { fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group { Group { delimiter, @@ -506,7 +558,7 @@ impl server::Group for Rustc<'_> { } } -impl server::Punct for Rustc<'_> { +impl server::Punct for Rustc<'_, '_> { fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct { Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self)) } @@ -524,9 +576,9 @@ impl server::Punct for Rustc<'_> { } } -impl server::Ident for Rustc<'_> { +impl server::Ident for Rustc<'_, '_> { fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident { - Ident::new(self.sess, Symbol::intern(string), is_raw, span) + Ident::new(self.sess(), Symbol::intern(string), is_raw, span) } fn span(&mut self, ident: Self::Ident) -> Self::Span { ident.span @@ -536,10 +588,10 @@ impl server::Ident for Rustc<'_> { } } -impl server::Literal for Rustc<'_> { +impl server::Literal for Rustc<'_, '_> { fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned()); + let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned()); let first_span = parser.token.span.data(); let minus_present = parser.eat(&token::BinOp(token::Minus)); @@ -675,7 +727,7 @@ impl server::Literal for Rustc<'_> { } } -impl server::SourceFile for Rustc<'_> { +impl server::SourceFile for Rustc<'_, '_> { fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { Lrc::ptr_eq(file1, file2) } @@ -695,7 +747,7 @@ impl server::SourceFile for Rustc<'_> { } } -impl server::MultiSpan for Rustc<'_> { +impl server::MultiSpan for Rustc<'_, '_> { fn new(&mut self) -> Self::MultiSpan { vec![] } @@ -704,7 +756,7 @@ impl server::MultiSpan for Rustc<'_> { } } -impl server::Diagnostic for Rustc<'_> { +impl server::Diagnostic for Rustc<'_, '_> { fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { let mut diag = Diagnostic::new(level.to_internal(), msg); diag.set_span(MultiSpan::from_spans(spans)); @@ -720,13 +772,13 @@ impl server::Diagnostic for Rustc<'_> { diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None); } fn emit(&mut self, diag: Self::Diagnostic) { - self.sess.span_diagnostic.emit_diagnostic(&diag); + self.sess().span_diagnostic.emit_diagnostic(&diag); } } -impl server::Span for Rustc<'_> { +impl server::Span for Rustc<'_, '_> { fn debug(&mut self, span: Self::Span) -> String { - if self.span_debug { + if self.ecx.ecfg.span_debug { format!("{:?}", span) } else { format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) @@ -742,7 +794,7 @@ impl server::Span for Rustc<'_> { self.mixed_site } fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - self.sess.source_map().lookup_char_pos(span.lo()).file + self.sess().source_map().lookup_char_pos(span.lo()).file } fn parent(&mut self, span: Self::Span) -> Option<Self::Span> { span.parent_callsite() @@ -751,11 +803,11 @@ impl server::Span for Rustc<'_> { span.source_callsite() } fn start(&mut self, span: Self::Span) -> LineColumn { - let loc = self.sess.source_map().lookup_char_pos(span.lo()); + let loc = self.sess().source_map().lookup_char_pos(span.lo()); LineColumn { line: loc.line, column: loc.col.to_usize() } } fn end(&mut self, span: Self::Span) -> LineColumn { - let loc = self.sess.source_map().lookup_char_pos(span.hi()); + let loc = self.sess().source_map().lookup_char_pos(span.hi()); LineColumn { line: loc.line, column: loc.col.to_usize() } } fn before(&mut self, span: Self::Span) -> Self::Span { @@ -765,8 +817,8 @@ impl server::Span for Rustc<'_> { span.shrink_to_hi() } fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> { - let self_loc = self.sess.source_map().lookup_char_pos(first.lo()); - let other_loc = self.sess.source_map().lookup_char_pos(second.lo()); + let self_loc = self.sess().source_map().lookup_char_pos(first.lo()); + let other_loc = self.sess().source_map().lookup_char_pos(second.lo()); if self_loc.file.name != other_loc.file.name { return None; @@ -778,7 +830,7 @@ impl server::Span for Rustc<'_> { span.with_ctxt(at.ctxt()) } fn source_text(&mut self, span: Self::Span) -> Option<String> { - self.sess.source_map().span_to_snippet(span).ok() + self.sess().source_map().span_to_snippet(span).ok() } /// Saves the provided span into the metadata of /// *the crate we are currently compiling*, which must @@ -805,10 +857,10 @@ impl server::Span for Rustc<'_> { /// since we've loaded `my_proc_macro` from disk in order to execute it). /// In this way, we have obtained a span pointing into `my_proc_macro` fn save_span(&mut self, span: Self::Span) -> usize { - self.sess.save_proc_macro_span(span) + self.sess().save_proc_macro_span(span) } fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span { - let (resolver, krate, def_site) = (self.resolver, self.krate, self.def_site); + let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site); *self.rebased_spans.entry(id).or_insert_with(|| { // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding, // replace it with a def-site context until we are encoding it properly. @@ -821,11 +873,11 @@ impl server::Span for Rustc<'_> { fn ident_name_compatibility_hack( nt: &Nonterminal, orig_span: Span, - rustc: &mut Rustc<'_>, + rustc: &mut Rustc<'_, '_>, ) -> Option<(rustc_span::symbol::Ident, bool)> { if let NtIdent(ident, is_raw) = nt { if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind { - let source_map = rustc.sess.source_map(); + let source_map = rustc.sess().source_map(); let filename = source_map.span_to_filename(orig_span); if let FileName::Real(RealFileName::LocalPath(path)) = filename { let matches_prefix = |prefix, filename| { @@ -846,7 +898,7 @@ fn ident_name_compatibility_hack( let snippet = source_map.span_to_snippet(orig_span); if snippet.as_deref() == Ok("$name") { if time_macros_impl { - rustc.sess.buffer_lint_with_diagnostic( + rustc.sess().buffer_lint_with_diagnostic( &PROC_MACRO_BACK_COMPAT, orig_span, ast::CRATE_NODE_ID, @@ -871,7 +923,7 @@ fn ident_name_compatibility_hack( .and_then(|c| c.parse::<u32>().ok()) .map_or(false, |v| v < 40) { - rustc.sess.buffer_lint_with_diagnostic( + rustc.sess().buffer_lint_with_diagnostic( &PROC_MACRO_BACK_COMPAT, orig_span, ast::CRATE_NODE_ID, @@ -894,7 +946,7 @@ fn ident_name_compatibility_hack( source_map.span_to_filename(rustc.def_site) { if macro_path.to_string_lossy().contains("pin-project-internal-0.") { - rustc.sess.buffer_lint_with_diagnostic( + rustc.sess().buffer_lint_with_diagnostic( &PROC_MACRO_BACK_COMPAT, orig_span, ast::CRATE_NODE_ID, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 941d957103c..6950fae898f 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -34,6 +34,9 @@ declare_features! ( /// These are used to test this portion of the compiler, /// they don't actually mean anything. (accepted, test_accepted_feature, "1.0.0", None, None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: for testing purposes @@ -43,262 +46,269 @@ declare_features! ( // feature-group-start: accepted features // ------------------------------------------------------------------------- + /// Allows the sysV64 ABI to be specified on all platforms + /// instead of just the platforms on which it is the C ABI. + (accepted, abi_sysv64, "1.24.0", Some(36167), None), + /// Allows the definition of associated constants in `trait` or `impl` blocks. + (accepted, associated_consts, "1.20.0", Some(29646), None), /// Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None, None), - /// Allows using assigning a default type to type parameters in algebraic data type definitions. - (accepted, default_type_params, "1.0.0", None, None), - // FIXME: explain `globs`. - (accepted, globs, "1.0.0", None, None), - /// Allows `macro_rules!` items. - (accepted, macro_rules, "1.0.0", None, None), - /// Allows use of `&foo[a..b]` as a slicing syntax. - (accepted, slicing_syntax, "1.0.0", None, None), - /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). - (accepted, struct_variant, "1.0.0", None, None), - /// Allows indexing tuples. - (accepted, tuple_indexing, "1.0.0", None, None), - /// Allows the use of `if let` expressions. - (accepted, if_let, "1.0.0", None, None), - /// Allows the use of `while let` expressions. - (accepted, while_let, "1.0.0", None, None), - /// Allows using `#![no_std]`. - (accepted, no_std, "1.6.0", None, None), + /// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions. + (accepted, async_await, "1.39.0", Some(50547), None), + /// Allows all literals in attribute lists and values of key-value pairs. + (accepted, attr_literals, "1.30.0", Some(34981), None), /// Allows overloading augmented assignment operations like `a += b`. (accepted, augmented_assignments, "1.8.0", Some(28235), None), + /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. + (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), + /// Allows bindings in the subpattern of a binding pattern. + /// For example, you can write `x @ Some(y)`. + (accepted, bindings_after_at, "1.56.0", Some(65490), None), /// Allows empty structs and enum variants with braces. (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - /// Allows `#[deprecated]` attribute. - (accepted, deprecated, "1.9.0", Some(29935), None), - /// Allows macros to appear in the type position. - (accepted, type_macros, "1.13.0", Some(27245), None), - /// Allows use of the postfix `?` operator in expressions. - (accepted, question_mark, "1.13.0", Some(31436), None), - /// Allows `..` in tuple (struct) patterns. - (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - /// Allows some increased flexibility in the name resolution rules, - /// especially around globs and shadowing (RFC 1560). - (accepted, item_like_imports, "1.15.0", Some(35120), None), - /// Allows using `Self` and associated types in struct expressions and patterns. - (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - /// Allows elision of `'static` lifetimes in `static`s and `const`s. - (accepted, static_in_const, "1.17.0", Some(35897), None), - /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. - (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - /// Allows the definition recursive static items. - (accepted, static_recursion, "1.17.0", Some(29719), None), - /// Allows `pub(restricted)` visibilities (RFC 1422). - (accepted, pub_restricted, "1.18.0", Some(32409), None), - /// Allows `#![windows_subsystem]`. - (accepted, windows_subsystem, "1.18.0", Some(37499), None), - /// Allows `break {expr}` with a value inside `loop`s. - (accepted, loop_break_value, "1.19.0", Some(37339), None), - /// Allows numeric fields in struct expressions and patterns. - (accepted, relaxed_adts, "1.19.0", Some(35626), None), + /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), + /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. + (accepted, cfg_doctest, "1.40.0", Some(62210), None), + /// Allows `cfg(target_feature = "...")`. + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + /// Allows `cfg(target_vendor = "...")`. + (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), + /// Allows implementing `Clone` for closures where possible (RFC 2132). + (accepted, clone_closures, "1.26.0", Some(44490), None), /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - /// Allows attributes on struct literal fields. - (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - /// Allows the definition of associated constants in `trait` or `impl` blocks. - (accepted, associated_consts, "1.20.0", Some(29646), None), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), - /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). - (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - /// Allows `Drop` types in constants (RFC 1440). - (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - /// Allows the sysV64 ABI to be specified on all platforms - /// instead of just the platforms on which it is the C ABI. - (accepted, abi_sysv64, "1.24.0", Some(36167), None), - /// Allows `repr(align(16))` struct attribute (RFC 1358). - (accepted, repr_align, "1.25.0", Some(33626), None), - /// Allows '|' at beginning of match arms (RFC 1925). - (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - /// Allows nested groups in `use` items (RFC 2128). - (accepted, use_nested_groups, "1.25.0", Some(44494), None), + /// Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + /// Allows calling constructor functions in `const fn`. + (accepted, const_constructor, "1.40.0", Some(61456), 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. + (accepted, const_fn_union, "1.56.0", Some(51909), None), + /// Allows unsizing coercions in `const fn`. + (accepted, const_fn_unsize, "1.54.0", Some(64992), None), + /// Allows the use of `if` and `match` in constants. + (accepted, const_if_match, "1.46.0", Some(49146), None), /// Allows indexing into constant arrays. (accepted, const_indexing, "1.26.0", Some(29947), None), - /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. - (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - /// Allows `..=` in patterns (RFC 1192). - (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). - (accepted, termination_trait, "1.26.0", Some(43301), None), - /// Allows implementing `Clone` for closures where possible (RFC 2132). - (accepted, clone_closures, "1.26.0", Some(44490), None), + /// Allows let bindings, assignments and destructuring in `const` functions and constants. + /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used + /// at the same time as let bindings. + (accepted, const_let, "1.33.0", Some(48821), None), + /// Allows the use of `loop` and `while` in constants. + (accepted, const_loop, "1.46.0", Some(52000), None), + /// Allows panicking during const eval (producing compile-time errors). + (accepted, const_panic, "1.57.0", Some(51999), None), + /// Allows dereferencing raw pointers during const eval. + (accepted, const_raw_ptr_deref, "1.58.0", Some(51911), None), /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490), None), - /// Allows `impl Trait` in function arguments. - (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - /// Allows `impl Trait` in function return types. - (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - /// Allows using the `u128` and `i128` types. - (accepted, i128_type, "1.26.0", Some(35118), None), - /// Allows default match binding modes (RFC 2005). - (accepted, match_default_bindings, "1.26.0", Some(42640), None), - /// Allows `'_` placeholder lifetimes. - (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). - (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - /// Allows `cfg(target_feature = "...")`. - (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - /// Allows `#[target_feature(...)]`. - (accepted, target_feature, "1.27.0", None, None), - /// Allows using `dyn Trait` as a syntax for trait objects. - (accepted, dyn_trait, "1.27.0", Some(44662), None), - /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). - (accepted, fn_must_use, "1.27.0", Some(43302), None), - /// Allows use of the `:lifetime` macro fragment specifier. - (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). - (accepted, termination_trait_test, "1.27.0", Some(48854), None), - /// Allows the `#[global_allocator]` attribute. - (accepted, global_allocator, "1.28.0", Some(27389), None), - /// Allows `#[repr(transparent)]` attribute on newtype structs. - (accepted, repr_transparent, "1.28.0", Some(43036), None), - /// Allows procedural macros in `proc-macro` crates. - (accepted, proc_macro, "1.29.0", Some(38356), None), - /// Allows `foo.rs` as an alternative to `foo/mod.rs`. - (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - /// Allows use of the `:vis` macro fragment specifier - (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - /// Allows importing and reexporting macros with `use`, - /// enables macro modularization in general. - (accepted, use_extern_macros, "1.30.0", Some(35896), None), - /// Allows keywords to be escaped for use as identifiers. - (accepted, raw_identifiers, "1.30.0", Some(48589), None), - /// Allows attributes scoped to tools. - (accepted, tool_attributes, "1.30.0", Some(44690), None), - /// Allows multi-segment paths in attributes and derives. - (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - /// Allows all literals in attribute lists and values of key-value pairs. - (accepted, attr_literals, "1.30.0", Some(34981), None), - /// Allows inferring outlives requirements (RFC 2093). - (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - /// This defines the behavior of panics. - (accepted, panic_handler, "1.30.0", Some(44489), None), - /// Allows `#[used]` to preserve symbols (see llvm.compiler.used). - (accepted, used, "1.30.0", Some(40289), None), /// Allows `crate` in paths. (accepted, crate_in_paths, "1.30.0", Some(45477), None), + /// Allows using assigning a default type to type parameters in algebraic data type definitions. + (accepted, default_type_params, "1.0.0", None, None), + /// Allows `#[deprecated]` attribute. + (accepted, deprecated, "1.9.0", Some(29935), None), + /// Allows `#[doc(alias = "...")]`. + (accepted, doc_alias, "1.48.0", Some(50146), None), + /// Allows `..` in tuple (struct) patterns. + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), + /// Allows `..=` in patterns (RFC 1192). + (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + /// Allows `Drop` types in constants (RFC 1440). + (accepted, drop_types_in_const, "1.22.0", Some(33156), None), + /// Allows using `dyn Trait` as a syntax for trait objects. + (accepted, dyn_trait, "1.27.0", Some(44662), None), + /// Allows integer match exhaustiveness checking (RFC 2591). + (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), + /// Allows arbitrary expressions in key-value attributes at parse time. + (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), + /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), + /// Allows `extern crate self as foo;`. + /// This puts local crate root into extern prelude under name `foo`. + (accepted, extern_crate_self, "1.34.0", Some(56409), None), /// Allows access to crate names passed via `--extern` through prelude. (accepted, extern_prelude, "1.30.0", Some(44660), None), - /// Allows parentheses in patterns. - (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - /// Allows the definition of `const fn` functions. - (accepted, min_const_fn, "1.31.0", Some(53555), None), - /// Allows scoped lints. - (accepted, tool_lints, "1.31.0", Some(44690), None), + /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + (accepted, field_init_shorthand, "1.17.0", Some(37340), None), + /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). + (accepted, fn_must_use, "1.27.0", Some(43302), None), + /// Allows capturing variables in scope using format_args! + (accepted, format_args_capture, "1.58.0", Some(67984), None), + /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + (accepted, generic_param_attrs, "1.27.0", Some(48848), None), + /// Allows the `#[global_allocator]` attribute. + (accepted, global_allocator, "1.28.0", Some(27389), None), + // FIXME: explain `globs`. + (accepted, globs, "1.0.0", None, None), + /// Allows using the `u128` and `i128` types. + (accepted, i128_type, "1.26.0", Some(35118), None), + /// Allows the use of `if let` expressions. + (accepted, if_let, "1.0.0", None, None), + /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. + (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), /// Allows lifetime elision in `impl` headers. For example: /// + `impl<I:Iterator> Iterator for &mut Iterator` /// + `impl Debug for Foo<'_>` (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. - (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - /// Allows use of the `:literal` macro fragment specifier (RFC 1576). - (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - /// Allows use of `?` as the Kleene "at most one" operator in macros. - (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - /// Allows `Self` struct constructor (RFC 2302). - (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - /// Allows `Self` in type definitions (RFC 2300). - (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - /// Allows `use x::y;` to search `x` in the current scope. - (accepted, uniform_paths, "1.32.0", Some(53130), None), - /// Allows integer match exhaustiveness checking (RFC 2591). - (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - /// Allows `use path as _;` and `extern crate c as _;`. - (accepted, underscore_imports, "1.33.0", Some(48216), None), - /// Allows `#[repr(packed(N))]` attribute on structs. - (accepted, repr_packed, "1.33.0", Some(33158), None), + /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. + (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), + /// Allows inferring outlives requirements (RFC 2093). + (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. - (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - /// Allows let bindings, assignments and destructuring in `const` functions and constants. - /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used - /// at the same time as let bindings. - (accepted, const_let, "1.33.0", Some(48821), None), - /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. - (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. - (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - /// Allows `cfg(target_vendor = "...")`. - (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - /// Allows `extern crate self as foo;`. - /// This puts local crate root into extern prelude under name `foo`. - (accepted, extern_crate_self, "1.34.0", Some(56409), None), - /// Allows arbitrary delimited token streams in non-macro attributes. - (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - /// Allows paths to enum variants on type aliases including `Self`. - (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - /// Allows using `#[repr(align(X))]` on enums with equivalent semantics - /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. - (accepted, repr_align_enum, "1.37.0", Some(57996), None), - /// Allows `const _: TYPE = VALUE`. - (accepted, underscore_const_names, "1.37.0", Some(54912), None), - /// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions. - (accepted, async_await, "1.39.0", Some(50547), None), - /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. - (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), - /// Allows attributes in formal function parameters. - (accepted, param_attrs, "1.39.0", Some(60406), None), + /// Allows some increased flexibility in the name resolution rules, + /// especially around globs and shadowing (RFC 1560). + (accepted, item_like_imports, "1.15.0", Some(35120), None), + /// Allows `break {expr}` with a value inside `loop`s. + (accepted, loop_break_value, "1.19.0", Some(37339), None), + /// Allows use of `?` as the Kleene "at most one" operator in macros. + (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), + /// Allows macro attributes to observe output of `#[derive]`. + (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), + /// Allows use of the `:lifetime` macro fragment specifier. + (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), + /// Allows use of the `:literal` macro fragment specifier (RFC 1576). + (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), + /// Allows `macro_rules!` items. + (accepted, macro_rules, "1.0.0", None, None), + /// Allows use of the `:vis` macro fragment specifier + (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), /// Allows macro invocations in `extern {}` blocks. (accepted, macros_in_extern, "1.40.0", Some(49476), None), + /// Allows '|' at beginning of match arms (RFC 1925). + (accepted, match_beginning_vert, "1.25.0", Some(44101), None), + /// Allows default match binding modes (RFC 2005). + (accepted, match_default_bindings, "1.26.0", Some(42640), None), + /// Allows `impl Trait` with multiple unrelated lifetimes. + (accepted, member_constraints, "1.54.0", Some(61997), None), + /// Allows the definition of `const fn` functions. + (accepted, min_const_fn, "1.31.0", Some(53555), None), + /// The smallest useful subset of const generics. + (accepted, min_const_generics, "1.51.0", Some(74878), None), + /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), + /// Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.16.0", Some(37544), None), + /// Allows patterns with concurrent by-move and by-ref bindings. + /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. + (accepted, move_ref_pattern, "1.49.0", Some(68354), None), + /// Allows using `#![no_std]`. + (accepted, no_std, "1.6.0", None, None), + /// Allows defining identifiers beyond ASCII. + (accepted, non_ascii_idents, "1.53.0", Some(55467), None), /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). (accepted, non_exhaustive, "1.40.0", Some(44109), None), - /// Allows calling constructor functions in `const fn`. - (accepted, const_constructor, "1.40.0", Some(61456), None), - /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. - (accepted, cfg_doctest, "1.40.0", Some(62210), None), + /// Allows `foo.rs` as an alternative to `foo/mod.rs`. + (accepted, non_modrs_mods, "1.30.0", Some(44660), None), + /// Allows the use of or-patterns (e.g., `0 | 1`). + (accepted, or_patterns, "1.53.0", Some(54883), None), + /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + /// This defines the behavior of panics. + (accepted, panic_handler, "1.30.0", Some(44489), None), + /// Allows attributes in formal function parameters. + (accepted, param_attrs, "1.39.0", Some(60406), None), + /// Allows parentheses in patterns. + (accepted, pattern_parentheses, "1.31.0", Some(51087), None), + /// Allows procedural macros in `proc-macro` crates. + (accepted, proc_macro, "1.29.0", Some(38356), None), + /// Allows multi-segment paths in attributes and derives. + (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), + /// Allows `pub(restricted)` visibilities (RFC 1422). + (accepted, pub_restricted, "1.18.0", Some(32409), None), + /// Allows use of the postfix `?` operator in expressions. + (accepted, question_mark, "1.13.0", Some(31436), None), + /// Allows keywords to be escaped for use as identifiers. + (accepted, raw_identifiers, "1.30.0", Some(48589), None), /// Allows relaxing the coherence rules such that /// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted. (accepted, re_rebalance_coherence, "1.41.0", Some(55437), None), - /// Allows #[repr(transparent)] on univariant enums (RFC 2645). - (accepted, transparent_enums, "1.42.0", Some(60405), None), + /// Allows numeric fields in struct expressions and patterns. + (accepted, relaxed_adts, "1.19.0", Some(35626), None), + /// Lessens the requirements for structs to implement `Unsize`. + (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None), + /// Allows `repr(align(16))` struct attribute (RFC 1358). + (accepted, repr_align, "1.25.0", Some(33626), None), + /// Allows using `#[repr(align(X))]` on enums with equivalent semantics + /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + (accepted, repr_align_enum, "1.37.0", Some(57996), None), + /// Allows `#[repr(packed(N))]` attribute on structs. + (accepted, repr_packed, "1.33.0", Some(33158), None), + /// Allows `#[repr(transparent)]` attribute on newtype structs. + (accepted, repr_transparent, "1.28.0", Some(43036), None), + /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), + /// Allows `Self` in type definitions (RFC 2300). + (accepted, self_in_typedefs, "1.32.0", Some(49303), None), + /// Allows `Self` struct constructor (RFC 2302). + (accepted, self_struct_ctor, "1.32.0", Some(51994), None), /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`. (accepted, slice_patterns, "1.42.0", Some(62254), None), - /// Allows the use of `if` and `match` in constants. - (accepted, const_if_match, "1.46.0", Some(49146), None), - /// Allows the use of `loop` and `while` in constants. - (accepted, const_loop, "1.46.0", Some(52000), None), + /// Allows use of `&foo[a..b]` as a slicing syntax. + (accepted, slicing_syntax, "1.0.0", None, None), + /// Allows elision of `'static` lifetimes in `static`s and `const`s. + (accepted, static_in_const, "1.17.0", Some(35897), None), + /// Allows the definition recursive static items. + (accepted, static_recursion, "1.17.0", Some(29719), None), + /// Allows attributes on struct literal fields. + (accepted, struct_field_attributes, "1.20.0", Some(38814), None), + /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + (accepted, struct_variant, "1.0.0", None, None), + /// Allows `#[target_feature(...)]`. + (accepted, target_feature, "1.27.0", None, None), + /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). + (accepted, termination_trait, "1.26.0", Some(43301), None), + /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + (accepted, termination_trait_test, "1.27.0", Some(48854), None), + /// Allows attributes scoped to tools. + (accepted, tool_attributes, "1.30.0", Some(44690), None), + /// Allows scoped lints. + (accepted, tool_lints, "1.31.0", Some(44690), None), /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809), None), - /// Allows `#[doc(alias = "...")]`. - (accepted, doc_alias, "1.48.0", Some(50146), None), - /// Allows patterns with concurrent by-move and by-ref bindings. - /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. - (accepted, move_ref_pattern, "1.49.0", Some(68354), None), - /// The smallest useful subset of const generics. - (accepted, min_const_generics, "1.51.0", Some(74878), None), + /// Allows #[repr(transparent)] on univariant enums (RFC 2645). + (accepted, transparent_enums, "1.42.0", Some(60405), None), + /// Allows indexing tuples. + (accepted, tuple_indexing, "1.0.0", None, None), + /// Allows paths to enum variants on type aliases including `Self`. + (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), + /// Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245), None), + /// Allows `const _: TYPE = VALUE`. + (accepted, underscore_const_names, "1.37.0", Some(54912), None), + /// Allows `use path as _;` and `extern crate c as _;`. + (accepted, underscore_imports, "1.33.0", Some(48216), None), + /// Allows `'_` placeholder lifetimes. + (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), + /// Allows `use x::y;` to search `x` in the current scope. + (accepted, uniform_paths, "1.32.0", Some(53130), None), + /// Allows `impl Trait` in function arguments. + (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + /// Allows arbitrary delimited token streams in non-macro attributes. + (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block. (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668), None), - /// Allows the use of or-patterns (e.g., `0 | 1`). - (accepted, or_patterns, "1.53.0", Some(54883), None), - /// Allows defining identifiers beyond ASCII. - (accepted, non_ascii_idents, "1.53.0", Some(55467), None), - /// Allows arbitrary expressions in key-value attributes at parse time. - (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None), - /// Allows unsizing coercions in `const fn`. - (accepted, const_fn_unsize, "1.54.0", Some(64992), None), - /// Allows `impl Trait` with multiple unrelated lifetimes. - (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.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. - (accepted, const_fn_union, "1.56.0", Some(51909), None), - /// Allows macro attributes to observe output of `#[derive]`. - (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), - /// Allows panicking during const eval (producing compile-time errors). - (accepted, const_panic, "1.57.0", Some(51999), None), - /// Lessens the requirements for structs to implement `Unsize`. - (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None), + /// Allows importing and reexporting macros with `use`, + /// enables macro modularization in general. + (accepted, use_extern_macros, "1.30.0", Some(35896), None), + /// Allows nested groups in `use` items (RFC 2128). + (accepted, use_nested_groups, "1.25.0", Some(44494), None), + /// Allows `#[used]` to preserve symbols (see llvm.compiler.used). + (accepted, used, "1.30.0", Some(40289), None), + /// Allows the use of `while let` expressions. + (accepted, while_let, "1.0.0", None, None), + /// Allows `#![windows_subsystem]`. + (accepted, windows_subsystem, "1.18.0", Some(37499), None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 0266b7844ba..608581306be 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -122,130 +122,101 @@ impl Feature { #[rustfmt::skip] declare_features! ( // ------------------------------------------------------------------------- - // feature-group-start: internal feature gates + // feature-group-start: internal feature gates (no tracking issue) // ------------------------------------------------------------------------- - // no-tracking-issue-start - /// Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", None, None), - - /// Allows using compiler's own crates. - (active, rustc_private, "1.0.0", Some(27812), None), - - /// Allows using the `rust-intrinsic`'s "ABI". - (active, intrinsics, "1.0.0", None, None), - - /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. - (active, lang_items, "1.0.0", None, None), - - /// Allows using the `#[stable]` and `#[unstable]` attributes. - (active, staged_api, "1.0.0", None, None), - - /// Allows using `#[allow_internal_unstable]`. This is an + /// Allows using the `thiscall` ABI. + (active, abi_thiscall, "1.19.0", None, None), + /// Allows using the `unadjusted` ABI; perma-unstable. + (active, abi_unadjusted, "1.16.0", None, None), + /// Allows using the `vectorcall` ABI. + (active, abi_vectorcall, "1.7.0", None, None), + /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + (active, allocator_internals, "1.20.0", None, None), + /// Allows using `#[allow_internal_unsafe]`. This is an /// attribute on `macro_rules!` and can't use the attribute handling /// below (it has to be checked before expansion possibly makes /// macros disappear). - (active, allow_internal_unstable, "1.0.0", None, None), - - /// Allows using `#[allow_internal_unsafe]`. This is an + (active, allow_internal_unsafe, "1.0.0", None, None), + /// Allows using `#[allow_internal_unstable]`. This is an /// attribute on `macro_rules!` and can't use the attribute handling /// below (it has to be checked before expansion possibly makes /// macros disappear). - (active, allow_internal_unsafe, "1.0.0", None, None), - - /// no-tracking-issue-end - - /// Allows using `#[link_name="llvm.*"]`. - (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - - /// Allows using the `box $expr` syntax. - (active, box_syntax, "1.0.0", Some(49733), None), - - /// Allows using `#[start]` on a function indicating that it is the program entrypoint. - (active, start, "1.0.0", Some(29633), None), - - /// Allows using the `#[fundamental]` attribute. - (active, fundamental, "1.0.0", Some(29635), None), - - /// Allows using the `rust-call` ABI. - (active, unboxed_closures, "1.0.0", Some(29625), None), - - /// Allows using the `#[linkage = ".."]` attribute. - (active, linkage, "1.0.0", Some(29603), None), - - /// Allows using `box` in patterns (RFC 469). - (active, box_patterns, "1.0.0", Some(29641), None), - - // no-tracking-issue-start - - /// Allows using `#[prelude_import]` on glob `use` items. - (active, prelude_import, "1.2.0", None, None), - - // no-tracking-issue-end - - // no-tracking-issue-start - - /// Allows using `#[omit_gdb_pretty_printer_section]`. - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - - /// Allows using the `vectorcall` ABI. - (active, abi_vectorcall, "1.7.0", None, None), - - // no-tracking-issue-end - - /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. - /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library - /// feature with the same name exists. - (active, structural_match, "1.8.0", Some(31434), None), - - /// Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - - /// Allows using the `#![panic_runtime]` attribute. - (active, panic_runtime, "1.10.0", Some(32837), None), - - /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. - (active, needs_panic_runtime, "1.10.0", Some(32837), None), - - // no-tracking-issue-start - + (active, allow_internal_unstable, "1.0.0", None, None), /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), - - /// Allows using the `unadjusted` ABI; perma-unstable. - (active, abi_unadjusted, "1.16.0", None, None), - + /// Allows using the `rust-intrinsic`'s "ABI". + (active, intrinsics, "1.0.0", None, None), + /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + (active, lang_items, "1.0.0", None, None), + /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`, + /// it is not on path for eventual stabilization). + (active, no_niche, "1.42.0", None, None), + /// Allows using `#[omit_gdb_pretty_printer_section]`. + (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + /// Allows using `#[prelude_import]` on glob `use` items. + (active, prelude_import, "1.2.0", None, None), /// Used to identify crates that contain the profiler runtime. (active, profiler_runtime, "1.18.0", None, None), - - /// Allows using the `thiscall` ABI. - (active, abi_thiscall, "1.19.0", None, None), - - /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. - (active, allocator_internals, "1.20.0", None, None), - + /// Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", None, None), + /// Allows using the `#[stable]` and `#[unstable]` attributes. + (active, staged_api, "1.0.0", None, None), /// Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! - /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`, - /// it is not on path for eventual stabilization). - (active, no_niche, "1.42.0", None, None), + // no-tracking-issue-end + // ------------------------------------------------------------------------- + // feature-group-end: internal feature gates (no tracking issue) + // ------------------------------------------------------------------------- - /// Allows using `#[rustc_allow_const_fn_unstable]`. - /// This is an attribute on `const fn` for the same - /// purpose as `#[allow_internal_unstable]`. - (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), + // ------------------------------------------------------------------------- + // feature-group-start: internal feature gates + // ------------------------------------------------------------------------- /// Allows features specific to auto traits. /// Renamed from `optin_builtin_traits`. (active, auto_traits, "1.50.0", Some(13231), None), - + /// Allows using `box` in patterns (RFC 469). + (active, box_patterns, "1.0.0", Some(29641), None), + /// Allows using the `box $expr` syntax. + (active, box_syntax, "1.0.0", Some(49733), None), /// Allows `#[doc(notable_trait)]`. /// Renamed from `doc_spotlight`. (active, doc_notable_trait, "1.52.0", Some(45040), None), - - // no-tracking-issue-end + /// Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + /// Allows using the `#[fundamental]` attribute. + (active, fundamental, "1.0.0", Some(29635), None), + /// Allows using `#[link_name="llvm.*"]`. + (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), + /// Allows using the `#[linkage = ".."]` attribute. + (active, linkage, "1.0.0", Some(29603), None), + /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + (active, needs_panic_runtime, "1.10.0", Some(32837), None), + /// Allows using the `#![panic_runtime]` attribute. + (active, panic_runtime, "1.10.0", Some(32837), None), + /// Allows using `#[rustc_allow_const_fn_unstable]`. + /// This is an attribute on `const fn` for the same + /// purpose as `#[allow_internal_unstable]`. + (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), + /// Allows using compiler's own crates. + (active, rustc_private, "1.0.0", Some(27812), None), + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. + (active, start, "1.0.0", Some(29633), None), + /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. + /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library + /// feature with the same name exists. + (active, structural_match, "1.8.0", Some(31434), None), + /// Allows using the `rust-call` ABI. + (active, unboxed_closures, "1.0.0", Some(29625), None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: internal feature gates @@ -258,23 +229,26 @@ declare_features! ( // FIXME: Document these and merge with the list below. // Unstable `#[target_feature]` directives. - (active, arm_target_feature, "1.27.0", Some(44839), None), (active, aarch64_target_feature, "1.27.0", Some(44839), None), + (active, adx_target_feature, "1.32.0", Some(44839), None), + (active, arm_target_feature, "1.27.0", Some(44839), None), + (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, bpf_target_feature, "1.54.0", Some(44839), None), + (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), + (active, ermsb_target_feature, "1.49.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, powerpc_target_feature, "1.27.0", Some(44839), None), + (active, riscv_target_feature, "1.45.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), (active, sse4a_target_feature, "1.27.0", Some(44839), None), (active, tbm_target_feature, "1.27.0", Some(44839), None), (active, wasm_target_feature, "1.30.0", Some(44839), None), - (active, adx_target_feature, "1.32.0", Some(44839), None), - (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), - (active, rtm_target_feature, "1.35.0", Some(44839), None), - (active, f16c_target_feature, "1.36.0", Some(44839), None), - (active, riscv_target_feature, "1.45.0", Some(44839), None), - (active, ermsb_target_feature, "1.49.0", Some(44839), None), - (active, bpf_target_feature, "1.54.0", Some(44839), None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: actual feature gates (target features) @@ -284,422 +258,287 @@ declare_features! ( // feature-group-start: actual feature gates // ------------------------------------------------------------------------- - /// Allows using `#![plugin(myplugin)]`. - (active, plugin, "1.0.0", Some(29597), None), - - /// Allows using `#[thread_local]` on `static` items. - (active, thread_local, "1.0.0", Some(29594), None), - - /// Allows the use of SIMD types in functions declared in `extern` blocks. - (active, simd_ffi, "1.0.0", Some(27731), None), - - /// Allows using non lexical lifetimes (RFC 2094). - (active, nll, "1.0.0", Some(43234), None), - - /// Allows associated type defaults. - (active, associated_type_defaults, "1.2.0", Some(29661), None), - - /// Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), - - /// Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - - /// Allows `repr(simd)` and importing the various simd intrinsics. - (active, repr_simd, "1.4.0", Some(27731), None), - - /// Allows `extern "platform-intrinsic" { ... }`. - (active, platform_intrinsics, "1.4.0", Some(27731), None), - - /// Allows attributes on expressions and non-item statements. - (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - - /// Allows the use of type ascription in expressions. - (active, type_ascription, "1.6.0", Some(23416), None), - - /// Allows `cfg(target_thread_local)`. - (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - - /// Allows specialization of implementations (RFC 1210). - (incomplete, specialization, "1.7.0", Some(31844), None), - - /// A minimal, sound subset of specialization intended to be used by the - /// standard library until the soundness issues with specialization - /// are fixed. - (active, min_specialization, "1.7.0", Some(31844), None), - - /// Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - - /// Allows `cfg(target_has_atomic = "...")`. - (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - - /// Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - - /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - - /// Allows exhaustive pattern matching on types that contain uninhabited types. - (active, exhaustive_patterns, "1.13.0", Some(51085), None), - - /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields - /// that don't implement `Copy` as long as they don't have any drop glue. - /// This is checked recursively. On encountering type variable where no progress can be made, - /// `T: Copy` is used as a substitute for "no drop glue". - /// - /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. - (active, untagged_unions, "1.13.0", Some(55149), None), - - /// Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), - - /// Allows `extern "ptx-*" fn()`. - (active, abi_ptx, "1.15.0", Some(38788), None), - - /// Allows the `#[repr(i128)]` attribute for enums. - (incomplete, repr128, "1.16.0", Some(56071), None), - - /// Allows `#[link(kind="static-nobundle"...)]`. - (active, static_nobundle, "1.16.0", Some(37403), None), - + /// Allows using the `amdgpu-kernel` ABI. + (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), + /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. + (active, abi_avr_interrupt, "1.45.0", Some(69664), None), + /// Allows `extern "C-cmse-nonsecure-call" fn()`. + (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), + /// Allows using the `efiapi` ABI. + (active, abi_efiapi, "1.40.0", Some(65815), None), /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - - /// Allows declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), - + /// Allows `extern "ptx-*" fn()`. + (active, abi_ptx, "1.15.0", Some(38788), None), /// Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - + /// Allows additional const parameter types, such as `&'static str` or user defined types + (incomplete, adt_const_params, "1.56.0", Some(44580), None), + /// Allows defining an `#[alloc_error_handler]`. + (active, alloc_error_handler, "1.29.0", Some(51540), None), /// Allows a test to fail without failing the whole suite. (active, allow_fail, "1.19.0", Some(46488), None), - - /// Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - - /// Allows defining generators. - (active, generators, "1.21.0", Some(43122), None), - - /// Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), - - /// Allows `#[doc(masked)]`. - (active, doc_masked, "1.21.0", Some(44027), None), - - /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - - /// Allows defining `extern type`s. - (active, extern_types, "1.23.0", Some(43467), None), - + /// Allows explicit discriminants on non-unit enum variants. + (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), - - /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (active, in_band_lifetimes, "1.23.0", Some(44524), None), - - /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), - - /// Allows defining `trait X = A + B;` alias items. - (active, trait_alias, "1.24.0", Some(41517), None), - - /// Allows inferring `'static` outlives requirements (RFC 2093). - (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - - /// Allows dereferencing raw pointers during const eval. - (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - - /// Allows inconsistent bounds in where clauses. - (active, trivial_bounds, "1.28.0", Some(48214), None), - - /// Allows `'a: { break 'a; }`. - (active, label_break_value, "1.28.0", Some(48594), None), - - /// Allows using `#[doc(keyword = "...")]`. - (active, doc_keyword, "1.28.0", Some(51315), None), - - /// Allows using `try {...}` expressions. - (active, try_blocks, "1.29.0", Some(31436), None), - - /// Allows defining an `#[alloc_error_handler]`. - (active, alloc_error_handler, "1.29.0", Some(51540), None), - - /// Allows using the `amdgpu-kernel` ABI. - (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - - /// Allows `#[marker]` on certain traits allowing overlapping implementations. - (active, marker_trait_attr, "1.30.0", Some(29864), None), - - /// Allows macro attributes on expressions, statements and non-inline modules. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - - /// Allows unsized rvalues at arguments and parameters. - (incomplete, unsized_locals, "1.30.0", Some(48055), None), - - /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. - (active, custom_test_frameworks, "1.30.0", Some(50297), None), - - /// Allows non-builtin attributes in inner attribute position. - (active, custom_inner_attributes, "1.30.0", Some(54726), None), - - /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (active, lint_reasons, "1.31.0", Some(54503), None), - - /// Allows exhaustive integer pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - - /// Allows using `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), - - /// Allows using `#[optimize(X)]`. - (active, optimize_attribute, "1.34.0", Some(54882), None), - - /// Allows using C-variadics. - (active, c_variadic, "1.34.0", Some(44930), None), - + /// Allows using `const` operands in inline assembly. + (active, asm_const, "1.58.0", Some(72016), None), + /// Enables experimental inline assembly support for additional architectures. + (active, asm_experimental_arch, "1.58.0", Some(72016), None), + /// Allows using `sym` operands in inline assembly. + (active, asm_sym, "1.58.0", Some(72016), None), /// Allows the user of associated type bounds. (active, associated_type_bounds, "1.34.0", Some(52662), None), - - /// Allows `if/while p && let q = r && ...` chains. - (incomplete, let_chains, "1.37.0", Some(53667), None), - - /// Allows #[repr(transparent)] on unions (RFC 2645). - (active, transparent_unions, "1.37.0", Some(60405), None), - - /// Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - + /// Allows associated type defaults. + (active, associated_type_defaults, "1.2.0", Some(29661), None), /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), - - /// Allows `impl Trait` to be used inside type aliases (RFC 2515). - (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - - /// Allows the definition of `const extern fn` and `const unsafe extern fn`. - (active, const_extern_fn, "1.40.0", Some(64926), None), - - /// Allows the use of raw-dylibs (RFC 2627). - (incomplete, raw_dylib, "1.40.0", Some(58713), None), - - /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. - /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and - /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. - (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), - - /// Allows using the `efiapi` ABI. - (active, abi_efiapi, "1.40.0", Some(65815), None), - - /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. - (active, raw_ref_op, "1.41.0", Some(64490), None), - - /// Allows diverging expressions to fall back to `!` rather than `()`. - (active, never_type_fallback, "1.41.0", Some(65992), None), - - /// Allows using the `#[register_attr]` attribute. - (active, register_attr, "1.41.0", Some(66080), None), - - /// Allows using the `#[register_tool]` attribute. - (active, register_tool, "1.41.0", Some(66079), None), - + /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries. + (active, c_unwind, "1.52.0", Some(74990), None), + /// Allows using C-variadics. + (active, c_variadic, "1.34.0", Some(44930), None), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), + /// Enables `#[cfg(panic = "...")]` config key. + (active, cfg_panic, "1.49.0", Some(77443), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), - - /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern. - (active, half_open_range_patterns, "1.41.0", Some(67264), None), - - /// Allows using `&mut` in constant functions. - (active, const_mut_refs, "1.41.0", Some(57349), None), - - /// Allows `impl const Trait for T` syntax. - (active, const_trait_impl, "1.42.0", Some(67792), None), - - /// Allows the use of `no_sanitize` attribute. - (active, no_sanitize, "1.42.0", Some(39699), None), - - // Allows limiting the evaluation steps of const expressions - (active, const_eval_limit, "1.43.0", Some(67217), None), - - /// Allow negative trait implementations. - (active, negative_impls, "1.44.0", Some(68318), None), - - /// Allows the use of `#[target_feature]` on safe functions. - (active, target_feature_11, "1.45.0", Some(69098), None), - + /// Allows `cfg(target_abi = "...")`. + (active, cfg_target_abi, "1.55.0", Some(80970), None), + /// Allows `cfg(target_has_atomic = "...")`. + (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + /// Allows `cfg(target_thread_local)`. + (active, cfg_target_thread_local, "1.7.0", Some(29594), None), /// Allow conditional compilation depending on rust version (active, cfg_version, "1.45.0", Some(64796), None), - - /// Allows the use of `#[ffi_pure]` on foreign functions. - (active, ffi_pure, "1.45.0", Some(58329), None), - - /// Allows the use of `#[ffi_const]` on foreign functions. - (active, ffi_const, "1.45.0", Some(58328), None), - - /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. - (active, abi_avr_interrupt, "1.45.0", Some(69664), None), - - /// Be more precise when looking for live drops in a const context. - (active, const_precise_live_drops, "1.46.0", Some(73255), None), - - /// Allows capturing variables in scope using format_args! - (active, format_args_capture, "1.46.0", Some(67984), None), - - /// Allows `if let` guard in match arms. - (active, if_let_guard, "1.47.0", Some(51114), None), - + /// Allows `#[track_caller]` on closures and generators. + (active, closure_track_caller, "1.57.0", Some(87417), None), + /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + /// Allows `async {}` expressions in const contexts. + (active, const_async_blocks, "1.53.0", Some(85368), None), + // Allows limiting the evaluation steps of const expressions + (active, const_eval_limit, "1.43.0", Some(67217), None), + /// Allows the definition of `const extern fn` and `const unsafe extern fn`. + (active, const_extern_fn, "1.40.0", Some(64926), None), /// Allows basic arithmetic on floating point types in a `const fn`. (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), - /// Allows using and casting function pointers in a `const fn`. (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None), - - /// Allows to use the `#[cmse_nonsecure_entry]` attribute. - (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), - - /// Allows rustc to inject a default alloc_error_handler - (active, default_alloc_error_handler, "1.48.0", Some(66741), None), - - /// Allows argument and return position `impl Trait` in a `const fn`. - (active, const_impl_trait, "1.48.0", Some(77463), None), - - /// Allows `#[instruction_set(_)]` attribute - (active, isa_attribute, "1.48.0", Some(74727), None), - - /// Allow anonymous constants from an inline `const` block - (incomplete, inline_const, "1.49.0", Some(76001), None), - - /// Allows unsized fn parameters. - (active, unsized_fn_params, "1.49.0", Some(48055), None), - - /// Allows the use of destructuring assignments. - (active, destructuring_assignment, "1.49.0", Some(71126), None), - - /// Enables `#[cfg(panic = "...")]` config key. - (active, cfg_panic, "1.49.0", Some(77443), None), - - /// Allows capturing disjoint fields in a closure/generator (RFC 2229). - (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), - + /// Allows trait bounds in `const fn`. + (active, const_fn_trait_bound, "1.53.0", Some(57563), None), + /// Allows `for _ in _` loops in const contexts. + (active, const_for, "1.56.0", Some(87575), None), /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`). (active, const_generics_defaults, "1.51.0", Some(44580), None), - + /// Allows argument and return position `impl Trait` in a `const fn`. + (active, const_impl_trait, "1.48.0", Some(77463), None), + /// Allows using `&mut` in constant functions. + (active, const_mut_refs, "1.41.0", Some(57349), None), + /// Be more precise when looking for live drops in a const context. + (active, const_precise_live_drops, "1.46.0", Some(73255), None), /// Allows references to types with interior mutability within constants (active, const_refs_to_cell, "1.51.0", Some(80384), None), - - /// Allows using `pointer` and `reference` in intra-doc links - (active, intra_doc_pointers, "1.51.0", Some(80896), None), - - /// Allows `extern "C-cmse-nonsecure-call" fn()`. - (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), - - /// Allows associated types in inherent impls. - (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), - - // Allows setting the threshold for the `large_assignments` lint. - (active, large_assignments, "1.52.0", Some(83518), None), - - /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries. - (active, c_unwind, "1.52.0", Some(74990), None), - + /// Allows `impl const Trait for T` syntax. + (active, const_trait_impl, "1.42.0", Some(67792), None), + /// Allows the `?` operator in const contexts. + (active, const_try, "1.56.0", Some(74935), None), + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + (active, crate_visibility_modifier, "1.23.0", Some(53120), None), + /// Allows non-builtin attributes in inner attribute position. + (active, custom_inner_attributes, "1.30.0", Some(54726), None), + /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + (active, custom_test_frameworks, "1.30.0", Some(50297), None), + /// Allows declarative macros 2.0 (`macro`). + (active, decl_macro, "1.17.0", Some(39412), None), + /// Allows rustc to inject a default alloc_error_handler + (active, default_alloc_error_handler, "1.48.0", Some(66741), None), + /// Allows default type parameters to influence type inference. + (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + /// Allows `#[derive(Default)]` and `#[default]` on enums. + (active, derive_default_enum, "1.56.0", Some(86985), None), + /// Allows the use of destructuring assignments. + (active, destructuring_assignment, "1.49.0", Some(71126), None), + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (active, doc_auto_cfg, "1.58.0", Some(43781), None), + /// Allows `#[doc(cfg(...))]`. + (active, doc_cfg, "1.21.0", Some(43781), None), + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.57.0", Some(43781), None), + /// Allows using `#[doc(keyword = "...")]`. + (active, doc_keyword, "1.28.0", Some(51315), None), + /// Allows `#[doc(masked)]`. + (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows using doc(primitive) without a future-incompat warning + (active, doc_primitive, "1.56.0", Some(88070), None), + /// Allows `X..Y` patterns. + (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + /// Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", Some(51085), None), + /// Allows explicit generic arguments specification with `impl Trait` present. + (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None), + /// Allows defining `extern type`s. + (active, extern_types, "1.23.0", Some(43467), None), + /// Allows the use of `#[ffi_const]` on foreign functions. + (active, ffi_const, "1.45.0", Some(58328), None), + /// Allows the use of `#[ffi_pure]` on foreign functions. + (active, ffi_pure, "1.45.0", Some(58329), None), + /// Allows using `#[ffi_returns_twice]` on foreign functions. + (active, ffi_returns_twice, "1.34.0", Some(58314), None), /// Allows using `#[repr(align(...))]` on function items (active, fn_align, "1.53.0", Some(82232), None), - - /// Allows `extern "wasm" fn` - (active, wasm_abi, "1.53.0", Some(83788), None), - - /// Allows function attribute `#[no_coverage]`, to bypass coverage - /// instrumentation of that function. - (active, no_coverage, "1.53.0", Some(84605), None), - - /// Allows trait bounds in `const fn`. - (active, const_fn_trait_bound, "1.53.0", Some(57563), None), - - /// Allows `async {}` expressions in const contexts. - (active, const_async_blocks, "1.53.0", Some(85368), None), - + /// Allows defining generators. + (active, generators, "1.21.0", Some(43122), None), + /// Infer generic args for both consts and types. + (active, generic_arg_infer, "1.55.0", Some(85077), None), + /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598). + (active, generic_associated_types, "1.23.0", Some(44265), None), + /// Allows non-trivial generic constants which have to have wfness manually propagated to callers + (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), + /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern. + (active, half_open_range_patterns, "1.41.0", Some(67264), None), + /// Allows `if let` guard in match arms. + (active, if_let_guard, "1.47.0", Some(51114), None), /// Allows using imported `main` function (active, imported_main, "1.53.0", Some(28937), None), - + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + (active, in_band_lifetimes, "1.23.0", Some(44524), None), + /// Allows inferring `'static` outlives requirements (RFC 2093). + (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), + /// Allows associated types in inherent impls. + (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), + /// Allow anonymous constants from an inline `const` block + (incomplete, inline_const, "1.49.0", Some(76001), None), + /// Allows using `pointer` and `reference` in intra-doc links + (active, intra_doc_pointers, "1.51.0", Some(80896), None), + /// Allows `#[instruction_set(_)]` attribute + (active, isa_attribute, "1.48.0", Some(74727), None), + /// Allows `'a: { break 'a; }`. + (active, label_break_value, "1.28.0", Some(48594), None), + // Allows setting the threshold for the `large_assignments` lint. + (active, large_assignments, "1.52.0", Some(83518), None), + /// Allows `if/while p && let q = r && ...` chains. + (incomplete, let_chains, "1.37.0", Some(53667), None), + /// Allows `let...else` statements. + (active, let_else, "1.56.0", Some(87335), None), + /// Allows `#[link(..., cfg(..))]`. + (active, link_cfg, "1.14.0", Some(37406), None), + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + (active, lint_reasons, "1.31.0", Some(54503), None), + /// Allows `#[marker]` on certain traits allowing overlapping implementations. + (active, marker_trait_attr, "1.30.0", Some(29864), None), + /// A minimal, sound subset of specialization intended to be used by the + /// standard library until the soundness issues with specialization + /// are fixed. + (active, min_specialization, "1.7.0", Some(31844), None), + /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. + (active, more_qualified_paths, "1.54.0", Some(86935), None), + /// Allows the `#[must_not_suspend]` attribute. + (active, must_not_suspend, "1.57.0", Some(83310), None), + /// Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` (active, native_link_modifiers, "1.53.0", Some(81490), None), - + /// Allows specifying the as-needed link modifier + (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allows specifying the bundle link modifier (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None), - /// Allows specifying the verbatim link modifier (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None), - /// Allows specifying the whole-archive link modifier (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None), - - /// Allows specifying the as-needed link modifier - (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), - - /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. - (active, more_qualified_paths, "1.54.0", Some(86935), None), - - /// Allows `cfg(target_abi = "...")`. - (active, cfg_target_abi, "1.55.0", Some(80970), None), - - /// Infer generic args for both consts and types. - (active, generic_arg_infer, "1.55.0", Some(85077), None), - - /// Allows `#[derive(Default)]` and `#[default]` on enums. - (active, derive_default_enum, "1.56.0", Some(86985), None), - - /// Allows `for _ in _` loops in const contexts. - (active, const_for, "1.56.0", Some(87575), None), - - /// Allows the `?` operator in const contexts. - (active, const_try, "1.56.0", Some(74935), None), - + /// Allow negative trait implementations. + (active, negative_impls, "1.44.0", Some(68318), None), + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + /// Allows diverging expressions to fall back to `!` rather than `()`. + (active, never_type_fallback, "1.41.0", Some(65992), None), + /// Allows using non lexical lifetimes (RFC 2094). + (active, nll, "1.0.0", Some(43234), None), + /// Allows `#![no_core]`. + (active, no_core, "1.3.0", Some(29639), None), + /// Allows function attribute `#[no_coverage]`, to bypass coverage + /// instrumentation of that function. + (active, no_coverage, "1.53.0", Some(84605), None), + /// Allows the use of `no_sanitize` attribute. + (active, no_sanitize, "1.42.0", Some(39699), None), + /// Allows using the `non_exhaustive_omitted_patterns` lint. + (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), + /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. + /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and + /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. + (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), + /// Allows using `#[optimize(X)]`. + (active, optimize_attribute, "1.34.0", Some(54882), None), + /// Allows `extern "platform-intrinsic" { ... }`. + (active, platform_intrinsics, "1.4.0", Some(27731), None), + /// Allows using `#![plugin(myplugin)]`. + (active, plugin, "1.0.0", Some(29597), None), + /// Allows exhaustive integer pattern matching on `usize` and `isize`. + (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), + /// Allows macro attributes on expressions, statements and non-inline modules. + (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + /// Allows the use of raw-dylibs (RFC 2627). + (incomplete, raw_dylib, "1.40.0", Some(58713), None), + /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. + (active, raw_ref_op, "1.41.0", Some(64490), None), + /// Allows using the `#[register_attr]` attribute. + (active, register_attr, "1.41.0", Some(66080), None), + /// Allows using the `#[register_tool]` attribute. + (active, register_tool, "1.41.0", Some(66079), None), + /// Allows the `#[repr(i128)]` attribute for enums. + (incomplete, repr128, "1.16.0", Some(56071), None), + /// Allows `repr(simd)` and importing the various simd intrinsics. + (active, repr_simd, "1.4.0", Some(27731), None), + /// Allows the use of SIMD types in functions declared in `extern` blocks. + (active, simd_ffi, "1.0.0", Some(27731), None), + /// Allows specialization of implementations (RFC 1210). + (incomplete, specialization, "1.7.0", Some(31844), None), + /// Allows `#[link(kind="static-nobundle"...)]`. + (active, static_nobundle, "1.16.0", Some(37403), None), + /// Allows attributes on expressions and non-item statements. + (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + /// Allows the use of `#[target_feature]` on safe functions. + (active, target_feature_11, "1.45.0", Some(69098), None), + /// Allows using `#[thread_local]` on `static` items. + (active, thread_local, "1.0.0", Some(29594), None), + /// Allows defining `trait X = A + B;` alias items. + (active, trait_alias, "1.24.0", Some(41517), None), /// Allows upcasting trait objects via supertraits. /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. (incomplete, trait_upcasting, "1.56.0", Some(65991), None), - - /// Allows explicit generic arguments specification with `impl Trait` present. - (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None), - - /// Allows using doc(primitive) without a future-incompat warning - (active, doc_primitive, "1.56.0", Some(88070), None), - - /// Allows non-trivial generic constants which have to have wfness manually propagated to callers - (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), - - /// Allows additional const parameter types, such as `&'static str` or user defined types - (incomplete, adt_const_params, "1.56.0", Some(44580), None), - - /// Allows `let...else` statements. - (active, let_else, "1.56.0", Some(87335), None), - - /// Allows the `#[must_not_suspend]` attribute. - (active, must_not_suspend, "1.57.0", Some(83310), None), - - /// Allows `#[track_caller]` on closures and generators. - (active, closure_track_caller, "1.57.0", Some(87417), None), - - /// 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), - + /// Allows #[repr(transparent)] on unions (RFC 2645). + (active, transparent_unions, "1.37.0", Some(60405), None), + /// Allows inconsistent bounds in where clauses. + (active, trivial_bounds, "1.28.0", Some(48214), None), + /// Allows using `try {...}` expressions. + (active, try_blocks, "1.29.0", Some(31436), None), + /// Allows `impl Trait` to be used inside type aliases (RFC 2515). + (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + /// Allows the use of type ascription in expressions. + (active, type_ascription, "1.6.0", Some(23416), None), /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None), - - /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (active, doc_auto_cfg, "1.58.0", Some(43781), None), - - /// Allows using `const` operands in inline assembly. - (active, asm_const, "1.58.0", Some(72016), None), - - /// Allows using `sym` operands in inline assembly. - (active, asm_sym, "1.58.0", Some(72016), None), - - /// Enables experimental inline assembly support for additional architectures. - (active, asm_experimental_arch, "1.58.0", Some(72016), None), + /// Allows unsized fn parameters. + (active, unsized_fn_params, "1.49.0", Some(48055), None), + /// Allows unsized rvalues at arguments and parameters. + (incomplete, unsized_locals, "1.30.0", Some(48055), None), + /// Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), + /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields + /// that don't implement `Copy` as long as they don't have any drop glue. + /// This is checked recursively. On encountering type variable where no progress can be made, + /// `T: Copy` is used as a substitute for "no drop glue". + /// + /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. + (active, untagged_unions, "1.13.0", Some(55149), None), + /// Allows `extern "wasm" fn` + (active, wasm_abi, "1.53.0", Some(83788), None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 33188d375f5..7212bbf38c7 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -115,16 +115,26 @@ macro_rules! template { macro_rules! ungated { ($attr:ident, $typ:expr, $tpl:expr $(,)?) => { - (sym::$attr, $typ, $tpl, Ungated) + BuiltinAttribute { name: sym::$attr, type_: $typ, template: $tpl, gate: Ungated } }; } macro_rules! gated { ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { - (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) + BuiltinAttribute { + name: sym::$attr, + type_: $typ, + template: $tpl, + gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + } }; ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { - (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) + BuiltinAttribute { + name: sym::$attr, + type_: $typ, + template: $tpl, + gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + } }; } @@ -143,12 +153,12 @@ macro_rules! rustc_attr { ) }; ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { - ( - sym::$attr, - $typ, - $tpl, - Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), - ) + BuiltinAttribute { + name: sym::$attr, + type_: $typ, + template: $tpl, + gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), + } }; } @@ -161,7 +171,12 @@ macro_rules! experimental { const IMPL_DETAIL: &str = "internal implementation detail"; const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; -pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); +pub struct BuiltinAttribute { + pub name: Symbol, + pub type_: AttributeType, + pub template: AttributeTemplate, + pub gate: AttributeGate, +} /// Attributes that have a special meaning to rustc or rustdoc. #[rustfmt::skip] @@ -290,9 +305,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Plugins: - ( - sym::plugin, CrateLevel, template!(List: "name"), - Gated( + BuiltinAttribute { + name: sym::plugin, + type_: CrateLevel, + template: template!(List: "name"), + gate: Gated( Stability::Deprecated( "https://github.com/rust-lang/rust/pull/64675", Some("may be removed in a future compiler version"), @@ -300,8 +317,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ sym::plugin, "compiler plugins are deprecated", cfg_fn!(plugin) - ) - ), + ), + }, // Testing: gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)), @@ -497,17 +514,17 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ lang, Normal, template!(NameValueStr: "name"), lang_items, "language items are subject to change", ), - ( - sym::rustc_diagnostic_item, - Normal, - template!(NameValueStr: "name"), - Gated( + BuiltinAttribute { + name: sym::rustc_diagnostic_item, + type_: Normal, + template: template!(NameValueStr: "name"), + gate: Gated( Stability::Unstable, sym::rustc_attrs, "diagnostic items compiler internal support for linting", cfg_fn!(rustc_attrs), ), - ), + }, gated!( // Used in resolve: prelude_import, Normal, template!(Word), @@ -601,7 +618,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ]; pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { - BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() + BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect() } pub fn is_builtin_attr_name(name: Symbol) -> bool { @@ -612,8 +629,8 @@ pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> SyncLazy::new(|| { let mut map = FxHashMap::default(); for attr in BUILTIN_ATTRIBUTES.iter() { - if map.insert(attr.0, attr).is_some() { - panic!("duplicate builtin attribute `{}`", attr.0); + if map.insert(attr.name, attr).is_some() { + panic!("duplicate builtin attribute `{}`", attr.name); } } map diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 7b9b68268ea..4b40040a036 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -45,132 +45,130 @@ declare_features! ( // feature-group-start: removed features // ------------------------------------------------------------------------- - (removed, import_shadowing, "1.0.0", None, None, None), - (removed, managed_boxes, "1.0.0", None, None, None), - /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 - (removed, negate_unsigned, "1.0.0", Some(29645), None, None), - (removed, reflect, "1.0.0", Some(27749), None, None), - /// A way to temporarily opt out of opt in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None, None), - (removed, quad_precision_float, "1.0.0", None, None, None), - (removed, struct_inherit, "1.0.0", None, None, None), - (removed, test_removed_feature, "1.0.0", None, None, None), - (removed, visible_private_types, "1.0.0", None, None, None), - (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - /// Allows using items which are missing stability attributes - (removed, unmarked_api, "1.0.0", None, None, None), - (removed, allocator, "1.0.0", None, None, None), - (removed, simd, "1.0.0", Some(27731), None, - Some("removed in favor of `#[repr(simd)]`")), (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, Some("merged into `#![feature(slice_patterns)]`")), - (removed, macro_reexport, "1.0.0", Some(29638), None, - Some("subsumed by `pub use`")), + (removed, allocator, "1.0.0", None, None, None), + (removed, await_macro, "1.38.0", Some(50547), None, + Some("subsumed by `.await` syntax")), + /// Allows comparing raw pointers during const eval. + (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, + Some("cannot be allowed in const eval in any meaningful way")), + /// Allows non-trivial generic constants which have to be manually propagated upwards. + (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")), + /// Allows the definition of `const` functions with some advanced features. + (removed, const_fn, "1.54.0", Some(57563), None, + Some("split into finer-grained feature gates")), + /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`). + (removed, const_generics, "1.34.0", Some(44580), None, + Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")), + /// Allows `[x; N]` where `x` is a constant (RFC 2203). + (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None, + Some("removed due to causing promotable bugs")), + /// Allows casting raw pointers to `usize` during const eval. + (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None, + Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")), + /// Allows `T: ?const Trait` syntax in bounds. + (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None, + Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")), /// Allows using custom attributes (RFC 572). (removed, custom_attribute, "1.0.0", Some(29642), None, Some("removed in favor of `#![register_tool]` and `#![register_attr]`")), - /// Allows features specific to OIBIT (now called auto traits). - /// Renamed to `auto_traits`. - (removed, optin_builtin_traits, "1.0.0", Some(13231), None, - Some("renamed to `auto_traits`")), - (removed, pushpop_unsafe, "1.2.0", None, None, None), - (removed, needs_allocator, "1.4.0", Some(27389), None, - Some("subsumed by `#![feature(allocator_internals)]`")), - /// Allows identifying crates that contain sanitizer runtimes. - (removed, sanitizer_runtime, "1.17.0", None, None, None), + /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + (removed, custom_derive, "1.32.0", Some(29644), None, + Some("subsumed by `#[proc_macro_derive]`")), /// Allows `#[doc(spotlight)]`. /// The attribute was renamed to `#[doc(notable_trait)]` /// and the feature to `doc_notable_trait`. (removed, doc_spotlight, "1.22.0", Some(45040), None, Some("renamed to `doc_notable_trait`")), - (removed, proc_macro_mod, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_expr, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_non_items, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_gen, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, panic_implementation, "1.28.0", Some(44489), None, - Some("subsumed by `#[panic_handler]`")), - /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.32.0", Some(29644), None, - Some("subsumed by `#[proc_macro_derive]`")), - /// Paths of the form: `extern::foo::bar` - (removed, extern_in_paths, "1.33.0", Some(55600), None, - Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.33.0", Some(29601), None, None), - /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`). - (removed, const_generics, "1.34.0", Some(44580), None, - Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")), - /// Allows `[x; N]` where `x` is a constant (RFC 2203). - (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None, - Some("removed due to causing promotable bugs")), /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), - (removed, await_macro, "1.38.0", Some(50547), None, - Some("subsumed by `.await` syntax")), /// Allows defining `existential type`s. (removed, existential_type, "1.38.0", Some(63063), None, Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), - /// Allows using the macros: - /// + `__diagnostic_used` - /// + `__register_diagnostic` - /// +`__build_diagnostic_array` - (removed, rustc_diagnostic_macros, "1.38.0", None, None, None), - /// Allows using `#[on_unimplemented(..)]` on traits. - /// (Moved to `rustc_attrs`.) - (removed, on_unimplemented, "1.40.0", None, None, None), - /// Allows overlapping impls of marker traits. - (removed, overlapping_marker_traits, "1.42.0", Some(29864), None, - Some("removed in favor of `#![feature(marker_trait_attr)]`")), - /// Allows `T: ?const Trait` syntax in bounds. - (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None, - Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")), - /// Allows `#[no_debug]`. - (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), + /// Paths of the form: `extern::foo::bar` + (removed, extern_in_paths, "1.33.0", Some(55600), None, + Some("subsumed by `::foo::bar` paths")), + /// Allows `#[doc(include = "some-file")]`. + (removed, external_doc, "1.54.0", Some(44732), None, + Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), + /// Allows `impl Trait` in bindings (`let`, `const`, `static`). + (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None, + Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")), + (removed, import_shadowing, "1.0.0", None, None, None), /// Lazily evaluate constants. This allows constants to depend on type parameters. (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")), - /// Allows comparing raw pointers during const eval. - (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, - Some("cannot be allowed in const eval in any meaningful way")), - /// Allows non-trivial generic constants which have to be manually propagated upwards. - (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")), /// Allows using the `#[link_args]` attribute. (removed, link_args, "1.53.0", Some(29596), None, Some("removed in favor of using `-C link-arg=ARG` on command line, \ which is available from cargo build scripts with `cargo:rustc-link-arg` now")), + (removed, macro_reexport, "1.0.0", Some(29638), None, + Some("subsumed by `pub use`")), /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. (removed, main, "1.53.0", Some(29634), None, None), - (removed, pub_macro_rules, "1.53.0", Some(78855), None, - Some("removed due to being incomplete, in particular it does not work across crates")), - /// Allows the definition of `const` functions with some advanced features. - (removed, const_fn, "1.54.0", Some(57563), None, - Some("split into finer-grained feature gates")), - /// Allows using `#[plugin_registrar]` on functions. - (removed, plugin_registrar, "1.54.0", Some(29597), None, - Some("a __rustc_plugin_registrar symbol must now be defined instead")), - - /// Allows `#[doc(include = "some-file")]`. - (removed, external_doc, "1.54.0", Some(44732), None, - Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), - - /// Allows casting raw pointers to `usize` during const eval. - (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), None, - Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")), - - /// Allows `impl Trait` in bindings (`let`, `const`, `static`). - (removed, impl_trait_in_bindings, "1.55.0", Some(63065), None, - Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")), - + (removed, managed_boxes, "1.0.0", None, None, None), /// Allows the use of type alias impl trait in function return positions (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None, Some("removed in favor of full type_alias_impl_trait")), - + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), + /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + (removed, negate_unsigned, "1.0.0", Some(29645), None, None), + /// Allows `#[no_debug]`. + (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), + /// Allows using `#[on_unimplemented(..)]` on traits. + /// (Moved to `rustc_attrs`.) + (removed, on_unimplemented, "1.40.0", None, None, None), + /// A way to temporarily opt out of opt in copy. This will *never* be accepted. + (removed, opt_out_copy, "1.0.0", None, None, None), + /// Allows features specific to OIBIT (now called auto traits). + /// Renamed to `auto_traits`. + (removed, optin_builtin_traits, "1.0.0", Some(13231), None, + Some("renamed to `auto_traits`")), + /// Allows overlapping impls of marker traits. + (removed, overlapping_marker_traits, "1.42.0", Some(29864), None, + Some("removed in favor of `#![feature(marker_trait_attr)]`")), + (removed, panic_implementation, "1.28.0", Some(44489), None, + Some("subsumed by `#[panic_handler]`")), + /// Allows using `#[plugin_registrar]` on functions. + (removed, plugin_registrar, "1.54.0", Some(29597), None, + Some("a __rustc_plugin_registrar symbol must now be defined instead")), + (removed, proc_macro_expr, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_gen, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_mod, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_non_items, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, pub_macro_rules, "1.53.0", Some(78855), None, + Some("removed due to being incomplete, in particular it does not work across crates")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, quad_precision_float, "1.0.0", None, None, None), + (removed, quote, "1.33.0", Some(29601), None, None), + (removed, reflect, "1.0.0", Some(27749), None, None), + /// Allows using the macros: + /// + `__diagnostic_used` + /// + `__register_diagnostic` + /// +`__build_diagnostic_array` + (removed, rustc_diagnostic_macros, "1.38.0", None, None, None), + /// Allows identifying crates that contain sanitizer runtimes. + (removed, sanitizer_runtime, "1.17.0", None, None, None), + (removed, simd, "1.0.0", Some(27731), None, + Some("removed in favor of `#[repr(simd)]`")), + (removed, struct_inherit, "1.0.0", None, None, None), + (removed, test_removed_feature, "1.0.0", None, None, None), + /// Allows using items which are missing stability attributes + (removed, unmarked_api, "1.0.0", None, None, None), + (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), /// Allows `#[unwind(..)]`. /// /// Permits specifying whether a function should permit unwinding or abort on unwind. (removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")), + (removed, visible_private_types, "1.0.0", None, None, None), + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! + // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. + // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // ------------------------------------------------------------------------- // feature-group-end: removed features diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 1a34dd04428..5091a7bccc5 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -1,10 +1,5 @@ /// This declares a list of types which can be allocated by `Arena`. /// -/// The `few` modifier will cause allocation to use the shared arena and recording the destructor. -/// This is faster and more memory efficient if there's only a few allocations of the type. -/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is -/// faster and more memory efficient if there is lots of allocations. -/// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`, /// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro. #[macro_export] @@ -12,7 +7,7 @@ macro_rules! arena_types { ($macro:path, $tcx:lifetime) => ( $macro!([ // HIR types - [few] hir_krate: rustc_hir::Crate<$tcx>, + [] hir_krate: rustc_hir::Crate<$tcx>, [] arm: rustc_hir::Arm<$tcx>, [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span), [] asm_template: rustc_ast::InlineAsmTemplatePiece, @@ -29,14 +24,14 @@ macro_rules! arena_types { [] pat_field: rustc_hir::PatField<$tcx>, [] fn_decl: rustc_hir::FnDecl<$tcx>, [] foreign_item: rustc_hir::ForeignItem<$tcx>, - [few] foreign_item_ref: rustc_hir::ForeignItemRef, + [] foreign_item_ref: rustc_hir::ForeignItemRef, [] impl_item: rustc_hir::ImplItem<$tcx>, [] impl_item_ref: rustc_hir::ImplItemRef, [] item: rustc_hir::Item<$tcx>, - [few] inline_asm: rustc_hir::InlineAsm<$tcx>, - [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, + [] inline_asm: rustc_hir::InlineAsm<$tcx>, + [] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, [] local: rustc_hir::Local<$tcx>, - [few] mod_: rustc_hir::Mod<$tcx>, + [] mod_: rustc_hir::Mod<$tcx>, [] owner_info: rustc_hir::OwnerInfo<$tcx>, [] param: rustc_hir::Param<$tcx>, [] pat: rustc_hir::Pat<$tcx>, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index cb668eb35e0..60761a05de8 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -104,8 +104,10 @@ pub enum DefKind { Use, /// An `extern` block. ForeignMod, - /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}` + /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` AnonConst, + /// An inline constant, e.g. `const { 1 + 2 }` + InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, Field, @@ -155,6 +157,7 @@ impl DefKind { DefKind::Use => "import", DefKind::ForeignMod => "foreign module", DefKind::AnonConst => "constant expression", + DefKind::InlineConst => "inline constant", DefKind::Field => "field", DefKind::Impl => "implementation", DefKind::Closure => "closure", @@ -174,6 +177,7 @@ impl DefKind { | DefKind::OpaqueTy | DefKind::Impl | DefKind::Use + | DefKind::InlineConst | DefKind::ExternCrate => "an", DefKind::Macro(macro_kind) => macro_kind.article(), _ => "a", @@ -207,6 +211,7 @@ impl DefKind { // Not namespaced. DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::ExternCrate diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a441a635c1e..e00c5789fe9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -647,6 +647,22 @@ pub struct WhereBoundPredicate<'hir> { pub bounds: GenericBounds<'hir>, } +impl WhereBoundPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn is_param_bound(&self, param_def_id: DefId) -> bool { + let path = match self.bounded_ty.kind { + TyKind::Path(QPath::Resolved(None, path)) => path, + _ => return false, + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => { + def_id == param_def_id + } + _ => false, + } + } +} + /// A lifetime predicate (e.g., `'a: 'b + 'c`). #[derive(Debug, HashStable_Generic)] pub struct WhereRegionPredicate<'hir> { diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 38cbf5314ef..c0137fc7a5a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -139,9 +139,6 @@ pub fn dep_graph_path(sess: &Session) -> PathBuf { pub fn staging_dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME) } -pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf { - in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME) -} pub fn work_products_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME) diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 4d38556e5d2..9c6e2aeb50a 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -6,6 +6,7 @@ use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; +use rustc_session::config::IncrementalStateAssertion; use rustc_session::Session; use std::path::Path; @@ -16,6 +17,7 @@ use super::work_product; type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>; +#[derive(Debug)] pub enum LoadResult<T> { Ok { data: T }, DataOutOfDate, @@ -24,6 +26,26 @@ pub enum LoadResult<T> { impl<T: Default> LoadResult<T> { pub fn open(self, sess: &Session) -> T { + // Check for errors when using `-Zassert-incremental-state` + match (sess.opts.assert_incr_state, &self) { + (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => { + sess.fatal( + "We asserted that the incremental cache should not be loaded, \ + but it was loaded.", + ); + } + ( + Some(IncrementalStateAssertion::Loaded), + LoadResult::Error { .. } | LoadResult::DataOutOfDate, + ) => { + sess.fatal( + "We asserted that an existing incremental cache directory should \ + be successfully loaded, but it was not.", + ); + } + _ => {} + }; + match self { LoadResult::Error { message } => { sess.warn(&message); @@ -33,7 +55,7 @@ impl<T: Default> LoadResult<T> { if let Err(err) = delete_all_session_dir_contents(sess) { sess.err(&format!( "Failed to delete invalidated or incompatible \ - incremental compilation session directory contents `{}`: {}.", + incremental compilation session directory contents `{}`: {}.", dep_graph_path(sess).display(), err )); @@ -105,7 +127,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`. // Fortunately, we just checked that this isn't the case. - let path = dep_graph_path_from(&sess.incr_comp_session_dir()); + let path = dep_graph_path(&sess); let report_incremental_info = sess.opts.debugging_opts.incremental_info; let expected_hash = sess.opts.dep_tracking_hash(false); diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 45639bad243..55ccfd0ad23 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -118,32 +118,54 @@ macro_rules! newtype_index { } impl $type { + /// Maximum value the index can take, as a `u32`. $v const MAX_AS_U32: u32 = $max; + /// Maximum value the index can take. $v const MAX: Self = Self::from_u32($max); + /// Creates a new index from a given `usize`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. #[inline] $v const fn from_usize(value: usize) -> Self { assert!(value <= ($max as usize)); + // SAFETY: We just checked that `value <= max`. unsafe { Self::from_u32_unchecked(value as u32) } } + /// Creates a new index from a given `u32`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. #[inline] $v const fn from_u32(value: u32) -> Self { assert!(value <= $max); + // SAFETY: We just checked that `value <= max`. unsafe { Self::from_u32_unchecked(value) } } + /// Creates a new index from a given `u32`. + /// + /// # Safety + /// + /// The provided value must be less than or equal to the maximum value for the newtype. + /// Providing a value outside this range is undefined due to layout restrictions. + /// + /// Prefer using `from_u32`. #[inline] $v const unsafe fn from_u32_unchecked(value: u32) -> Self { Self { private: value } } - /// Extracts the value of this index as an integer. + /// Extracts the value of this index as a `usize`. #[inline] $v const fn index(self) -> usize { self.as_usize() diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 2296cc6129a..5b4a9d9dfad 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -108,7 +108,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let tcx = self.tcx; // Select everything, returning errors. - let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new); + let true_errors = fulfill_cx.select_where_possible(self); debug!("true_errors = {:#?}", true_errors); if !true_errors.is_empty() { @@ -118,7 +118,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } // Anything left unselected *now* must be an ambiguity. - let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new); + let ambig_errors = fulfill_cx.select_all_or_error(self); debug!("ambig_errors = {:#?}", ambig_errors); let region_obligations = self.take_registered_region_obligations(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8849d623b2d..c25ec1356e2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1704,13 +1704,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let ty::Opaque(def_id, substs) = ty.kind() { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); // Future::Output - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; let bounds = self.tcx.explicit_item_bounds(*def_id); @@ -1800,31 +1794,38 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }, (_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => { - let span = match cause.code { - // scrutinee's span - ObligationCauseCode::Pattern { span: Some(span), .. } => span, - _ => exp_span, - }; - diag.span_suggestion_verbose( - span.shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await".to_string(), - Applicability::MaybeIncorrect, - ); - } - (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => { - let span = match cause.code { - // scrutinee's span - ObligationCauseCode::Pattern { span: Some(span), .. } => span, - _ => exp_span, - }; diag.span_suggestion_verbose( - span.shrink_to_hi(), + exp_span.shrink_to_hi(), "consider `await`ing on the `Future`", ".await".to_string(), Applicability::MaybeIncorrect, ); } + (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code { + ObligationCauseCode::Pattern { span: Some(span), .. } + | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { + diag.span_suggestion_verbose( + span.shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); + } + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + ref prior_arms, + .. + }) => { + diag.multipart_suggestion_verbose( + "consider `await`ing on the `Future`", + prior_arms + .iter() + .map(|arm| (arm.shrink_to_hi(), ".await".to_string())) + .collect(), + Applicability::MaybeIncorrect, + ); + } + _ => {} + }, _ => {} } } @@ -2190,14 +2191,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(SubregionOrigin::CompareImplMethodObligation { span, - item_name, impl_item_def_id, trait_item_def_id, }) = origin { return self.report_extra_impl_obligation( span, - item_name, impl_item_def_id, trait_item_def_id, &format!("`{}: {}`", bound_kind, sub), @@ -2530,7 +2529,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::MiscVariable(_) => String::new(), infer::PatternRegion(_) => " for pattern".to_string(), infer::AddrOfRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_, _) => " for autoref".to_string(), + infer::Autoref(_) => " for autoref".to_string(), infer::Coercion(_) => " for automatic coercion".to_string(), infer::LateBoundRegion(_, br, infer::FnCall) => { format!(" for lifetime parameter {}in function call", br_string(br)) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 0878f8550da..eb1c80ecb01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -3,8 +3,6 @@ use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir::intravisit::Visitor; -use rustc_hir::FnRetTy; use rustc_middle::ty; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -48,19 +46,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; // inapplicable }; + // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect, + // and can steer users down the wrong path. + if *named == ty::ReStatic { + return None; + } + debug!("try_report_named_anon_conflict: named = {:?}", named); debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info); debug!("try_report_named_anon_conflict: region_info = {:?}", region_info); - let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( - anon_param_info.param, - anon_param_info.param_ty, - anon_param_info.param_ty_span, - anon_param_info.bound_region, - anon_param_info.is_first, - region_info.def_id, - region_info.is_impl_item, - ); + let param = anon_param_info.param; + let new_ty = anon_param_info.param_ty; + let new_ty_span = anon_param_info.param_ty_span; + let br = anon_param_info.bound_region; + let is_first = anon_param_info.is_first; + let scope_def_id = region_info.def_id; + let is_impl_item = region_info.is_impl_item; + match br { ty::BrAnon(_) => {} _ => { @@ -75,26 +78,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; } - if let Some((_, fndecl)) = find_anon_type(self.tcx(), anon, &br) { - if self.is_self_anon(is_first, scope_def_id) { - return None; - } - - if let FnRetTy::Return(ty) = &fndecl.output { - let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir()); - v.visit_ty(ty); - - debug!("try_report_named_anon_conflict: ret ty {:?}", ty); - if sub == &ty::ReStatic - && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none()) - { - // If the failure is due to a `'static` requirement coming from a `dyn` or - // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case - // better in `static_impl_trait`. - debug!("try_report_named_anon_conflict: impl Trait + 'static"); - return None; - } - } + if find_anon_type(self.tcx(), anon, &br).is_some() + && self.is_self_anon(is_first, scope_def_id) + { + return None; } let (error_var, span_label_var) = match param.pat.simple_ident() { @@ -114,16 +101,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); diag.span_label(span, format!("lifetime `{}` required", named)); - // Suggesting `'static` is nearly always incorrect, and can steer users - // down the wrong path. - if *named != ty::ReStatic { - diag.span_suggestion( - new_ty_span, - &format!("add explicit lifetime `{}` to {}", named, span_label_var), - new_ty.to_string(), - Applicability::Unspecified, - ); - } + diag.span_suggestion( + new_ty_span, + &format!("add explicit lifetime `{}` to {}", named, span_label_var), + new_ty.to_string(), + Applicability::Unspecified, + ); Some(diag) } 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 b9e7ee12bc8..cfa79213c80 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 @@ -54,12 +54,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { if let SubregionOrigin::CompareImplTypeObligation { span, - item_name, impl_item_def_id, trait_item_def_id, } = origin { - self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + self.emit_associated_type_err( + span, + self.infcx.tcx.item_name(impl_item_def_id), + impl_item_def_id, + trait_item_def_id, + ); return Some(ErrorReported); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 167a8893a11..6600c18351f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -330,30 +330,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::CompareImplMethodObligation { - span, - item_name, - impl_item_def_id, - trait_item_def_id, - } => self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", sup, sub), - ), - infer::CompareImplTypeObligation { - span, - item_name, - impl_item_def_id, - trait_item_def_id, - } => self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", sup, sub), - ), + infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => { + self.report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ) + } + infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self + .report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ), } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9dae978dcde..b874947cc69 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -419,21 +419,11 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl method against /// the containing trait. - CompareImplMethodObligation { - span: Span, - item_name: Symbol, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, + CompareImplMethodObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId }, /// Comparing the signature and requirements of an impl associated type /// against the containing trait - CompareImplTypeObligation { - span: Span, - item_name: Symbol, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, + CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -469,7 +459,7 @@ pub enum RegionVariableOrigin { AddrOfRegion(Span), /// Regions created as part of an autoref of a method receiver - Autoref(Span, ty::AssocItem), + Autoref(Span), /// Regions created as part of an automatic coercion Coercion(Span), @@ -1830,23 +1820,19 @@ impl<'tcx> SubregionOrigin<'tcx> { } traits::ObligationCauseCode::CompareImplMethodObligation { - item_name, impl_item_def_id, trait_item_def_id, } => SubregionOrigin::CompareImplMethodObligation { span: cause.span, - item_name, impl_item_def_id, trait_item_def_id, }, traits::ObligationCauseCode::CompareImplTypeObligation { - item_name, impl_item_def_id, trait_item_def_id, } => SubregionOrigin::CompareImplTypeObligation { span: cause.span, - item_name, impl_item_def_id, trait_item_def_id, }, @@ -1862,7 +1848,7 @@ impl RegionVariableOrigin { MiscVariable(a) | PatternRegion(a) | AddrOfRegion(a) - | Autoref(a, _) + | Autoref(a) | Coercion(a) | EarlyBoundRegion(a, ..) | LateBoundRegion(a, ..) diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 9e04773c5fa..3947282aa62 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// function. We can then add implied bounds and the like from the /// closure arguments into the environment -- these should only /// apply in the closure body, so once we exit, we invoke - /// `pop_snapshot_post_closure` to remove them. + /// `pop_snapshot_post_typeck_child` to remove them. /// /// Example: /// @@ -129,12 +129,12 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// seems like it'd be readily fixed if we wanted. There are /// similar leaks around givens that seem equally suspicious, to /// be honest. --nmatsakis - pub fn push_snapshot_pre_closure(&self) -> usize { + pub fn push_snapshot_pre_typeck_child(&self) -> usize { self.region_bound_pairs_accum.len() } - /// See `push_snapshot_pre_closure`. - pub fn pop_snapshot_post_closure(&mut self, len: usize) { + /// See `push_snapshot_pre_typeck_child`. + pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) { self.region_bound_pairs_accum.truncate(len); } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index dce4a87b041..152a395c871 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -46,30 +46,25 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>>; + fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>; fn select_all_with_constness_or_error( &mut self, infcx: &InferCtxt<'_, 'tcx>, _constness: hir::Constness, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + ) -> Vec<FulfillmentError<'tcx>> { self.select_all_or_error(infcx) } - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>>; + fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>) + -> Vec<FulfillmentError<'tcx>>; // FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated fn select_with_constness_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, _constness: hir::Constness, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + ) -> Vec<FulfillmentError<'tcx>> { self.select_where_possible(infcx) } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 9dbfa3a850b..c1f302e665d 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -6,7 +6,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; use rustc_span::{MultiSpan, Span}; use std::fmt; use std::iter; @@ -15,8 +14,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_extra_impl_obligation( &self, error_span: Span, - item_name: Symbol, - _impl_item_def_id: DefId, + impl_item_def_id: DefId, trait_item_def_id: DefId, requirement: &dyn fmt::Display, ) -> DiagnosticBuilder<'tcx> { @@ -27,6 +25,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { let span = self.tcx.sess.source_map().guess_head_span(trait_item_span); + let item_name = self.tcx.item_name(impl_item_def_id); err.span_label(span, format!("definition of `{}` from trait", item_name)); } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index c839f824d1c..92f74af4eb3 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -5,6 +5,7 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; use rustc_span::symbol::Ident; +use rustc_span::Span; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -97,6 +98,22 @@ pub fn elaborate_predicates<'tcx>( elaborate_obligations(tcx, obligations) } +pub fn elaborate_predicates_with_span<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>, +) -> Elaborator<'tcx> { + let obligations = predicates + .map(|(predicate, span)| { + predicate_obligation( + predicate, + ty::ParamEnv::empty(), + ObligationCause::dummy_with_span(span), + ) + }) + .collect(); + elaborate_obligations(tcx, obligations) +} + pub fn elaborate_obligations<'tcx>( tcx: TyCtxt<'tcx>, mut obligations: Vec<PredicateObligation<'tcx>>, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 7a6a643e3d0..2904b3f5b70 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -36,6 +36,7 @@ pub struct Compiler { pub(crate) input_path: Option<PathBuf>, pub(crate) output_dir: Option<PathBuf>, pub(crate) output_file: Option<PathBuf>, + pub(crate) temps_dir: Option<PathBuf>, pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>, pub(crate) override_queries: Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, @@ -57,6 +58,9 @@ impl Compiler { pub fn output_file(&self) -> &Option<PathBuf> { &self.output_file } + pub fn temps_dir(&self) -> &Option<PathBuf> { + &self.temps_dir + } pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> { &self.register_lints } @@ -65,7 +69,14 @@ impl Compiler { sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess) + util::build_output_filenames( + &self.input, + &self.output_dir, + &self.output_file, + &self.temps_dir, + attrs, + sess, + ) } } @@ -186,6 +197,8 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R ); } + let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + let compiler = Compiler { sess, codegen_backend, @@ -193,6 +206,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, + temps_dir, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3f6e879e6e4..b073ee9682f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -692,6 +692,7 @@ pub fn prepare_outputs( &compiler.input, &compiler.output_dir, &compiler.output_file, + &compiler.temps_dir, &krate.attrs, sess, ); @@ -722,6 +723,13 @@ pub fn prepare_outputs( } } + if let Some(ref dir) = compiler.temps_dir { + if fs::create_dir_all(dir).is_err() { + sess.err("failed to find or create the directory specified by `--temps-dir`"); + return Err(ErrorReported); + } + } + write_out_deps(sess, boxed_resolver, &outputs, &output_paths); let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2d3cb52f5fd..6b5c79a2d5d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -551,6 +551,7 @@ fn test_codegen_options_tracking_hash() { untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")])); untracked!(rpath, true); untracked!(save_temps, true); + untracked!(strip, Strip::Debuginfo); macro_rules! tracked { ($name: ident, $non_default_value: expr) => { @@ -635,6 +636,7 @@ fn test_debugging_options_tracking_hash() { // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. // This list is in alphabetical order. + untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(ast_json, true); untracked!(ast_json_noexpand, true); untracked!(borrowck, String::from("other")); @@ -684,7 +686,7 @@ fn test_debugging_options_tracking_hash() { untracked!(self_profile_events, Some(vec![String::new()])); untracked!(span_debug, true); untracked!(span_free_formats, true); - untracked!(strip, Strip::Debuginfo); + untracked!(temps_dir, Some(String::from("abc"))); untracked!(terminal_width, Some(80)); untracked!(threads, 99); untracked!(time, true); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 94650237873..04e183a9ba5 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -604,6 +604,7 @@ pub fn build_output_filenames( input: &Input, odir: &Option<PathBuf>, ofile: &Option<PathBuf>, + temps_dir: &Option<PathBuf>, attrs: &[ast::Attribute], sess: &Session, ) -> OutputFilenames { @@ -626,6 +627,7 @@ pub fn build_output_filenames( dirpath, stem, None, + temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -654,6 +656,7 @@ pub fn build_output_filenames( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), ofile, + temps_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6548cdc0fdc..f2e4e70a197 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -32,8 +32,7 @@ use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; -use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType}; -use rustc_feature::{GateIssue, Stability}; +use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; @@ -959,7 +958,7 @@ impl EarlyLintPass for AnonymousParameters { pub struct DeprecatedAttr { // This is not free to compute, so we want to keep it around, rather than // compute it for every attribute. - depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>, + depr_attrs: Vec<&'static BuiltinAttribute>, } impl_lint_pass!(DeprecatedAttr => []); @@ -990,14 +989,14 @@ fn lint_deprecated_attr( impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - for &&(n, _, _, ref g) in &self.depr_attrs { - if attr.ident().map(|ident| ident.name) == Some(n) { + for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { + if attr.ident().map(|ident| ident.name) == Some(*name) { if let &AttributeGate::Gated( Stability::Deprecated(link, suggestion), name, reason, _, - ) = g + ) = gate { let msg = format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f6514ddca9f..507b4421fa1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -30,7 +30,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(crate_visibility_modifier)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(iter_order_by)] #![feature(iter_zip)] #![feature(never_type)] diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ddbc3c59128..4f77db8a24d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -889,15 +889,17 @@ LLVMRustOptimizeWithNewPassManager( OptimizerLastEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); - MPM.addPass(ModuleAddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); #if LLVM_VERSION_GE(14, 0) - AddressSanitizerOptions opts(/*CompileKernel=*/false, - SanitizerOptions->SanitizeAddressRecover, - /*UseAfterScope=*/true, - AsanDetectStackUseAfterReturnMode::Runtime); - MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts))); + AddressSanitizerOptions opts = AddressSanitizerOptions{ + /*CompileKernel=*/false, + SanitizerOptions->SanitizeAddressRecover, + /*UseAfterScope=*/true, + AsanDetectStackUseAfterReturnMode::Runtime, + }; + MPM.addPass(ModuleAddressSanitizerPass(opts)); #else + MPM.addPass(ModuleAddressSanitizerPass( + /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass( /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover, /*UseAfterScope=*/true))); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 5e90aec003e..b2c7818a542 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1179,7 +1179,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); let mut vis = self.get_visibility(ctor_def_id.index); - if ctor_def_id == def_id && vis == ty::Visibility::Public { + if ctor_def_id == def_id && vis.is_public() { // For non-exhaustive variants lower the constructor visibility to // within the crate. We only need this for fictive constructors, // for other constructors correct visibilities diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7ea004b16f2..eeb0a77adc0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -318,7 +318,7 @@ pub fn provide(providers: &mut Providers) { } let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { - if child.vis != ty::Visibility::Public { + if !child.vis.is_public() { return; } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0dbef66ac37..d46829c2cee 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::ConstParam | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { DefKind::Use | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { (true, mir_opt_base) } // Constants - DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => { - (true, false) - } + DefKind::AnonConst + | DefKind::InlineConst + | DefKind::AssocConst + | DefKind::Static + | DefKind::Const => (true, false), // Full-fledged functions DefKind::AssocFn | DefKind::Fn => { let generics = tcx.generics_of(def_id); @@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::AssocFn | DefKind::AssocConst | DefKind::AnonConst + | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::Impl | DefKind::Field @@ -2187,5 +2193,8 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { result[header + 2] = (pos >> 8) as u8; result[header + 3] = (pos >> 0) as u8; + // Record metadata size for self-profiling + tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64); + EncodedMetadata { raw_data: result } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 420c500a7de..2bcc2a4f7cf 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -1,10 +1,5 @@ /// This declares a list of types which can be allocated by `Arena`. /// -/// The `few` modifier will cause allocation to use the shared arena and recording the destructor. -/// This is faster and more memory efficient if there's only a few allocations of the type. -/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is -/// faster and more memory efficient if there is lots of allocations. -/// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type /// listed. These impls will appear in the implement_ty_decoder! macro. #[macro_export] @@ -37,7 +32,7 @@ macro_rules! arena_types { [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, // Required for the incremental on-disk cache - [few] mir_keys: rustc_hir::def_id::DefIdSet, + [] mir_keys: rustc_hir::def_id::DefIdSet, [] region_scope_tree: rustc_middle::middle::region::ScopeTree, [] dropck_outlives: rustc_middle::infer::canonical::Canonical<'tcx, @@ -77,10 +72,10 @@ macro_rules! arena_types { rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>> >, - [few] all_traits: Vec<rustc_hir::def_id::DefId>, - [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, - [few] foreign_module: rustc_session::cstore::ForeignModule, - [few] foreign_modules: Vec<rustc_session::cstore::ForeignModule>, + [] all_traits: Vec<rustc_hir::def_id::DefId>, + [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, + [] foreign_module: rustc_session::cstore::ForeignModule, + [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8f52e16c2eb..d9d0781b37a 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -266,7 +266,15 @@ impl<'hir> Map<'hir> { }; DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data)) } - Node::AnonConst(_) => DefKind::AnonConst, + Node::AnonConst(_) => { + let inline = match self.find(self.get_parent_node(hir_id)) { + Some(Node::Expr(&Expr { + kind: ExprKind::ConstBlock(ref anon_const), .. + })) if anon_const.hir_id == hir_id => true, + _ => false, + }; + if inline { DefKind::InlineConst } else { DefKind::AnonConst } + } Node::Field(_) => DefKind::Field, Node::Expr(expr) => match expr.kind { ExprKind::Closure(.., None) => DefKind::Closure, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 1eba2994ed3..0e70d49ef49 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -248,8 +248,12 @@ pub fn struct_lint_level<'s, 'd>( (Level::Warn, None) => sess.struct_warn(""), (Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""), (Level::ForceWarn, None) => sess.struct_force_warn(""), - (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""), - (Level::Deny | Level::Forbid, None) => sess.struct_err(""), + (Level::Deny | Level::Forbid, Some(span)) => { + let mut builder = sess.diagnostic().struct_err_lint(""); + builder.set_span(span); + builder + } + (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""), }; // If this code originates in a foreign macro, aka something that this crate diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8e363cfbff5..8e1b887f87d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -958,7 +958,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })? } (_, _) if is_function => write!(w, "fn ")?, - (DefKind::AnonConst, _) => {} // things like anon const, not an item + (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item _ => bug!("Unexpected def kind {:?}", kind), } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 06041bbb02d..9a58009a173 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -797,7 +797,7 @@ rustc_queries! { /// additional requirements that the closure's creator must verify. query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) } + cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) } } query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { @@ -822,6 +822,14 @@ rustc_queries! { desc { "check for overlap between inherent impls defined in this crate" } } + /// Checks whether all impls in the crate pass the overlap check, returning + /// which impls fail it. If all impls are correct, the returned slice is empty. + query orphan_check_crate(_: ()) -> &'tcx [LocalDefId] { + desc { + "checking whether the immpl in the this crate follow the orphan rules", + } + } + /// Check whether the function has any recursion that could cause the inliner to trigger /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the /// current function, just all intermediate functions. @@ -1056,11 +1064,6 @@ rustc_queries! { } /// Return all `impl` blocks in the current crate. - /// - /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. - /// Passing in any other crate will cause an ICE. - /// - /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE query all_local_trait_impls(_: ()) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> { desc { "local trait impls" } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6570d8e1567..245df636107 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -267,14 +267,12 @@ pub enum ObligationCauseCode<'tcx> { /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplMethodObligation { - item_name: Symbol, impl_item_def_id: DefId, trait_item_def_id: DefId, }, /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplTypeObligation { - item_name: Symbol, impl_item_def_id: DefId, trait_item_def_id: DefId, }, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 869b2ab9dbc..27e22ccac02 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,7 +1,9 @@ use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ParamEnv, ParamEnvAnd}; +use crate::ty::{ + self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, + TyCtxt, TypeFoldable, +}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -54,6 +56,24 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def.def_id_for_type_of()); + match Self::try_eval_lit_or_param(tcx, ty, expr) { + Some(v) => v, + None => tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: def.to_global(), + substs_: None, + promoted: None, + }), + ty, + }), + } + } + + fn try_eval_lit_or_param( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ) -> Option<&'tcx Self> { let lit_input = match expr.kind { hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { @@ -69,7 +89,7 @@ impl<'tcx> Const<'tcx> { // If an error occurred, ignore that it's a literal and leave reporting the error up to // mir. if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { - return c; + return Some(c); } else { tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); } @@ -85,7 +105,7 @@ impl<'tcx> Const<'tcx> { }; use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; - let val = match expr.kind { + match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. @@ -95,16 +115,53 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id.to_def_id()); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.hir().name(hir_id); - ty::ConstKind::Param(ty::ParamConst::new(index, name)) + Some(tcx.mk_const(ty::Const { + val: ty::ConstKind::Param(ty::ParamConst::new(index, name)), + ty, + })) } - _ => ty::ConstKind::Unevaluated(ty::Unevaluated { - def: def.to_global(), - substs_: None, - promoted: None, - }), + _ => None, + } + } + + pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self { + debug!("Const::from_inline_const(def_id={:?})", def_id); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, + _ => span_bug!( + tcx.def_span(def_id.to_def_id()), + "from_inline_const can only process anonymous constants" + ), }; - tcx.mk_const(ty::Const { val, ty }) + let expr = &tcx.hir().body(body_id).value; + + let ty = tcx.typeck(def_id).node_type(hir_id); + + let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) { + Some(v) => v, + None => { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); + let parent_substs = + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); + let substs = + InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) + .substs; + tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id).to_global(), + substs_: Some(substs), + promoted: None, + }), + ty, + }) + } + }; + debug_assert!(!ret.has_free_regions(tcx)); + ret } /// Interns the given value as a constant. diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 2bd9415171d..b14a6989265 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -42,6 +42,7 @@ pub enum TypeError<'tcx> { TupleSize(ExpectedFound<usize>), FixedArraySize(ExpectedFound<u64>), ArgCount, + FieldMisMatch(Symbol, Symbol), RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), @@ -134,6 +135,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { pluralize!(values.found) ), ArgCount => write!(f, "incorrect number of function parameters"), + FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field), RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"), RegionsInsufficientlyPolymorphic(br, _) => write!( f, @@ -224,6 +226,7 @@ impl<'tcx> TypeError<'tcx> { | ArgumentMutability(_) | TupleSize(_) | ArgCount + | FieldMisMatch(..) | RegionsDoesNotOutlive(..) | RegionsInsufficientlyPolymorphic(..) | RegionsOverlyPolymorphic(..) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cf47da157d1..673733faa76 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -74,9 +74,10 @@ pub use self::sty::{ Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, - GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, - PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, - RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, + GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, + ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, + PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, + UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, }; pub use self::trait_def::TraitDef; @@ -332,6 +333,10 @@ impl Visibility { Visibility::Invisible => false, } } + + pub fn is_public(self) -> bool { + matches!(self, Visibility::Public) + } } /// The crate variances map is computed during typeck and contains the @@ -1927,7 +1932,8 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::Static | DefKind::AssocConst | DefKind::Ctor(..) - | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def), + | DefKind::AnonConst + | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), // If the caller wants `mir_for_ctfe` of a function they should not be using // `instance_mir`, so we'll assume const fn also wants the optimized version. _ => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 742005e245f..5d9e7aaf72f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2404,7 +2404,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate external crate defs but be mindful about visibility while let Some(def) = queue.pop() { for child in tcx.item_children(def).iter() { - if child.vis != ty::Visibility::Public { + if !child.vis.is_public() { continue; } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index d6069395474..0f8e80806e3 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -602,6 +602,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { TupleSize(x) => TupleSize(x), FixedArraySize(x) => FixedArraySize(x), ArgCount => ArgCount, + FieldMisMatch(x, y) => FieldMisMatch(x, y), RegionsDoesNotOutlive(a, b) => { return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 874de3366d7..610f9bd8f82 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -704,6 +704,66 @@ impl<'tcx> UpvarSubsts<'tcx> { } } +/// An inline const is modeled like +/// +/// const InlineConst<'l0...'li, T0...Tj, R>: R; +/// +/// where: +/// +/// - 'l0...'li and T0...Tj are the generic parameters +/// inherited from the item that defined the inline const, +/// - R represents the type of the constant. +/// +/// When the inline const is instantiated, `R` is substituted as the actual inferred +/// type of the constant. The reason that `R` is represented as an extra type parameter +/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters: +/// inline const can reference lifetimes that are internal to the creating function. +#[derive(Copy, Clone, Debug, TypeFoldable)] +pub struct InlineConstSubsts<'tcx> { + /// Generic parameters from the enclosing item, + /// concatenated with the inferred type of the constant. + pub substs: SubstsRef<'tcx>, +} + +/// Struct returned by `split()`. +pub struct InlineConstSubstsParts<'tcx, T> { + pub parent_substs: &'tcx [GenericArg<'tcx>], + pub ty: T, +} + +impl<'tcx> InlineConstSubsts<'tcx> { + /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`. + pub fn new( + tcx: TyCtxt<'tcx>, + parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>, + ) -> InlineConstSubsts<'tcx> { + InlineConstSubsts { + substs: tcx.mk_substs( + parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())), + ), + } + } + + /// Divides the inline const substs into their respective components. + /// The ordering assumed here must match that used by `InlineConstSubsts::new` above. + fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> { + match self.substs[..] { + [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty }, + _ => bug!("inline const substs missing synthetics"), + } + } + + /// Returns the substitutions of the inline const's parent. + pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent_substs + } + + /// Returns the type of this inline const. + pub fn ty(self) -> Ty<'tcx> { + self.split().ty.expect_ty() + } +} + #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub enum ExistentialPredicate<'tcx> { @@ -2007,7 +2067,9 @@ impl<'tcx> TyS<'tcx> { ) -> Option<Discr<'tcx>> { match self.kind() { TyKind::Adt(adt, _) if adt.variants.is_empty() => { - bug!("discriminant_for_variant called on zero variant enum"); + // This can actually happen during CTFE, see + // https://github.com/rust-lang/rust/issues/89765. + None } TyKind::Adt(adt, _) if adt.is_enum() => { Some(adt.discriminant_for_variant(tcx, variant_index)) @@ -2026,10 +2088,10 @@ impl<'tcx> TyS<'tcx> { ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => { - let assoc_items = - tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); - let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; - tcx.mk_projection(discriminant_def_id, tcx.mk_substs([self.into()].iter())) + let assoc_items = tcx.associated_item_def_ids( + tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + ); + tcx.mk_projection(assoc_items[0], tcx.intern_substs(&[self.into()])) } ty::Bool diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 2438d1a1602..73a8e18949d 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -3,7 +3,7 @@ use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; +use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_hir::def_id::DefId; @@ -204,6 +204,14 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { GeneratorSubsts { substs: self } } + /// Interpret these substitutions as the substitutions of an inline const. + /// Inline const substitutions have a particular structure controlled by the + /// compiler that encodes information like the inferred type; + /// see `ty::InlineConstSubsts` struct for more comments. + pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> { + InlineConstSubsts { substs: self } + } + /// Creates an `InternalSubsts` that maps each generic parameter to itself. pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2c884813d23..6e7acb244d1 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -325,9 +325,9 @@ impl<'tcx> TyCtxt<'tcx> { let ty = self.type_of(adt_did); let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { - if let Some(item) = self.associated_items(impl_did).in_definition_order().next() { + if let Some(item_id) = self.associated_item_def_ids(impl_did).first() { if validate(self, impl_did).is_ok() { - return Some((item.def_id, self.impl_constness(impl_did))); + return Some((*item_id, self.impl_constness(impl_did))); } } None @@ -423,6 +423,15 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator) } + /// Returns `true` if `def_id` refers to a definition that does not have its own + /// type-checking context, i.e. closure, generator or inline const. + pub fn is_typeck_child(self, def_id: DefId) -> bool { + matches!( + self.def_kind(def_id), + DefKind::Closure | DefKind::Generator | DefKind::InlineConst + ) + } + /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). pub fn is_trait(self, def_id: DefId) -> bool { self.def_kind(def_id) == DefKind::Trait @@ -440,16 +449,19 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Ctor(..)) } - /// Given the def-ID of a fn or closure, returns the def-ID of - /// the innermost fn item that the closure is contained within. - /// This is a significant `DefId` because, when we do - /// type-checking, we type-check this fn item and all of its - /// (transitive) closures together. Therefore, when we fetch the + /// Given the `DefId`, returns the `DefId` of the innermost item that + /// has its own type-checking context or "inference enviornment". + /// + /// For example, a closure has its own `DefId`, but it is type-checked + /// with the containing item. Similarly, an inline const block has its + /// own `DefId` but it is type-checked together with the containing item. + /// + /// Therefore, when we fetch the /// `typeck` the closure, for example, we really wind up /// fetching the `typeck` the enclosing fn item. - pub fn closure_base_def_id(self, def_id: DefId) -> DefId { + pub fn typeck_root_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; - while self.is_closure(def_id) { + while self.is_typeck_child(def_id) { def_id = self.parent(def_id).unwrap_or_else(|| { bug!("closure {:?} has no parent", def_id); }); diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs index da857b0a403..08977049db0 100644 --- a/compiler/rustc_middle/src/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -34,7 +34,7 @@ where let rv = f(); let duration = start.elapsed(); let mut accu = accu.lock(); - *accu = *accu + duration; + *accu += duration; rv } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4df073c40e2..6320d5d4749 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1762,8 +1762,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { let expr_span = expr.span; let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span)); - let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false); let wildcard = Pat::wildcard_from_ty(pat.ty); + let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false); let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false); let fake_borrow_temps = self.lower_match_tree( block, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 17296a95bc1..b4005ccd1cc 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -578,7 +578,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::ConstBlock(ref anon_const) => { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); ExprKind::ConstBlock { value } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index cb74ae4df2e..ce80214c875 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -544,7 +544,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let (lit, neg) = match expr.kind { hir::ExprKind::ConstBlock(ref anon_const) => { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); if matches!(value.val, ConstKind::Param(_)) { let span = self.tcx.hir().span(anon_const.hir_id); self.errors.push(PatternError::ConstParamInPattern(span)); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index d959d2f7f6f..3ed434131b2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -443,9 +443,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { - for row in row.expand_or_pat() { - self.patterns.push(row); - } + self.patterns.extend(row.expand_or_pat()); } else { self.patterns.push(row); } @@ -797,7 +795,7 @@ fn is_useful<'p, 'tcx>( return ret; } - assert!(rows.iter().all(|r| r.len() == v.len())); + debug_assert!(rows.iter().all(|r| r.len() == v.len())); let ty = v.head().ty(); let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 7607ccc3aba..11856f6e047 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -604,7 +604,7 @@ where debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.require_lang_item(LangItem::Drop, None); - let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); + let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); @@ -624,12 +624,7 @@ where )], terminator: Some(Terminator { kind: TerminatorKind::Call { - func: Operand::function_handle( - tcx, - drop_fn.def_id, - substs, - self.source_info.span, - ), + func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span), args: vec![Operand::Move(Place::from(ref_place))], destination: Some((unit_temp, succ)), cleanup: unwind.into_option(), diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f2ea5fedc62..f59aaa664f3 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -310,7 +310,6 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - match self_ty.kind() { _ if is_copy => builder.copy_shim(), - ty::Array(ty, len) => builder.array_shim(dest, src, ty, len), ty::Closure(_, substs) => { builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) } @@ -459,154 +458,6 @@ impl CloneShimBuilder<'tcx> { ); } - fn loop_header( - &mut self, - beg: Place<'tcx>, - end: Place<'tcx>, - loop_body: BasicBlock, - loop_end: BasicBlock, - is_cleanup: bool, - ) { - let tcx = self.tcx; - - let cond = self.make_place(Mutability::Mut, tcx.types.bool); - let compute_cond = self.make_statement(StatementKind::Assign(Box::new(( - cond, - Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))), - )))); - - // `if end != beg { goto loop_body; } else { goto loop_end; }` - self.block( - vec![compute_cond], - TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end), - is_cleanup, - ); - } - - fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> { - Box::new(Constant { - span: self.span, - user_ty: None, - literal: ty::Const::from_usize(self.tcx, value).into(), - }) - } - - fn array_shim( - &mut self, - dest: Place<'tcx>, - src: Place<'tcx>, - ty: Ty<'tcx>, - len: &'tcx ty::Const<'tcx>, - ) { - let tcx = self.tcx; - let span = self.span; - - let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); - let end = self.make_place(Mutability::Not, tcx.types.usize); - - // BB #0 - // `let mut beg = 0;` - // `let end = len;` - // `goto #1;` - let inits = vec![ - self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::Use(Operand::Constant(self.make_usize(0))), - )))), - self.make_statement(StatementKind::Assign(Box::new(( - end, - Rvalue::Use(Operand::Constant(Box::new(Constant { - span: self.span, - user_ty: None, - literal: len.into(), - }))), - )))), - ]; - self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); - - // BB #1: loop { - // BB #2; - // BB #3; - // } - // BB #4; - self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false); - - // BB #2 - // `dest[i] = Clone::clone(src[beg])`; - // Goto #3 if ok, #5 if unwinding happens. - let dest_field = self.tcx.mk_place_index(dest, beg); - let src_field = self.tcx.mk_place_index(src, beg); - self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5)); - - // BB #3 - // `beg = beg + 1;` - // `goto #1`; - let statements = vec![self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::BinaryOp( - BinOp::Add, - Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), - ), - ))))]; - self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); - - // BB #4 - // `return dest;` - self.block(vec![], TerminatorKind::Return, false); - - // BB #5 (cleanup) - // `let end = beg;` - // `let mut beg = 0;` - // goto #6; - let end = beg; - let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span)); - let init = self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::Use(Operand::Constant(self.make_usize(0))), - )))); - self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); - - // BB #6 (cleanup): loop { - // BB #7; - // BB #8; - // } - // BB #9; - self.loop_header( - Place::from(beg), - Place::from(end), - BasicBlock::new(7), - BasicBlock::new(9), - true, - ); - - // BB #7 (cleanup) - // `drop(dest[beg])`; - self.block( - vec![], - TerminatorKind::Drop { - place: self.tcx.mk_place_index(dest, beg), - target: BasicBlock::new(8), - unwind: None, - }, - true, - ); - - // BB #8 (cleanup) - // `beg = beg + 1;` - // `goto #6;` - let statement = self.make_statement(StatementKind::Assign(Box::new(( - Place::from(beg), - Rvalue::BinaryOp( - BinOp::Add, - Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))), - ), - )))); - self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); - - // BB #9 (resume) - self.block(vec![], TerminatorKind::Resume, true); - } - fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I) where I: Iterator<Item = Ty<'tcx>>, diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 7a7a56a034e..658c9028ca1 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -361,6 +361,17 @@ fn collect_and_partition_mono_items<'tcx>( ) }); + if tcx.prof.enabled() { + // Record CGU size estimates for self-profiling. + for cgu in codegen_units { + tcx.prof.artifact_size( + "codegen_unit_size_estimate", + &cgu.name().as_str()[..], + cgu.size_estimate() as u64, + ); + } + } + let mono_items: DefIdSet = items .iter() .filter_map(|mono_item| match *mono_item { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index e6e4438b6d4..595080619da 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::Field | DefKind::LifetimeParam @@ -195,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>( generics: &'tcx ty::Generics, unused_parameters: &FiniteBitSet<u32>, ) { - let base_def_id = tcx.closure_base_def_id(def_id); + let base_def_id = tcx.typeck_root_def_id(def_id); if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { return; } @@ -303,7 +304,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(uv) - if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => + if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) => { self.visit_child_body(uv.def.did, uv.substs(self.tcx)); ControlFlow::CONTINUE diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 569f186a727..7f68112a427 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -82,6 +82,33 @@ pub(crate) fn emit_unescape_error( Applicability::MachineApplicable, ); } + } else { + let printable: Vec<char> = lit + .chars() + .filter(|&x| { + unicode_width::UnicodeWidthChar::width(x).unwrap_or(0) != 0 + && !x.is_whitespace() + }) + .collect(); + + if let [ch] = printable.as_slice() { + has_help = true; + + handler.span_note( + span, + &format!( + "there are non-printing characters, the full sequence is `{}`", + lit.escape_default(), + ), + ); + + handler.span_suggestion( + span, + "consider removing the non-printing characters", + ch.to_string(), + Applicability::MaybeIncorrect, + ); + } } if !has_help { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2aa20d02c88..4781813ee8e 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -5,7 +5,7 @@ use crate::parse_in; use rustc_ast::tokenstream::{DelimSpan, TokenTree}; use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; use rustc_errors::{Applicability, FatalError, PResult}; -use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; use rustc_span::{sym, Symbol}; @@ -15,14 +15,13 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { return; } - let attr_info = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); + let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); // Check input tokens for built-in and key-value attributes. match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some((name, _, template, _)) if name != sym::rustc_dummy => { - check_builtin_attribute(sess, attr, name, template) + Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { + check_builtin_attribute(sess, attr, *name, *template) } _ if let MacArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. @@ -168,7 +167,7 @@ pub fn emit_fatal_malformed_builtin_attribute( attr: &Attribute, name: Symbol, ) -> ! { - let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2; + let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template; emit_malformed_attribute(sess, attr, name, template); // This is fatal, otherwise it will likely cause a cascade of other errors // (and an error here is expected to be very rare). diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 596d13d2d9a..6ff2259dc5b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; -use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -112,6 +112,7 @@ impl CheckAttrVisitor<'tcx> { self.check_default_method_body_is_const(attr, span, target) } sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), + sym::must_use => self.check_must_use(hir_id, &attr, span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -148,7 +149,7 @@ impl CheckAttrVisitor<'tcx> { } if hir_id != CRATE_HIR_ID { - if let Some((_, AttributeType::CrateLevel, ..)) = + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { @@ -1046,6 +1047,37 @@ impl CheckAttrVisitor<'tcx> { is_valid } + /// Warns against some misuses of `#[must_use]` + fn check_must_use( + &self, + hir_id: HirId, + attr: &Attribute, + span: &Span, + _target: Target, + ) -> bool { + let node = self.tcx.hir().get(hir_id); + if let Some(fn_node) = node.fn_kind() { + if let rustc_hir::IsAsync::Async = fn_node.asyncness() { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build( + "`must_use` attribute on `async` functions \ + applies to the anonymous `Future` returned by the \ + function, not the value within", + ) + .span_label( + *span, + "this attribute does nothing, the `Future`s \ + returned by async functions are already `must_use`", + ) + .emit(); + }); + } + } + + // For now, its always valid + true + } + /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid. fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool { match target { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 4adec3c4f60..af1c7244100 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -7,7 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(iter_zip)] #![feature(map_try_insert)] #![feature(min_specialization)] diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 5fc8e230d72..6a8feb041da 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // properly, we can't miss any types. match expr.kind { - // Manually recurse over closures, because they are the only + // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(.., body, _, _) => { + hir::ExprKind::Closure(.., body, _, _) + | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } @@ -817,9 +818,9 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { } fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { - let closure_base_def_id = tcx.closure_base_def_id(def_id); - if closure_base_def_id != def_id { - return tcx.region_scope_tree(closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.region_scope_tree(typeck_root_def_id); } let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fa34b9abc1e..11668146f7b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -543,7 +543,7 @@ impl EmbargoVisitor<'tcx> { module: LocalDefId, ) { let level = Some(AccessLevel::Reachable); - if let ty::Visibility::Public = vis { + if vis.is_public() { self.update(def_id, level); } match def_kind { @@ -580,7 +580,7 @@ impl EmbargoVisitor<'tcx> { DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. - if let ty::Visibility::Public = vis { + if vis.is_public() { let item = self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id)); if let hir::ItemKind::Struct(ref struct_def, _) @@ -618,6 +618,7 @@ impl EmbargoVisitor<'tcx> { | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::GlobalAsm | DefKind::Impl @@ -932,7 +933,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { let def_id = self.tcx.hir().local_def_id(id); if let Some(exports) = self.tcx.module_exports(def_id) { for export in exports.iter() { - if export.vis == ty::Visibility::Public { + if export.vis.is_public() { if let Some(def_id) = export.res.opt_def_id() { if let Some(def_id) = def_id.as_local() { self.update(def_id, Some(AccessLevel::Exported)); @@ -1917,8 +1918,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> { /// 1. It's contained within a public type /// 2. It comes from a private crate fn leaks_private_dep(&self, item_id: DefId) -> bool { - let ret = self.required_visibility == ty::Visibility::Public - && self.tcx.is_private_dep(item_id.krate); + let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate); tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); ret diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d77a70e5327..3cf9d324a38 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -967,6 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm @@ -1193,15 +1194,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Mark the given macro as unused unless its name starts with `_`. // Macro uses will remove items from this set, and the remaining // items will be reported as `unused_macros`. - fn insert_unused_macro( - &mut self, - ident: Ident, - def_id: LocalDefId, - node_id: NodeId, - span: Span, - ) { + fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) { if !ident.as_str().starts_with('_') { - self.r.unused_macros.insert(def_id, (node_id, span)); + self.r.unused_macros.insert(def_id, (node_id, ident)); } } @@ -1245,7 +1240,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); } else { self.r.check_reserved_macro_name(ident, res); - self.insert_unused_macro(ident, def_id, item.id, span); + self.insert_unused_macro(ident, def_id, item.id); } self.r.visibilities.insert(def_id, vis); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( @@ -1266,7 +1261,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _ => self.resolve_visibility(&item.vis), }; if vis != ty::Visibility::Public { - self.insert_unused_macro(ident, def_id, item.id, span); + self.insert_unused_macro(ident, def_id, item.id); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); self.r.visibilities.insert(def_id, vis); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 760b7469961..63699128e9e 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -32,7 +32,6 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; -use rustc_middle::ty; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::{MultiSpan, Span, DUMMY_SP}; @@ -228,7 +227,7 @@ impl Resolver<'_> { for import in self.potentially_unused_imports.iter() { match import.kind { _ if import.used.get() - || import.vis.get() == ty::Visibility::Public + || import.vis.get().is_public() || import.span.is_dummy() => { if let ImportKind::MacroUse = import.kind { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ff0d76e94fd..c46a18e5103 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_middle::bug; -use rustc_middle::ty::{self, DefIdTree}; +use rustc_middle::ty::DefIdTree; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -731,7 +731,7 @@ impl<'a> Resolver<'a> { suggestions.extend( BUILTIN_ATTRIBUTES .iter() - .map(|(name, ..)| TypoSuggestion::typo_from_res(*name, res)), + .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)), ); } } @@ -1308,7 +1308,7 @@ impl<'a> Resolver<'a> { ); let def_span = self.session.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); - if !first && binding.vis == ty::Visibility::Public { + if !first && binding.vis.is_public() { note_span.push_span_label(def_span, "consider importing it directly".into()); } err.span_note(note_span, &msg); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 936ab81914a..4262c1e9051 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -164,7 +164,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi import: Import { kind: ImportKind::ExternCrate { .. }, .. }, .. }, - ) => import.vis.get() == ty::Visibility::Public, + ) => import.vis.get().is_public(), _ => false, } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 5def43c2423..39e710cb77f 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>( def_id: LocalDefId, ) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> { match tcx.def_kind(def_id) { - DefKind::AnonConst => { + DefKind::AnonConst | DefKind::InlineConst => { let mut def_id = tcx .parent(def_id.to_def_id()) .unwrap_or_else(|| bug!("anon const or closure without a parent")); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5f3620b247e..d17e8875a1e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -13,7 +13,7 @@ #![feature(drain_filter)] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(iter_zip)] #![feature(let_else)] #![feature(never_type)] @@ -988,7 +988,7 @@ pub struct Resolver<'a> { non_macro_attr: Lrc<SyntaxExtension>, local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>, ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>, - unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>, + unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4f6e23d8f84..31fd9b989e1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -315,8 +315,13 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn check_unused_macros(&mut self) { - for (_, &(node_id, span)) in self.unused_macros.iter() { - self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition"); + for (_, &(node_id, ident)) in self.unused_macros.iter() { + self.lint_buffer.buffer_lint( + UNUSED_MACROS, + node_id, + ident.span, + &format!("unused macro definition: `{}`", ident.as_str()), + ); } } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 543cd0247a5..c7f8fe3a88a 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -739,6 +739,7 @@ impl<'tcx> SaveContext<'tcx> { | HirDefKind::ForeignMod | HirDefKind::LifetimeParam | HirDefKind::AnonConst + | HirDefKind::InlineConst | HirDefKind::Use | HirDefKind::Field | HirDefKind::GlobalAsm diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8a9e8739d03..3f0a6b0e2f6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -37,7 +37,7 @@ use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; -/// The different settings that the `-Z strip` flag can have. +/// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { /// Do not strip at all. @@ -165,6 +165,18 @@ pub enum LinkerPluginLto { Disabled, } +/// Used with `-Z assert-incr-state`. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum IncrementalStateAssertion { + /// Found and loaded an existing session directory. + /// + /// Note that this says nothing about whether any particular query + /// will be found to be red or green. + Loaded, + /// Did not load an existing session directory. + NotLoaded, +} + impl LinkerPluginLto { pub fn enabled(&self) -> bool { match *self { @@ -578,6 +590,7 @@ pub struct OutputFilenames { pub out_directory: PathBuf, filestem: String, pub single_output_file: Option<PathBuf>, + pub temps_directory: Option<PathBuf>, pub outputs: OutputTypes, } @@ -592,12 +605,14 @@ impl OutputFilenames { out_directory: PathBuf, out_filestem: String, single_output_file: Option<PathBuf>, + temps_directory: Option<PathBuf>, extra: String, outputs: OutputTypes, ) -> Self { OutputFilenames { out_directory, single_output_file, + temps_directory, outputs, filestem: format!("{}{}", out_filestem, extra), } @@ -608,7 +623,14 @@ impl OutputFilenames { .get(&flavor) .and_then(|p| p.to_owned()) .or_else(|| self.single_output_file.clone()) - .unwrap_or_else(|| self.temp_path(flavor, None)) + .unwrap_or_else(|| self.output_path(flavor)) + } + + /// Gets the output path where a compilation artifact of the given type + /// should be placed on disk. + pub fn output_path(&self, flavor: OutputType) -> PathBuf { + let extension = flavor.extension(); + self.with_directory_and_extension(&self.out_directory, &extension) } /// Gets the path where a compilation artifact of the given type for the @@ -643,11 +665,17 @@ impl OutputFilenames { extension.push_str(ext); } - self.with_extension(&extension) + let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); + + self.with_directory_and_extension(&temps_directory, &extension) } pub fn with_extension(&self, extension: &str) -> PathBuf { - let mut path = self.out_directory.join(&self.filestem); + self.with_directory_and_extension(&self.out_directory, extension) + } + + fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf { + let mut path = directory.join(&self.filestem); path.set_extension(extension); path } @@ -688,6 +716,7 @@ pub fn host_triple() -> &'static str { impl Default for Options { fn default() -> Options { Options { + assert_incr_state: None, crate_types: Vec::new(), optimize: OptLevel::No, debuginfo: DebugInfo::None, @@ -1610,6 +1639,21 @@ fn select_debuginfo( } } +crate fn parse_assert_incr_state( + opt_assertion: &Option<String>, + error_format: ErrorOutputType, +) -> Option<IncrementalStateAssertion> { + match opt_assertion { + Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), + Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), + Some(s) => early_error( + error_format, + &format!("unexpected incremental state assertion value: {}", s), + ), + None => None, + } +} + fn parse_native_lib_kind( matches: &getopts::Matches, kind: &str, @@ -1999,6 +2043,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let incremental = cg.incremental.as_ref().map(PathBuf::from); + let assert_incr_state = + parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format); + if debugging_opts.profile && incremental.is_some() { early_error( error_format, @@ -2163,6 +2210,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; Options { + assert_incr_state, crate_types, optimize: opt_level, debuginfo, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 71464ad9714..2c217e40aba 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,7 +4,6 @@ use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; - use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel}; @@ -150,6 +149,7 @@ top_level_options!( /// If `Some`, enable incremental compilation, using the given /// directory to store intermediate results. incremental: Option<PathBuf> [UNTRACKED], + assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED], debugging_opts: DebuggingOptions [SUBSTRUCT], prints: Vec<PrintRequest> [UNTRACKED], @@ -219,7 +219,7 @@ top_level_options!( /// generated code to parse an option into its respective field in the struct. There are a few /// hand-written parsers for parsing specific types of values in this module. macro_rules! options { - ($struct_name:ident, $stat:ident, $prefix:expr, $outputname:expr, + ($struct_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr, $($( #[$attr:meta] )* $opt:ident : $t:ty = ( $init:expr, $parse:ident, @@ -264,13 +264,15 @@ macro_rules! options { } pub const $stat: OptionDescrs<$struct_name> = - &[ $( (stringify!($opt), $opt, desc::$parse, $desc) ),* ]; + &[ $( (stringify!($opt), $optmod::$opt, desc::$parse, $desc) ),* ]; + mod $optmod { $( - fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { - parse::$parse(&mut redirect_field!(cg.$opt), v) + pub(super) fn $opt(cg: &mut super::$struct_name, v: Option<&str>) -> bool { + super::parse::$parse(&mut redirect_field!(cg.$opt), v) } )* + } ) } @@ -918,7 +920,7 @@ mod parse { } options! { - CodegenOptions, CG_OPTIONS, "C", "codegen", + CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen", // This list is in alphabetical order. // @@ -1013,6 +1015,8 @@ options! { "use soft float ABI (*eabihf targets only) (default: no)"), split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), + strip: Strip = (Strip::None, parse_strip, [UNTRACKED], + "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), target_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], @@ -1027,7 +1031,7 @@ options! { } options! { - DebuggingOptions, DB_OPTIONS, "Z", "debugging", + DebuggingOptions, DB_OPTIONS, dbopts, "Z", "debugging", // This list is in alphabetical order. // @@ -1042,6 +1046,9 @@ options! { "make cfg(version) treat the current version as incomplete (default: no)"), asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior) (default: no)"), + assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED], + "assert that the incremental cache is in given state: \ + either `loaded` or `not-loaded`."), ast_json: bool = (false, parse_bool, [UNTRACKED], "print the AST as JSON and halt (default: no)"), ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], @@ -1331,6 +1338,8 @@ options! { "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), + temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED], + "the directory the intermediate files are written to"), terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED], "set the current terminal width"), tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0f6a3ddccba..74b3cfa44c3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -411,7 +411,7 @@ impl Session { self.diagnostic().abort_if_errors(); } pub fn compile_status(&self) -> Result<(), ErrorReported> { - if self.has_errors() { + if self.diagnostic().has_errors_or_lint_errors() { self.diagnostic().emit_stashed_diagnostics(); Err(ErrorReported) } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b9730a1e420..99fa9f00094 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -271,6 +271,7 @@ symbols! { __S, __next, __try_var, + _args, _d, _e, _task_context, diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index aaf81648c51..0f01a78c8c5 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -1,7 +1,7 @@ use crate::spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut base = super::linux_gnu_base::opts(); + let mut base = super::linux_base::opts(); base.os = "android".to_string(); // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 53afe4ca068..4c80483fc1f 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -152,11 +152,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { }, cause, ); - if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { + let errors = fulfillcx.select_where_possible(&self.infcx); + if !errors.is_empty() { // This shouldn't happen, except for evaluate/fulfill mismatches, // but that's not a reason for an ICE (`predicate_may_hold` is conservative // by design). - debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); + debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors); return None; } let obligations = fulfillcx.pending_obligations(); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6452b520452..54f7b91080d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -187,9 +187,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { // an additional sanity check. let mut fulfill = FulfillmentContext::new(); fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); - fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { - panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e) - }); + let errors = fulfill.select_all_or_error(&infcx); + + if !errors.is_empty() { + panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); + } let body_id_map: FxHashMap<_, _> = infcx .inner diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index ec62ee40068..2ccb2534917 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -49,34 +49,32 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - self.select_where_possible(infcx)?; - - if self.obligations.is_empty() { - Ok(()) - } else { - let errors = self - .obligations - .iter() - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - // FIXME - does Chalk have a notation of 'root obligation'? - // This is just for diagnostics, so it's okay if this is wrong - root_obligation: obligation.clone(), - }) - .collect(); - Err(errors) + fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> { + { + let errors = self.select_where_possible(infcx); + + if !errors.is_empty() { + return errors; + } } + + // any remaining obligations are errors + self.obligations + .iter() + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation.clone(), + }) + .collect() } fn select_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + ) -> Vec<FulfillmentError<'tcx>> { assert!(!infcx.is_in_snapshot()); let mut errors = Vec::new(); @@ -147,7 +145,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { } } - if errors.is_empty() { Ok(()) } else { Err(errors) } + errors } fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index f06f0e32f41..bdd4fdd4043 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -120,7 +120,8 @@ where // In principle, we only need to do this so long as `result` // contains unbound type parameters. It could be a slight // optimization to stop iterating early. - if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { + let errors = fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { infcx.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8edb7069fc4..6b5d37c0f43 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -151,7 +151,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) { match infcx.tcx.def_kind(uv.def.did) { - DefKind::AnonConst => { + DefKind::AnonConst | DefKind::InlineConst => { let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); if mir_body.is_polymorphic { @@ -495,7 +495,7 @@ pub(super) fn thir_abstract_const<'tcx>( // we want to look into them or treat them as opaque projections. // // Right now we do neither of that and simply always fail to unify them. - DefKind::AnonConst => (), + DefKind::AnonConst | DefKind::InlineConst => (), _ => return Ok(None), } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0b88eb7572a..f8df0e25959 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -266,19 +266,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } if let ObligationCauseCode::CompareImplMethodObligation { - item_name, impl_item_def_id, trait_item_def_id, } | ObligationCauseCode::CompareImplTypeObligation { - item_name, impl_item_def_id, trait_item_def_id, } = obligation.cause.code { self.report_extra_impl_obligation( span, - item_name, impl_item_def_id, trait_item_def_id, &format!("`{}`", obligation.predicate), @@ -2012,6 +2009,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { Some(param) => param, _ => return, }; + let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id(); + let preds = generics.where_clause.predicates.iter(); + let explicitly_sized = preds + .filter_map(|pred| match pred { + hir::WherePredicate::BoundPredicate(bp) => Some(bp), + _ => None, + }) + .filter(|bp| bp.is_param_bound(param_def_id)) + .flat_map(|bp| bp.bounds) + .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); + if explicitly_sized { + return; + } debug!("maybe_suggest_unsized_generics: param={:?}", param); match node { hir::Node::Item( 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 2689e2134fc..0bf01afb575 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -706,36 +706,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let param_env = obligation.param_env; - let trait_ref = poly_trait_ref.skip_binder(); - - let found_ty = trait_ref.self_ty(); - let found_ty_str = found_ty.to_string(); - let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty); - let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]); - let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty); - let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&expected_trait_ref.def_id()) { + if blacklist.contains(&old_ref.def_id()) { return false; } - let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_imm_trait_ref.without_const().to_predicate(self.tcx), - )); - - let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_mut_trait_ref.without_const().to_predicate(self.tcx), - )); + let orig_ty = old_ref.self_ty().skip_binder(); + let mk_result = |new_ty| { + let new_ref = old_ref.rebind(ty::TraitRef::new( + old_ref.def_id(), + self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]), + )); + self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + new_ref.without_const().to_predicate(self.tcx), + )) + }; + let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty)); + let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty)); if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -747,8 +740,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let msg = format!( "the trait bound `{}: {}` is not satisfied", - found_ty_str, - expected_trait_ref.print_only_trait_path(), + orig_ty.to_string(), + old_ref.print_only_trait_path(), ); if has_custom_message { err.note(&msg); @@ -764,7 +757,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "expected an implementor of trait `{}`", - expected_trait_ref.print_only_trait_path(), + old_ref.print_only_trait_path(), ), ); @@ -807,21 +800,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { - let expected_trait_ref = obligation.parent_trait_ref; - let new_imm_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs)); - let new_mut_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs)); - return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); + try_borrowing(obligation.parent_trait_ref, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - return try_borrowing( - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)), - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)), - *poly_trait_ref, - &never_suggest_borrow[..], - ); + try_borrowing(*poly_trait_ref, &never_suggest_borrow[..]) } else { false } @@ -1474,7 +1457,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); - let generator_did_root = self.tcx.closure_base_def_id(generator_did); + let generator_did_root = self.tcx.typeck_root_def_id(generator_did); debug!( "maybe_note_obligation_cause_for_async_await: generator_did={:?} \ generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}", @@ -2354,11 +2337,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) }); } - ObligationCauseCode::CompareImplMethodObligation { - item_name, - trait_item_def_id, - .. - } => { + ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => { + let item_name = self.tcx.item_name(trait_item_def_id); let msg = format!( "the requirement `{}` appears on the impl method `{}` but not on the \ corresponding trait method", @@ -2383,9 +2363,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } err.span_note(assoc_span, &msg); } - ObligationCauseCode::CompareImplTypeObligation { - item_name, trait_item_def_id, .. - } => { + ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => { + let item_name = self.tcx.item_name(trait_item_def_id); let msg = format!( "the requirement `{}` appears on the associated impl type `{}` but not on the \ corresponding associated trait type", @@ -2475,13 +2454,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.param_env, ); - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; // `<T as Future>::Output` let projection_ty = ty::ProjectionTy { // `T` diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 465d1465d5d..e121837c987 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -126,10 +126,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { } /// Attempts to select obligations using `selcx`. - fn select( - &mut self, - selcx: &mut SelectionContext<'a, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); @@ -163,7 +160,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { errors.len() ); - if errors.is_empty() { Ok(()) } else { Err(errors) } + errors } } @@ -223,41 +220,36 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - self.select_where_possible(infcx)?; - - let errors: Vec<_> = self - .predicates - .to_errors(CodeAmbiguity) - .into_iter() - .map(to_fulfillment_error) - .collect(); - if errors.is_empty() { Ok(()) } else { Err(errors) } + fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> { + { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + } + + self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } fn select_all_with_constness_or_error( &mut self, infcx: &InferCtxt<'_, 'tcx>, constness: rustc_hir::Constness, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - self.select_with_constness_where_possible(infcx, constness)?; - - let errors: Vec<_> = self - .predicates - .to_errors(CodeAmbiguity) - .into_iter() - .map(to_fulfillment_error) - .collect(); - if errors.is_empty() { Ok(()) } else { Err(errors) } + ) -> Vec<FulfillmentError<'tcx>> { + { + let errors = self.select_with_constness_where_possible(infcx, constness); + if !errors.is_empty() { + return errors; + } + } + + self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } fn select_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + ) -> Vec<FulfillmentError<'tcx>> { let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } @@ -266,7 +258,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'tcx>, constness: hir::Constness, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + ) -> Vec<FulfillmentError<'tcx>> { let mut selcx = SelectionContext::with_constness(infcx, constness); self.select(&mut selcx) } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index cedd1aa54b8..fa8890fc352 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -33,7 +33,8 @@ pub fn can_type_implement_copy( | ty::Char | ty::RawPtr(..) | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), + | ty::Ref(_, _, hir::Mutability::Not) + | ty::Array(..) => return Ok(()), ty::Adt(adt, substs) => (adt, substs), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8f247184e88..91671994c5a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,7 +65,8 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError} pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_match::NonStructuralMatchTy; pub use self::util::{ - elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs, + elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, + elaborate_trait_ref, elaborate_trait_refs, }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ @@ -180,8 +181,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( // Note: we only assume something is `Copy` if we can // *definitively* show that it implements `Copy`. Otherwise, // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { + match fulfill_cx.select_all_or_error(infcx).as_slice() { + [] => { debug!( "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", ty, @@ -189,12 +190,12 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( ); true } - Err(e) => { + errors => { debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", - ty, - infcx.tcx.def_path_str(def_id), - e + ?ty, + bound = %infcx.tcx.def_path_str(def_id), + ?errors, + "type_known_to_meet_bound_modulo_regions" ); false } @@ -410,7 +411,10 @@ where } debug!("fully_normalize: select_all_or_error start"); - fulfill_cx.select_all_or_error(infcx)?; + let errors = fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return Err(errors); + } debug!("fully_normalize: select_all_or_error complete"); let resolved_value = infcx.resolve_vars_if_possible(normalized_value); debug!("fully_normalize: resolved_value={:?}", resolved_value); @@ -441,7 +445,9 @@ pub fn impossible_predicates<'tcx>( fulfill_cx.register_predicate_obligation(&infcx, obligation); } - fulfill_cx.select_all_or_error(&infcx).is_err() + let errors = fulfill_cx.select_all_or_error(&infcx); + + !errors.is_empty() }); debug!("impossible_predicates = {:?}", result); result diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index b5398f8a435..0a85676f431 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -77,10 +77,11 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); fulfill_cx.register_predicate_obligations(infcx, obligations); - if let Err(e) = fulfill_cx.select_all_or_error(infcx) { + let errors = fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, - &format!("errors selecting obligation during MIR typeck: {:?}", e), + &format!("errors selecting obligation during MIR typeck: {:?}", errors), ); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 481bfa4a26b..2aa214694cb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1859,7 +1859,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Char | ty::RawPtr(..) | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => { + | ty::Ref(_, _, hir::Mutability::Not) + | ty::Array(..) => { // Implementations provided in libcore None } @@ -1872,11 +1873,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Ref(_, _, hir::Mutability::Mut) => None, - ty::Array(element_ty, _) => { - // (*) binder moved here - Where(obligation.predicate.rebind(vec![element_ty])) - } - ty::Tuple(tys) => { // (*) binder moved here Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect())) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index f9867f0671e..b64c5559227 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -225,8 +225,18 @@ fn fulfill_implication<'a, 'tcx>( for oblig in obligations.chain(more_obligations) { fulfill_cx.register_predicate_obligation(&infcx, oblig); } - match fulfill_cx.select_all_or_error(infcx) { - Err(errors) => { + match fulfill_cx.select_all_or_error(infcx).as_slice() { + [] => { + debug!( + "fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, target_trait_ref + ); + + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_vars_if_possible(target_substs)) + } + errors => { // no dice! debug!( "fulfill_implication: for impls on {:?} and {:?}, \ @@ -238,17 +248,6 @@ fn fulfill_implication<'a, 'tcx>( ); Err(()) } - - Ok(()) => { - debug!( - "fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, target_trait_ref - ); - - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(target_substs)) - } } }) } @@ -292,6 +291,11 @@ pub(super) fn specialization_graph_provider( sg } +// This function is only used when +// encountering errors and inlining +// it negatively impacts perf. +#[cold] +#[inline(never)] fn report_overlap_conflict( tcx: TyCtxt<'_>, overlap: OverlapError, @@ -444,8 +448,12 @@ fn report_conflicting_impls( match used_to_be_allowed { None => { sg.has_errored = true; - let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); - decorate(LintDiagnosticBuilder::new(err)); + if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) { + let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); + decorate(LintDiagnosticBuilder::new(err)); + } else { + tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"); + } } Some(kind) => { let lint = match kind { diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index a398e847b93..3d713822278 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -103,7 +103,7 @@ fn type_marked_structural( // // 2. We are sometimes doing future-incompatibility lints for // now, so we do not want unconditional errors here. - fulfillment_cx.select_all_or_error(infcx).is_ok() + fulfillment_cx.select_all_or_error(infcx).is_empty() } /// This implements the traversal over the structure of a given type to try to diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 37e00733737..92f2760e62c 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -128,9 +128,9 @@ fn compute_implied_outlives_bounds<'tcx>( // Ensure that those obligations that we had to solve // get solved *here*. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => Ok(implied_bounds), - Err(_) => Err(NoSolution), + match fulfill_cx.select_all_or_error(infcx).as_slice() { + [] => Ok(implied_bounds), + _ => Err(NoSolution), } } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 87b729faa54..13ffb2a5adc 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -362,7 +362,7 @@ fn resolve_associated_item<'tcx>( let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); match self_ty.kind() { _ if is_copy => (), - ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {} + ty::Closure(..) | ty::Tuple(..) => {} _ => return Ok(None), }; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 3f66e5b4ebf..595b623b020 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -17,7 +17,8 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> // needs drop. let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some(); + let res = + drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some(); debug!("needs_drop_raw({:?}) = {:?}", query, res); res @@ -27,10 +28,15 @@ fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let res = - drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx)) - .next() - .is_some(); + let res = drop_tys_helper( + tcx, + query.value, + query.param_env, + adt_consider_insignificant_dtor(tcx), + true, + ) + .next() + .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); res } @@ -141,9 +147,9 @@ where Ok(tys) => tys, }; for required_ty in tys { - let subst_ty = + let required = tcx.normalize_erasing_regions(self.param_env, required_ty); - queue_type(self, subst_ty); + queue_type(self, required); } } ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => { @@ -186,16 +192,39 @@ fn drop_tys_helper<'tcx>( ty: Ty<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>, + only_significant: bool, ) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> { + fn with_query_cache<'tcx>( + tcx: TyCtxt<'tcx>, + iter: impl IntoIterator<Item = Ty<'tcx>>, + only_significant: bool, + ) -> NeedsDropResult<Vec<Ty<'tcx>>> { + iter.into_iter().try_fold(Vec::new(), |mut vec, subty| { + match subty.kind() { + ty::Adt(adt_id, subst) => { + for subty in if only_significant { + tcx.adt_significant_drop_tys(adt_id.did)? + } else { + tcx.adt_drop_tys(adt_id.did)? + } { + vec.push(subty.subst(tcx, subst)); + } + } + _ => vec.push(subty), + }; + Ok(vec) + }) + } + let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("drop_tys_helper: `{:?}` is manually drop", adt_def); - return Ok(Vec::new().into_iter()); + Ok(Vec::new()) } else if let Some(dtor_info) = adt_has_dtor(adt_def) { match dtor_info { DtorType::Significant => { debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def); - return Err(AlwaysRequiresDrop); + Err(AlwaysRequiresDrop) } DtorType::Insignificant => { debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def); @@ -203,22 +232,27 @@ fn drop_tys_helper<'tcx>( // Since the destructor is insignificant, we just want to make sure all of // the passed in type parameters are also insignificant. // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex. - return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter()); + with_query_cache(tcx, substs.types(), only_significant) } } } else if adt_def.is_union() { debug!("drop_tys_helper: `{:?}` is a union", adt_def); - return Ok(Vec::new().into_iter()); + Ok(Vec::new()) + } else { + with_query_cache( + tcx, + adt_def.all_fields().map(|field| { + let r = tcx.type_of(field.did).subst(tcx, substs); + debug!( + "drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", + field, substs, r + ); + r + }), + only_significant, + ) } - Ok(adt_def - .all_fields() - .map(|field| { - let r = tcx.type_of(field.did).subst(tcx, substs); - debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r); - r - }) - .collect::<Vec<_>>() - .into_iter()) + .map(|v| v.into_iter()) }; NeedsDropTypes::new(tcx, param_env, ty, adt_components) @@ -252,20 +286,24 @@ fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, Alw // significant. let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); - drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor) + // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)` + drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor, false) .collect::<Result<Vec<_>, _>>() .map(|components| tcx.intern_type_list(&components)) } - +// If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed +// a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitue the generic parameters +// of the ADT into the outputted `ty`s. fn adt_significant_drop_tys( tcx: TyCtxt<'_>, def_id: DefId, ) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> { drop_tys_helper( tcx, - tcx.type_of(def_id), + tcx.type_of(def_id), // identical to `tcx.make_adt(def, identity_substs)` tcx.param_env(def_id), adt_consider_insignificant_dtor(tcx), + true, ) .collect::<Result<Vec<_>, _>>() .map(|components| tcx.intern_type_list(&components)) diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 84327a2880e..2f187997b55 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -672,6 +672,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_label(span, "explicit generic argument not allowed"); } + err.note( + "see issue #83701 <https://github.com/rust-lang/rust/issues/83701> \ + for more information", + ); + if tcx.sess.is_nightly_build() { + err.help( + "add `#![feature(explicit_generic_args_with_impl_trait)]` \ + to the crate attributes to enable", + ); + } + err.emit(); } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 5040c4db951..bb1d9744e66 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -371,16 +371,26 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let param_env = tcx.param_env(item_def_id); for field in fields { let field_ty = field.ty(tcx, substs); - // We are currently checking the type this field came from, so it must be local. - let field_span = tcx.hir().span_if_local(field.did).unwrap(); if field_ty.needs_drop(tcx, param_env) { + let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { + // We are currently checking the type this field came from, so it must be local. + Some(Node::Field(field)) => (field.span, field.ty.span), + _ => unreachable!("mir field has to correspond to hir field"), + }; struct_span_err!( tcx.sess, field_span, E0740, "unions may not contain fields that need dropping" ) - .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") + .multipart_suggestion_verbose( + "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped", + vec![ + (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")), + (ty_span.shrink_to_hi(), ">".into()), + ], + Applicability::MaybeIncorrect, + ) .emit(); return false; } @@ -663,8 +673,9 @@ fn check_opaque_meets_bounds<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); } // Finally, resolve all regions. This catches wily misuses of diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 410ac24b1f1..4a41552a5fb 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_substs = InternalSubsts::identity_for_item( self.tcx, - self.tcx.closure_base_def_id(expr_def_id.to_def_id()), + self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { @@ -257,8 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_gen { // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return` // associated item and not yield. - let return_assoc_item = - self.tcx.associated_items(gen_trait).in_definition_order().nth(1).unwrap().def_id; + let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1]; if return_assoc_item != projection.projection_def_id() { debug!("deduce_sig_from_projection: not return assoc item of generator"); return None; @@ -694,8 +693,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The `Future` trait has only one associted item, `Output`, // so check that this is what we see. - let output_assoc_item = - self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id; + let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0]; if output_assoc_item != predicate.projection_ty.item_def_id { span_bug!( cause_span, diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index ad65a0ba62a..28712e06582 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -950,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut fcx = traits::FulfillmentContext::new_in_snapshot(); fcx.register_predicate_obligations(self, ok.obligations); - fcx.select_where_possible(&self).is_ok() + fcx.select_where_possible(&self).is_empty() }) } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 7c262dcf723..cbfd8747ecf 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -92,7 +92,6 @@ fn compare_predicate_entailment<'tcx>( impl_m_span, impl_m_hir_id, ObligationCauseCode::CompareImplMethodObligation { - item_name: impl_m.ident.name, impl_item_def_id: impl_m.def_id, trait_item_def_id: trait_m.def_id, }, @@ -391,8 +390,9 @@ fn compare_predicate_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); return Err(ErrorReported); } @@ -1094,8 +1094,9 @@ crate fn compare_const_impl<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); return; } @@ -1165,7 +1166,6 @@ fn compare_type_predicate_entailment<'tcx>( impl_ty_span, impl_ty_hir_id, ObligationCauseCode::CompareImplTypeObligation { - item_name: impl_ty.ident.name, impl_item_def_id: impl_ty.def_id, trait_item_def_id: trait_ty.def_id, }, @@ -1210,8 +1210,9 @@ fn compare_type_predicate_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); return Err(ErrorReported); } @@ -1427,10 +1428,10 @@ pub fn check_type_bounds<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = - inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness) - { - infcx.report_fulfillment_errors(errors, None, false); + let errors = + inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); return Err(ErrorReported); } diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index fd150978f00..4b4d29307ff 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -113,9 +113,10 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( } } - if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { + let errors = fulfillment_cx.select_all_or_error(&infcx); + if !errors.is_empty() { // this could be reached when we get lazy normalization - infcx.report_fulfillment_errors(errors, None, false); + infcx.report_fulfillment_errors(&errors, None, false); return Err(ErrorReported); } @@ -239,8 +240,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( ty::PredicateKind::ConstEvaluatable(a), ty::PredicateKind::ConstEvaluatable(b), ) => tcx.try_unify_abstract_consts((a, b)), - (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => { - relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok() + ( + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)), + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)), + ) => { + relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok() + && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok() } _ => predicate == p, } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 3cba7991cca..5c79a067e9f 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -30,15 +30,17 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty; +use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; +use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts}; +use rustc_middle::ty::relate::expected_found_bool; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::Ty; -use rustc_middle::ty::TypeFoldable; -use rustc_middle::ty::{AdtKind, Visibility}; +use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; +use rustc_session::parse::feature_err; use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -323,7 +325,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty, + ExprKind::ConstBlock(ref anon_const) => { + self.check_expr_const_block(anon_const, expected, expr) + } ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -1166,6 +1170,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_array(element_ty, args.len() as u64) } + fn check_expr_const_block( + &self, + anon_const: &'tcx hir::AnonConst, + expected: Expectation<'tcx>, + _expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + let body = self.tcx.hir().body(anon_const.body); + + // Create a new function context. + let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id); + crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body); + + let ty = fcx.check_expr_with_expectation(&body.value, expected); + fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); + fcx.write_ty(anon_const.hir_id, ty); + ty + } + fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, @@ -1262,49 +1284,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); } - let error_happened = self.check_expr_struct_fields( + self.check_expr_struct_fields( adt_ty, expected, expr.hir_id, qpath.span(), variant, fields, - base_expr.is_none(), + base_expr, expr.span, ); - if let Some(base_expr) = base_expr { - // If check_expr_struct_fields hit an error, do not attempt to populate - // the fields with the base_expr. This could cause us to hit errors later - // when certain fields are assumed to exist that in fact do not. - if !error_happened { - self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {}); - match adt_ty.kind() { - ty::Adt(adt, substs) if adt.is_struct() => { - let fru_field_types = adt - .non_enum_variant() - .fields - .iter() - .map(|f| { - self.normalize_associated_types_in( - expr.span, - f.ty(self.tcx, substs), - ) - }) - .collect(); - - self.typeck_results - .borrow_mut() - .fru_field_types_mut() - .insert(expr.hir_id, fru_field_types); - } - _ => { - self.tcx - .sess - .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); - } - } - } - } + self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); adt_ty } @@ -1317,9 +1307,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], - check_completeness: bool, + base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, expr_span: Span, - ) -> bool { + ) { let tcx = self.tcx; let adt_ty_hint = self @@ -1394,7 +1384,116 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .emit(); } - } else if check_completeness && !error_happened && !remaining_fields.is_empty() { + } + + // If check_expr_struct_fields hit an error, do not attempt to populate + // the fields with the base_expr. This could cause us to hit errors later + // when certain fields are assumed to exist that in fact do not. + if error_happened { + return; + } + + if let Some(base_expr) = base_expr { + // FIXME: We are currently creating two branches here in order to maintain + // consistency. But they should be merged as much as possible. + let fru_tys = if self.tcx.features().type_changing_struct_update { + let base_ty = self.check_expr(base_expr); + match adt_ty.kind() { + ty::Adt(adt, substs) if adt.is_struct() => { + match base_ty.kind() { + ty::Adt(base_adt, base_subs) if adt == base_adt => { + variant + .fields + .iter() + .map(|f| { + let fru_ty = self.normalize_associated_types_in( + expr_span, + self.field_ty(base_expr.span, f, base_subs), + ); + let ident = self.tcx.adjust_ident(f.ident, variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + let target_ty = + self.field_ty(base_expr.span, f, substs); + let cause = self.misc(base_expr.span); + match self + .at(&cause, self.param_env) + .sup(target_ty, fru_ty) + { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations) + } + // FIXME: Need better diagnostics for `FieldMisMatch` error + Err(_) => self + .report_mismatched_types( + &cause, + target_ty, + fru_ty, + FieldMisMatch( + variant.ident.name, + ident.name, + ), + ) + .emit(), + } + } + fru_ty + }) + .collect() + } + _ => { + return self + .report_mismatched_types( + &self.misc(base_expr.span), + adt_ty, + base_ty, + Sorts(expected_found_bool(true, adt_ty, base_ty)), + ) + .emit(); + } + } + } + _ => { + return self + .tcx + .sess + .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); + } + } + } else { + self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { + let base_ty = self.check_expr(base_expr); + let same_adt = match (adt_ty.kind(), base_ty.kind()) { + (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true, + _ => false, + }; + if self.tcx.sess.is_nightly_build() && same_adt { + feature_err( + &self.tcx.sess.parse_sess, + sym::type_changing_struct_update, + base_expr.span, + "type changing struct updating is experimental", + ) + .emit(); + } + }); + match adt_ty.kind() { + ty::Adt(adt, substs) if adt.is_struct() => variant + .fields + .iter() + .map(|f| { + self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs)) + }) + .collect(), + _ => { + return self + .tcx + .sess + .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); + } + } + }; + self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys); + } else if kind_name != "union" && !remaining_fields.is_empty() { let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| { !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) }); @@ -1405,8 +1504,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_missing_fields(adt_ty, span, remaining_fields); } } - - error_happened } fn check_struct_fields_on_error( @@ -1632,7 +1729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|field| { // ignore already set fields and private fields from non-local crates if skip.iter().any(|&x| x == field.ident.name) - || (!variant.def_id.is_local() && field.vis != Visibility::Public) + || (!variant.def_id.is_local() && !field.vis.is_public()) { None } else { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 5308126f252..aae59eee991 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -642,11 +642,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - if let Err(errors) = self + let errors = self .fulfillment_cx .borrow_mut() - .select_all_with_constness_or_error(&self, self.inh.constness) - { + .select_all_with_constness_or_error(&self, self.inh.constness); + + if !errors.is_empty() { self.report_fulfillment_errors(&errors, self.inh.body_id, false); } } @@ -657,13 +658,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fallback_has_occurred: bool, mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), ) { - let result = self + let mut result = self .fulfillment_cx .borrow_mut() .select_with_constness_where_possible(self, self.inh.constness); - if let Err(mut errors) = result { - mutate_fulfillment_errors(&mut errors); - self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + if !result.is_empty() { + mutate_fulfillment_errors(&mut result); + self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred); } } @@ -793,14 +794,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we can. We don't care if some things turn // out unconstrained or ambiguous, as we're // just trying to get hints here. - self.save_and_restore_in_snapshot_flag(|_| { + let errors = self.save_and_restore_in_snapshot_flag(|_| { let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx); for obligation in ok.obligations { fulfill.register_predicate_obligation(self, obligation); } fulfill.select_where_possible(self) - }) - .map_err(|_| ())?; + }); + + if !errors.is_empty() { + return Err(()); + } } Err(_) => return Err(()), } @@ -948,7 +952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = rustc_errors::struct_span_err!( self.sess(), self_ty.span, - E0783, + E0782, "{}", msg, ); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index dcc635a1f00..6c7d3a0c9c0 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -14,6 +14,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty}; use rustc_span::symbol::{kw, sym}; +use rustc_middle::ty::subst::GenericArgKind; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -232,48 +233,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.ident); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let mut sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - vec![( - expr.span, - format!("{}{}", &receiver[..max_len], method_call), - )] + if !methods.is_empty() { + if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { + let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) + .filter_map(|(receiver, method)| { + let method_call = format!(".{}()", method.ident); + if receiver.ends_with(&method_call) { + None // do not suggest code that is already there (#53348) } else { - if expr.precedence().order() < ExprPrecedence::MethodCall.order() { - vec![ - (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!("){}", method_call)), - ] + let method_call_list = [".to_vec()", ".to_string()"]; + let mut sugg = if receiver.ends_with(".clone()") + && method_call_list.contains(&method_call.as_str()) + { + let max_len = receiver.rfind('.').unwrap(); + vec![( + expr.span, + format!("{}{}", &receiver[..max_len], method_call), + )] } else { - vec![(expr.span.shrink_to_hi(), method_call)] + if expr.precedence().order() + < ExprPrecedence::MethodCall.order() + { + vec![ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!("){}", method_call)), + ] + } else { + vec![(expr.span.shrink_to_hi(), method_call)] + } + }; + if is_struct_pat_shorthand_field { + sugg.insert( + 0, + (expr.span.shrink_to_lo(), format!("{}: ", receiver)), + ); } - }; - if is_struct_pat_shorthand_field { - sugg.insert( - 0, - (expr.span.shrink_to_lo(), format!("{}: ", receiver)), + Some(sugg) + } + }) + .peekable(); + if suggestions.peek().is_some() { + err.multipart_suggestions( + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } else if found.to_string().starts_with("Option<") + && expected.to_string() == "Option<&str>" + { + if let ty::Adt(_def, subst) = found.kind() { + if subst.len() != 0 { + if let GenericArgKind::Type(ty) = subst[0].unpack() { + let peeled = ty.peel_refs().to_string(); + if peeled == "String" { + let ref_cnt = ty.to_string().len() - peeled.len(); + let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)); + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + "try converting the passed type into a `&str`", + result, + Applicability::MaybeIncorrect, ); } - Some(sugg) } - }) - .peekable(); - if suggestions.peek().is_some() { - err.multipart_suggestions( - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); + } } } } diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index b0cb8443bfb..6314f2aba4e 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -324,9 +324,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), sym::discriminant_value => { - let assoc_items = - tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); - let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + let assoc_items = tcx.associated_item_def_ids( + tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + ); + let discriminant_def_id = assoc_items[0]; let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) }; ( diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index dc54f63f49c..e7e4e72f6c1 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -162,7 +162,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { match &pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { - let region = self.next_region_var(infer::Autoref(self.span, pick.item)); + let region = self.next_region_var(infer::Autoref(self.span)); target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target }); let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 13f475cd9e0..661ced952c7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -478,6 +478,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); + let is_string_or_ref_str = match actual.kind() { + ty::Ref(_, ty, _) => { + ty.is_str() + || matches!( + ty.kind(), + ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did) + ) + } + ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did), + _ => false, + }; + if is_string_or_ref_str && item_name.name == sym::iter { + err.span_suggestion_verbose( + item_name.span, + "because of the in-memory representation of `&str`, to obtain \ + an `Iterator` over each of its codepoint use method `chars`", + String::from("chars"), + Applicability::MachineApplicable, + ); + } if let ty::Adt(adt, _) = rcvr_ty.kind() { let mut inherent_impls_candidate = self .tcx @@ -1410,7 +1430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } // We only want to suggest public or local traits (#45781). - item.vis == ty::Visibility::Public || info.def_id.is_local() + item.vis.is_public() || info.def_id.is_local() }) .is_some() }) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 7450b4a4ef1..d19e99606bc 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -297,9 +297,9 @@ fn primary_body_of( fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id); - if outer_def_id != def_id { - return tcx.has_typeck_results(outer_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.has_typeck_results(typeck_root_def_id); } if let Some(def_id) = def_id.as_local() { @@ -348,9 +348,9 @@ fn typeck_with_fallback<'tcx>( ) -> &'tcx ty::TypeckResults<'tcx> { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); - if outer_def_id != def_id { - return tcx.typeck(outer_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); + if typeck_root_def_id != def_id { + return tcx.typeck(typeck_root_def_id); } let id = tcx.hir().local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index dd094745331..9c53a1d4eb6 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -826,10 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys)); let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx); fulfill.register_predicate_obligation(self, obligation); - Err(match fulfill.select_where_possible(&self.infcx) { - Err(errors) => errors, - _ => vec![], - }) + Err(fulfill.select_where_possible(&self.infcx)) } } } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5aa11cce25f..cbf33cf1b78 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -292,7 +292,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. - PatKind::Lit(lt) => match self.check_expr(lt).kind() { + // + // Call `resolve_vars_if_possible` here for inline const blocks. + PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 86d4e4d2b11..d2d8b14dd96 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -341,6 +341,29 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_region_obligations(body_id.hir_id); } + fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) { + debug!("visit_inline_const(id={:?})", id); + + // Save state of current function. We will restore afterwards. + let old_body_id = self.body_id; + let old_body_owner = self.body_owner; + let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); + + let body_id = body.id(); + self.body_id = body_id.hir_id; + self.body_owner = self.tcx.hir().body_owner_def_id(body_id); + + self.outlives_environment.save_implied_bounds(body_id.hir_id); + + self.visit_body(body); + self.visit_region_obligations(body_id.hir_id); + + // Restore state from previous function. + self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); + self.body_id = old_body_id; + self.body_owner = old_body_owner; + } + fn visit_region_obligations(&mut self, hir_id: hir::HirId) { debug!("visit_region_obligations: hir_id={:?}", hir_id); @@ -406,13 +429,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // `visit_fn_body`. We will restore afterwards. let old_body_id = self.body_id; let old_body_owner = self.body_owner; - let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); + let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); let body = self.tcx.hir().body(body_id); self.visit_fn_body(hir_id, body, span); // Restore state from previous function. - self.outlives_environment.pop_snapshot_post_closure(env_snapshot); + self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); self.body_id = old_body_id; self.body_owner = old_body_owner; } @@ -460,6 +483,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { intravisit::walk_expr(self, expr); } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.tcx.hir().body(anon_const.body); + self.visit_inline_const(anon_const.hir_id, body); + } + _ => intravisit::walk_expr(self, expr), } } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 774d8078e52..5f5d308a332 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -148,10 +148,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind { - let body = self.fcx.tcx.hir().body(body_id); - self.visit_body(body); - self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc); + match expr.kind { + hir::ExprKind::Closure(cc, _, body_id, _, _) => { + let body = self.fcx.tcx.hir().body(body_id); + self.visit_body(body); + self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc); + } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.fcx.tcx.hir().body(anon_const.body); + self.visit_body(body); + } + _ => {} } intravisit::walk_expr(self, expr); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index c1adc2894cc..0050ac99cb1 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1641,19 +1641,38 @@ fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. -fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { +fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirId) { let empty_env = ty::ParamEnv::empty(); let def_id = fcx.tcx.hir().local_def_id(id); - let predicates = fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, _)| *p); + let predicates_with_span = + fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, span)| (*p, *span)); // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates); + let implied_obligations = traits::elaborate_predicates_with_span(fcx.tcx, predicates_with_span); for obligation in implied_obligations { let pred = obligation.predicate; // Match the existing behavior. if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() { let pred = fcx.normalize_associated_types_in(span, pred); + let hir_node = fcx.tcx.hir().find(id); + + // only use the span of the predicate clause (#90869) + + if let Some(hir::Generics { where_clause, .. }) = + hir_node.and_then(|node| node.generics()) + { + let obligation_span = obligation.cause.span(fcx.tcx); + + span = where_clause + .predicates + .iter() + // There seems to be no better way to find out which predicate we are in + .find(|pred| pred.span().contains(obligation_span)) + .map(|pred| pred.span()) + .unwrap_or(obligation_span); + } + let obligation = traits::Obligation::new( traits::ObligationCause::new(span, id, traits::TrivialBound), empty_env, diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index d951df94dcf..fdc8b6b5e64 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -282,6 +282,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) => { self.visit_field_id(e.hir_id); } + hir::ExprKind::ConstBlock(anon_const) => { + self.visit_node_id(e.span, anon_const.hir_id); + + let body = self.tcx().hir().body(anon_const.body); + self.visit_body(body); + } _ => {} } diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index d818771f780..372e83592b9 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -263,7 +263,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } // Check that all transitive obligations are satisfied. - if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } @@ -522,7 +523,8 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI fulfill_cx.register_predicate_obligation(&infcx, predicate); // Check that all transitive obligations are satisfied. - if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs index 079604f128d..377ebf1fe2a 100644 --- a/compiler/rustc_typeck/src/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -168,6 +168,7 @@ pub fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; use self::inherent_impls::{crate_inherent_impls, inherent_impls}; use self::inherent_impls_overlap::crate_inherent_impls_overlap_check; + use self::orphan::orphan_check_crate; *providers = Providers { coherent_trait, @@ -175,6 +176,7 @@ pub fn provide(providers: &mut Providers) { inherent_impls, crate_inherent_impls_overlap_check, coerce_unsized_info, + orphan_check_crate, ..*providers }; } @@ -195,13 +197,13 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) { } pub fn check_coherence(tcx: TyCtxt<'_>) { + tcx.sess.time("unsafety_checking", || unsafety::check(tcx)); + tcx.ensure().orphan_check_crate(()); + for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } - tcx.sess.time("unsafety_checking", || unsafety::check(tcx)); - tcx.sess.time("orphan_checking", || orphan::check(tcx)); - // these queries are executed for side-effects (error reporting): tcx.ensure().crate_inherent_impls(()); tcx.ensure().crate_inherent_impls_overlap_check(()); diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 0326d1fd74f..b450d3f6c08 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -2,250 +2,266 @@ //! crate or pertains to a type defined in this crate. use rustc_errors::struct_span_err; +use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LocalDefId; +use rustc_span::Span; use rustc_trait_selection::traits; -pub fn check(tcx: TyCtxt<'_>) { - let mut orphan = OrphanChecker { tcx }; - tcx.hir().visit_all_item_likes(&mut orphan); +pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] { + let mut errors = Vec::new(); + for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) { + for &impl_of_trait in impls_of_trait { + match orphan_check_impl(tcx, impl_of_trait) { + Ok(()) => {} + Err(ErrorReported) => errors.push(impl_of_trait), + } + } + } + tcx.arena.alloc_slice(&errors) } -struct OrphanChecker<'tcx> { - tcx: TyCtxt<'tcx>, -} +#[instrument(skip(tcx), level = "debug")] +fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorReported> { + let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); + let trait_def_id = trait_ref.def_id; -impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { - /// Checks exactly one impl for orphan rules and other such - /// restrictions. In this fn, it can happen that multiple errors - /// apply to a specific impl, so just return after reporting one - /// to prevent inundating the user with a bunch of similar error - /// reports. - fn visit_item(&mut self, item: &hir::Item<'_>) { - // "Trait" impl - if let hir::ItemKind::Impl(hir::Impl { - generics, of_trait: Some(ref tr), self_ty, .. - }) = &item.kind - { - debug!( - "coherence2::orphan check: trait impl {}", - self.tcx.hir().node_to_string(item.hir_id()) - ); - let trait_ref = self.tcx.impl_trait_ref(item.def_id).unwrap(); - let trait_def_id = trait_ref.def_id; - let sm = self.tcx.sess.source_map(); - let sp = sm.guess_head_span(item.span); - match traits::orphan_check(self.tcx, item.def_id.to_def_id()) { - Ok(()) => {} - Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => { - let mut err = struct_span_err!( - self.tcx.sess, - sp, - E0117, - "only traits defined in the current crate can be implemented for \ - arbitrary types" - ); - err.span_label(sp, "impl doesn't use only types from inside the current crate"); - for (ty, is_target_ty) in &tys { - let mut ty = *ty; - self.tcx.infer_ctxt().enter(|infcx| { - // Remove the lifetimes unnecessary for this error. - ty = infcx.freshen(ty); - }); - ty = match ty.kind() { - // Remove the type arguments from the output, as they are not relevant. - // You can think of this as the reverse of `resolve_vars_if_possible`. - // That way if we had `Vec<MyType>`, we will properly attribute the - // problem to `Vec<T>` and avoid confusing the user if they were to see - // `MyType` in the error. - ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()), - _ => ty, - }; - let this = "this".to_string(); - let (ty, postfix) = match &ty.kind() { - ty::Slice(_) => (this, " because slices are always foreign"), - ty::Array(..) => (this, " because arrays are always foreign"), - ty::Tuple(..) => (this, " because tuples are always foreign"), - _ => (format!("`{}`", ty), ""), - }; - let msg = format!("{} is not defined in the current crate{}", ty, postfix); - if *is_target_ty { - // Point at `D<A>` in `impl<A, B> for C<B> in D<A>` - err.span_label(self_ty.span, &msg); - } else { - // Point at `C<B>` in `impl<A, B> for C<B> in D<A>` - err.span_label(tr.path.span, &msg); - } - } - err.note("define and implement a trait or new type instead"); - err.emit(); - return; - } - Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => { - let mut sp = sp; - for param in generics.params { - if param.name.ident().to_string() == param_ty.to_string() { - sp = param.span; - } - } + let item = tcx.hir().item(hir::ItemId { def_id }); + let impl_ = match item.kind { + hir::ItemKind::Impl(ref impl_) => impl_, + _ => bug!("{:?} is not an impl: {:?}", def_id, item), + }; + let sp = tcx.sess.source_map().guess_head_span(item.span); + let tr = impl_.of_trait.as_ref().unwrap(); + match traits::orphan_check(tcx, item.def_id.to_def_id()) { + Ok(()) => {} + Err(err) => emit_orphan_check_error( + tcx, + sp, + tr.path.span, + impl_.self_ty.span, + &impl_.generics, + err, + )?, + } + + // In addition to the above rules, we restrict impls of auto traits + // so that they can only be implemented on nominal types, such as structs, + // enums or foreign types. To see why this restriction exists, consider the + // following example (#22978). Imagine that crate A defines an auto trait + // `Foo` and a fn that operates on pairs of types: + // + // ``` + // // Crate A + // auto trait Foo { } + // fn two_foos<A:Foo,B:Foo>(..) { + // one_foo::<(A,B)>(..) + // } + // fn one_foo<T:Foo>(..) { .. } + // ``` + // + // This type-checks fine; in particular the fn + // `two_foos` is able to conclude that `(A,B):Foo` + // because `A:Foo` and `B:Foo`. + // + // Now imagine that crate B comes along and does the following: + // + // ``` + // struct A { } + // struct B { } + // impl Foo for A { } + // impl Foo for B { } + // impl !Send for (A, B) { } + // ``` + // + // This final impl is legal according to the orphan + // rules, but it invalidates the reasoning from + // `two_foos` above. + debug!( + "trait_ref={:?} trait_def_id={:?} trait_is_auto={}", + trait_ref, + trait_def_id, + tcx.trait_is_auto(trait_def_id) + ); + + if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { + let self_ty = trait_ref.self_ty(); + let opt_self_def_id = match *self_ty.kind() { + ty::Adt(self_def, _) => Some(self_def.did), + ty::Foreign(did) => Some(did), + _ => None, + }; - match local_type { - Some(local_type) => { - struct_span_err!( - self.tcx.sess, - sp, - E0210, - "type parameter `{}` must be covered by another type \ - when it appears before the first local type (`{}`)", - param_ty, - local_type - ) - .span_label( - sp, - format!( - "type parameter `{}` must be covered by another type \ - when it appears before the first local type (`{}`)", - param_ty, local_type - ), - ) - .note( - "implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local, \ - and no uncovered type parameters appear before that first \ - local type", - ) - .note( - "in this case, 'before' refers to the following order: \ - `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \ - where `T0` is the first and `Tn` is the last", - ) - .emit(); - } - None => { - struct_span_err!( - self.tcx.sess, - sp, - E0210, - "type parameter `{}` must be used as the type parameter for some \ - local type (e.g., `MyStruct<{}>`)", - param_ty, - param_ty - ).span_label(sp, format!( - "type parameter `{}` must be used as the type parameter for some \ - local type", - param_ty, - )).note("implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local" - ).note("only traits defined in the current crate can be \ - implemented for a type parameter" - ).emit(); - } - }; - return; + let msg = match opt_self_def_id { + // We only want to permit nominal types, but not *all* nominal types. + // They must be local to the current crate, so that people + // can't do `unsafe impl Send for Rc<SomethingLocal>` or + // `impl !Send for Box<SomethingLocalAndSend>`. + Some(self_def_id) => { + if self_def_id.is_local() { + None + } else { + Some(( + format!( + "cross-crate traits with a default impl, like `{}`, \ + can only be implemented for a struct/enum type \ + defined in the current crate", + tcx.def_path_str(trait_def_id) + ), + "can't implement cross-crate trait for type in another crate", + )) } } + _ => Some(( + format!( + "cross-crate traits with a default impl, like `{}`, can \ + only be implemented for a struct/enum type, not `{}`", + tcx.def_path_str(trait_def_id), + self_ty + ), + "can't implement cross-crate trait with a default impl for \ + non-struct/enum type", + )), + }; - // In addition to the above rules, we restrict impls of auto traits - // so that they can only be implemented on nominal types, such as structs, - // enums or foreign types. To see why this restriction exists, consider the - // following example (#22978). Imagine that crate A defines an auto trait - // `Foo` and a fn that operates on pairs of types: - // - // ``` - // // Crate A - // auto trait Foo { } - // fn two_foos<A:Foo,B:Foo>(..) { - // one_foo::<(A,B)>(..) - // } - // fn one_foo<T:Foo>(..) { .. } - // ``` - // - // This type-checks fine; in particular the fn - // `two_foos` is able to conclude that `(A,B):Foo` - // because `A:Foo` and `B:Foo`. - // - // Now imagine that crate B comes along and does the following: - // - // ``` - // struct A { } - // struct B { } - // impl Foo for A { } - // impl Foo for B { } - // impl !Send for (A, B) { } - // ``` - // - // This final impl is legal according to the orphan - // rules, but it invalidates the reasoning from - // `two_foos` above. - debug!( - "trait_ref={:?} trait_def_id={:?} trait_is_auto={}", - trait_ref, - trait_def_id, - self.tcx.trait_is_auto(trait_def_id) + if let Some((msg, label)) = msg { + struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); + return Err(ErrorReported); + } + } + + if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { + tcx.sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note(tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + return Err(ErrorReported); + } + + Ok(()) +} + +fn emit_orphan_check_error( + tcx: TyCtxt<'tcx>, + sp: Span, + trait_span: Span, + self_ty_span: Span, + generics: &hir::Generics<'tcx>, + err: traits::OrphanCheckErr<'tcx>, +) -> Result<!, ErrorReported> { + match err { + traits::OrphanCheckErr::NonLocalInputType(tys) => { + let mut err = struct_span_err!( + tcx.sess, + sp, + E0117, + "only traits defined in the current crate can be implemented for \ + arbitrary types" ); - if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { - let self_ty = trait_ref.self_ty(); - let opt_self_def_id = match *self_ty.kind() { - ty::Adt(self_def, _) => Some(self_def.did), - ty::Foreign(did) => Some(did), - _ => None, + err.span_label(sp, "impl doesn't use only types from inside the current crate"); + for (ty, is_target_ty) in &tys { + let mut ty = *ty; + tcx.infer_ctxt().enter(|infcx| { + // Remove the lifetimes unnecessary for this error. + ty = infcx.freshen(ty); + }); + ty = match ty.kind() { + // Remove the type arguments from the output, as they are not relevant. + // You can think of this as the reverse of `resolve_vars_if_possible`. + // That way if we had `Vec<MyType>`, we will properly attribute the + // problem to `Vec<T>` and avoid confusing the user if they were to see + // `MyType` in the error. + ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()), + _ => ty, }; - - let msg = match opt_self_def_id { - // We only want to permit nominal types, but not *all* nominal types. - // They must be local to the current crate, so that people - // can't do `unsafe impl Send for Rc<SomethingLocal>` or - // `impl !Send for Box<SomethingLocalAndSend>`. - Some(self_def_id) => { - if self_def_id.is_local() { - None - } else { - Some(( - format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - self.tcx.def_path_str(trait_def_id) - ), - "can't implement cross-crate trait for type in another crate", - )) - } - } - _ => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, can \ - only be implemented for a struct/enum type, not `{}`", - self.tcx.def_path_str(trait_def_id), - self_ty - ), - "can't implement cross-crate trait with a default impl for \ - non-struct/enum type", - )), + let this = "this".to_string(); + let (ty, postfix) = match &ty.kind() { + ty::Slice(_) => (this, " because slices are always foreign"), + ty::Array(..) => (this, " because arrays are always foreign"), + ty::Tuple(..) => (this, " because tuples are always foreign"), + _ => (format!("`{}`", ty), ""), }; - - if let Some((msg, label)) = msg { - struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg) - .span_label(sp, label) - .emit(); - return; + let msg = format!("{} is not defined in the current crate{}", ty, postfix); + if *is_target_ty { + // Point at `D<A>` in `impl<A, B> for C<B> in D<A>` + err.span_label(self_ty_span, &msg); + } else { + // Point at `C<B>` in `impl<A, B> for C<B> in D<A>` + err.span_label(trait_span, &msg); + } + } + err.note("define and implement a trait or new type instead"); + err.emit() + } + traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { + let mut sp = sp; + for param in generics.params { + if param.name.ident().to_string() == param_ty.to_string() { + sp = param.span; } } - if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { - self.tcx - .sess - .struct_span_err(sp, "cannot implement trait on type alias impl trait") - .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here") - .emit(); + match local_type { + Some(local_type) => struct_span_err!( + tcx.sess, + sp, + E0210, + "type parameter `{}` must be covered by another type \ + when it appears before the first local type (`{}`)", + param_ty, + local_type + ) + .span_label( + sp, + format!( + "type parameter `{}` must be covered by another type \ + when it appears before the first local type (`{}`)", + param_ty, local_type + ), + ) + .note( + "implementing a foreign trait is only possible if at \ + least one of the types for which it is implemented is local, \ + and no uncovered type parameters appear before that first \ + local type", + ) + .note( + "in this case, 'before' refers to the following order: \ + `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \ + where `T0` is the first and `Tn` is the last", + ) + .emit(), + None => struct_span_err!( + tcx.sess, + sp, + E0210, + "type parameter `{}` must be used as the type parameter for some \ + local type (e.g., `MyStruct<{}>`)", + param_ty, + param_ty + ) + .span_label( + sp, + format!( + "type parameter `{}` must be used as the type parameter for some \ + local type", + param_ty, + ), + ) + .note( + "implementing a foreign trait is only possible if at \ + least one of the types for which it is implemented is local", + ) + .note( + "only traits defined in the current crate can be \ + implemented for a type parameter", + ) + .emit(), } } } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} - - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} + Err(ErrorReported) } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 18e8ed394e8..2f427305782 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -28,7 +28,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; @@ -668,6 +668,7 @@ impl ItemCtxt<'tcx> { }) .flat_map(|b| predicates_from_bound(self, ty, b)); + let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); let from_where_clauses = ast_generics .where_clause .predicates @@ -677,7 +678,7 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bp| { - let bt = if is_param(self.tcx, bp.bounded_ty, param_id) { + let bt = if bp.is_param_bound(param_def_id) { Some(ty) } else if !only_self_bounds.0 { Some(self.to_ty(bp.bounded_ty)) @@ -714,23 +715,6 @@ impl ItemCtxt<'tcx> { } } -/// Tests whether this is the AST for a reference to the type -/// parameter with ID `param_id`. We use this so as to avoid running -/// `ast_ty_to_ty`, because we want to avoid triggering an all-out -/// conversion of the type to avoid inducing unnecessary cycles. -fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind { - match path.res { - Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { - def_id == tcx.hir().local_def_id(param_id).to_def_id() - } - _ => false, - } - } else { - false - } -} - fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!("convert: item {} with id {}", it.ident, it.hir_id()); @@ -1494,13 +1478,15 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - + Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { + Some(tcx.typeck_root_def_id(def_id)) + } _ => None, } } } Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { - Some(tcx.closure_base_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id)) } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { @@ -1692,6 +1678,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { })); } + // provide junk type parameter defs for const blocks. + if let Node::AnonConst(_) = node { + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { + params.push(ty::GenericParamDef { + index: type_start, + name: Symbol::intern("<const_ty>"), + def_id, + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { + has_default: false, + object_lifetime_default: rl::Set1::Empty, + synthetic: None, + }, + }); + } + } + let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index a6ea8abdf3f..04a68250ced 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -494,7 +494,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) if anon_const.hir_id == hir_id => { - tcx.typeck(def_id).node_type(anon_const.hir_id) + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + substs.as_inline_const().ty() } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index 39bcf899932..a49eda6572d 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -88,7 +88,8 @@ fn diagnostic_hir_wf_check<'tcx>( ), ); - if let Err(errors) = fulfill.select_all_or_error(&infcx) { + let errors = fulfill.select_all_or_error(&infcx); + if !errors.is_empty() { tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors); for error in errors { if error.obligation.predicate == self.predicate { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index f90cfb88491..0881cf07586 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -58,7 +58,7 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] -#![feature(format_args_capture)] +#![cfg_attr(bootstrap, feature(format_args_capture))] #![feature(if_let_guard)] #![feature(in_band_lifetimes)] #![feature(is_sorted)] @@ -157,10 +157,10 @@ fn require_same_types<'tcx>( } } - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => true, - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); + match fulfill_cx.select_all_or_error(infcx).as_slice() { + [] => true, + errors => { + infcx.report_fulfillment_errors(errors, None, false); false } } @@ -352,8 +352,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { term_id, cause, ); - if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None, false); + let errors = fulfillment_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); error = true; } }); diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs index 4ab5fe26abe..91727d57ddf 100644 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs @@ -83,7 +83,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { // variables. Process these constraints. let mut fulfill_cx = FulfillmentContext::new(); fulfill_cx.register_predicate_obligations(self, result.obligations); - if fulfill_cx.select_all_or_error(self).is_err() { + let errors = fulfill_cx.select_all_or_error(self); + if !errors.is_empty() { self.tcx.sess.delay_span_bug( span, "implied_outlives_bounds failed to solve obligations from instantiation", |
