From 0bce91ff0b3252b736040087f9b768027422f3f0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 14 Dec 2019 12:13:10 -0500 Subject: [PATCH 01/21] add Scalar::try_from_(u)int methods --- src/librustc/mir/interpret/value.rs | 34 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index a038ca23ae92d..4f196cda5ae2a 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -237,13 +237,18 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn from_uint(i: impl Into, size: Size) -> Self { + pub fn try_from_uint(i: impl Into, size: Size) -> InterpResult<'tcx, Self> { let i = i.into(); - assert_eq!( - truncate(i, size), i, - "Unsigned value {:#x} does not fit in {} bits", i, size.bits() - ); - Scalar::Raw { data: i, size: size.bytes() as u8 } + if truncate(i, size) == i { + Ok(Scalar::Raw { data: i, size: size.bytes() as u8 }) + } else { + throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()) + } + } + + #[inline] + pub fn from_uint(i: impl Into, size: Size) -> Self { + Self::try_from_uint(i, size).unwrap() } #[inline] @@ -267,15 +272,20 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn from_int(i: impl Into, size: Size) -> Self { + pub fn try_from_int(i: impl Into, size: Size) -> InterpResult<'tcx, Self> { let i = i.into(); // `into` performed sign extension, we have to truncate let truncated = truncate(i as u128, size); - assert_eq!( - sign_extend(truncated, size) as i128, i, - "Signed value {:#x} does not fit in {} bits", i, size.bits() - ); - Scalar::Raw { data: truncated, size: size.bytes() as u8 } + if sign_extend(truncated, size) as i128 == i { + Ok(Scalar::Raw { data: truncated, size: size.bytes() as u8 }) + } else { + throw_unsup_format!("Signed value {:#x} does not fit in {} bits", i, size.bits()) + } + } + + #[inline] + pub fn from_int(i: impl Into, size: Size) -> Self { + Self::try_from_int(i, size).unwrap() } #[inline] From 90686ded25ee4f7f6676141a0413c066a2a4d393 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 14 Dec 2019 12:13:26 -0500 Subject: [PATCH 02/21] add ImmTy::try_from_(u)int methods --- src/librustc_mir/interpret/operand.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 48e7193ec39d4..072152a388775 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -218,14 +218,23 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { ImmTy { imm: val.into(), layout } } + #[inline] + pub fn try_from_uint(i: impl Into, layout: TyLayout<'tcx>) -> InterpResult<'tcx, Self> { + Ok(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) + } #[inline] pub fn from_uint(i: impl Into, layout: TyLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_uint(i, layout.size), layout) + Self::try_from_uint(i, layout).unwrap() + } + + #[inline] + pub fn try_from_int(i: impl Into, layout: TyLayout<'tcx>) -> InterpResult<'tcx, Self> { + Ok(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) } #[inline] pub fn from_int(i: impl Into, layout: TyLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_int(i, layout.size), layout) + Self::try_from_int(i, layout).unwrap() } #[inline] From 43888e8c7c39588bfeb4ae1e0a45774932a9f934 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 11 Dec 2019 16:40:49 -0600 Subject: [PATCH 03/21] Refactor region error handling to be done by mirborrowckctx --- .../borrow_check/diagnostics/mod.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 69 +++++- src/librustc_mir/borrow_check/mod.rs | 121 ++++++++++- src/librustc_mir/borrow_check/nll.rs | 65 +++--- .../borrow_check/region_infer/mod.rs | 197 ++++-------------- 5 files changed, 253 insertions(+), 201 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index 1a76265fbdcf0..ede0c2084097c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -32,7 +32,7 @@ mod explain_borrow; crate use mutability_errors::AccessKind; crate use region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx}; -crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo}; +crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo, RegionErrors, RegionErrorKind}; crate use outlives_suggestion::OutlivesSuggestionBuilder; pub(super) struct IncludingDowncast(pub(super) bool); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index b78cd6bccf8ca..1cb6643e7d091 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -3,12 +3,13 @@ use rustc::hir::def_id::DefId; use rustc::infer::{ error_reporting::nice_region_error::NiceRegionError, + region_constraints::GenericKind, InferCtxt, NLLRegionVariableOrigin, }; use rustc::mir::{ ConstraintCategory, Local, Location, Body, }; -use rustc::ty::{self, RegionVid}; +use rustc::ty::{self, RegionVid, Ty}; use rustc_index::vec::IndexVec; use rustc_errors::DiagnosticBuilder; use std::collections::VecDeque; @@ -53,13 +54,61 @@ impl ConstraintDescription for ConstraintCategory { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] enum Trace { StartRegion, FromOutlivesConstraint(OutlivesConstraint), NotVisited, } +/// A collection of errors encountered during region inference. This is needed to efficiently +/// report errors after borrow checking. +#[derive(Clone, Debug)] +crate struct RegionErrors<'tcx> { + errors: smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>, +} + +#[derive(Clone, Debug)] +crate enum RegionErrorKind<'tcx> { + /// An error for a type test: `T: 'a` does not live long enough + TypeTestDoesNotLiveLongEnough { + /// The span of the type test + span: Span, + /// The generic type of the type test + generic: GenericKind<'tcx>, + }, + + /// A generic bound failure for a type test + TypeTestGenericBoundError { + /// The span of the type test + span: Span, + /// The generic type of the type test + generic: GenericKind<'tcx>, + /// The lower bound region + lower_bound_region: ty::Region<'tcx>, + }, + + /// An unexpected hidden region for an opaque type + UnexpectedHiddenRegion { + /// The def id of the opaque type + opaque_type_def_id: DefId, + /// The hidden type + hidden_ty: Ty<'tcx>, + /// The unexpected region + member_region: ty::Region<'tcx>, + }, + + /// Any other lifetime error + RegionError { + /// The origin of the region + fr_origin: NLLRegionVariableOrigin, + /// The region that should outlive `shorter_fr` + longer_fr: RegionVid, + /// The region that should be shorter, but we can't prove it + shorter_fr: RegionVid, + }, +} + /// Various pieces of state used when reporting borrow checker errors. pub struct ErrorReportingCtx<'a, 'b, 'tcx> { /// The region inference context used for borrow chekcing this MIR body. @@ -95,6 +144,22 @@ pub struct ErrorConstraintInfo { pub(super) span: Span, } +impl<'tcx> RegionErrors<'tcx> { + pub fn new() -> Self { + RegionErrors { + errors: smallvec::SmallVec::new(), + } + } + + pub fn push(&mut self, error: RegionErrorKind<'tcx>) { + self.errors.push(error) + } + + pub fn into_iter(self) -> impl Iterator> { + self.errors.into_iter() + } +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Converts a region inference variable into a `ty::Region` that /// we can use for error reporting. If `r` is universally bound, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 2554d5e729da9..1f45da083bce2 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -3,7 +3,7 @@ use rustc::hir::{self, HirId}; use rustc::hir::Node; use rustc::hir::def_id::DefId; -use rustc::infer::InferCtxt; +use rustc::infer::{opaque_types, InferCtxt}; use rustc::lint::builtin::UNUSED_MUT; use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; @@ -39,12 +39,15 @@ use crate::dataflow::MoveDataParamEnv; use crate::dataflow::{do_dataflow, DebugFormatted}; use crate::dataflow::EverInitializedPlaces; use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; +use crate::transform::MirSource; use self::flows::Flows; use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; -use self::diagnostics::AccessKind; +use self::diagnostics::{ + AccessKind, RegionErrors, RegionErrorKind, OutlivesSuggestionBuilder, RegionErrorNamingCtx, +}; use self::path_utils::*; @@ -211,20 +214,40 @@ fn do_mir_borrowck<'a, 'tcx>( let borrow_set = Rc::new(BorrowSet::build( tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); - // If we are in non-lexical mode, compute the non-lexical lifetimes. - let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions( + // Compute non-lexical lifetimes. + let nll::NllOutput { + regioncx, polonius_output, opt_closure_req, nll_errors + } = nll::compute_regions( infcx, def_id, free_regions, body, &promoted, - &local_names, - &upvars, location_table, param_env, &mut flow_inits, &mdpe.move_data, &borrow_set, + ); + + // Dump MIR results into a file, if that is enabled. This let us + // write unit-tests, as well as helping with debugging. + nll::dump_mir_results( + infcx, + MirSource::item(def_id), + &body, + ®ioncx, + &opt_closure_req, + ); + + // We also have a `#[rustc_nll]` annotation that causes us to dump + // information. + nll::dump_annotation( + infcx, + &body, + def_id, + ®ioncx, + &opt_closure_req, &mut errors_buffer, ); @@ -297,6 +320,9 @@ fn do_mir_borrowck<'a, 'tcx>( local_names, }; + // Compute and report region errors, if any. + mbcx.report_region_errors(nll_errors); + let mut state = Flows::new( flow_borrows, flow_uninits, @@ -1560,6 +1586,89 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // initial reservation. } } + + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. + fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { + // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are + // buffered in the `MirBorrowckCtxt`. + + // TODO(mark-i-m): Would be great to get rid of the naming context. + let mut region_naming = RegionErrorNamingCtx::new(); + let mut outlives_suggestion = OutlivesSuggestionBuilder::new(self.mir_def_id, &self.local_names); + + for nll_error in nll_errors.into_iter() { + match nll_error { + RegionErrorKind::TypeTestDoesNotLiveLongEnough { span, generic } => { + // FIXME. We should handle this case better. It + // indicates that we have e.g., some region variable + // whose value is like `'a+'b` where `'a` and `'b` are + // distinct unrelated univesal regions that are not + // known to outlive one another. It'd be nice to have + // some examples where this arises to decide how best + // to report it; we could probably handle it by + // iterating over the universal regions and reporting + // an error that multiple bounds are required. + self.infcx.tcx.sess + .struct_span_err( + span, + &format!("`{}` does not live long enough", generic), + ) + .buffer(&mut self.errors_buffer); + }, + + RegionErrorKind::TypeTestGenericBoundError { + span, generic, lower_bound_region + } => { + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); + self.infcx + .construct_generic_bound_failure( + region_scope_tree, + span, + None, + generic, + lower_bound_region, + ) + .buffer(&mut self.errors_buffer); + }, + + RegionErrorKind::UnexpectedHiddenRegion { + opaque_type_def_id, hidden_ty, member_region, + } => { + let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); + opaque_types::unexpected_hidden_region_diagnostic( + self.infcx.tcx, + Some(region_scope_tree), + opaque_type_def_id, + hidden_ty, + member_region, + ) + .buffer(&mut self.errors_buffer); + } + + RegionErrorKind::RegionError { + fr_origin, longer_fr, shorter_fr, + } => { + let db = self.nonlexical_regioncx.report_error( + &self.body, + &self.local_names, + &self.upvars, + self.infcx, + self.mir_def_id, + longer_fr, + fr_origin, + shorter_fr, + &mut outlives_suggestion, + &mut region_naming, + ); + + db.buffer(&mut self.errors_buffer); + + // Emit outlives suggestions + //outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming); + } + } + } + } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 6d28a8caa92bd..2bbf6c9c84799 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -3,12 +3,11 @@ use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, - Local, Location, Body, BodyAndCache, LocalKind, BasicBlock, + Location, Body, BodyAndCache, LocalKind, BasicBlock, Promoted, ReadOnlyBodyAndCache}; use rustc::ty::{self, RegionKind, RegionVid}; use rustc_index::vec::IndexVec; use rustc_errors::Diagnostic; -use syntax_pos::symbol::Symbol; use std::fmt::Debug; use std::env; use std::io; @@ -29,19 +28,28 @@ use crate::transform::MirSource; use crate::borrow_check::{ borrow_set::BorrowSet, + diagnostics::RegionErrors, location::LocationTable, facts::{AllFacts, AllFactsExt, RustcFacts}, region_infer::{RegionInferenceContext, values::RegionValueElements}, universal_regions::UniversalRegions, type_check::{self, MirTypeckResults, MirTypeckRegionConstraints}, - Upvar, renumber, constraint_generation, invalidation, + renumber, constraint_generation, invalidation, }; crate type PoloniusOutput = Output; -/// Rewrites the regions in the MIR to use NLL variables, also -/// scraping out the set of universal regions (e.g., region parameters) -/// declared on the function. That set will need to be given to +/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any +/// closure requirements to propagate, and any generated errors. +crate struct NllOutput<'tcx> { + pub regioncx: RegionInferenceContext<'tcx>, + pub polonius_output: Option>, + pub opt_closure_req: Option>, + pub nll_errors: RegionErrors<'tcx>, +} + +/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal +/// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, @@ -152,19 +160,12 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( universal_regions: UniversalRegions<'tcx>, body: ReadOnlyBodyAndCache<'_, 'tcx>, promoted: &IndexVec>, - local_names: &IndexVec>, - upvars: &[Upvar], location_table: &LocationTable, param_env: ty::ParamEnv<'tcx>, flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, - errors_buffer: &mut Vec, -) -> ( - RegionInferenceContext<'tcx>, - Option>, - Option>, -) { +) -> NllOutput<'tcx> { let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default()); let universal_regions = Rc::new(universal_regions); @@ -306,40 +307,22 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( }); // Solve the region constraints. - let closure_region_requirements = regioncx.solve( + let (closure_region_requirements, nll_errors) = regioncx.solve( infcx, &body, - local_names, - upvars, def_id, - errors_buffer, polonius_output.clone(), ); - // Dump MIR results into a file, if that is enabled. This let us - // write unit-tests, as well as helping with debugging. - dump_mir_results( - infcx, - MirSource::item(def_id), - &body, - ®ioncx, - &closure_region_requirements, - ); - - // We also have a `#[rustc_nll]` annotation that causes us to dump - // information - dump_annotation( - infcx, - &body, - def_id, - ®ioncx, - &closure_region_requirements, - errors_buffer); - - (regioncx, polonius_output, closure_region_requirements) + NllOutput { + regioncx, + polonius_output, + opt_closure_req: closure_region_requirements, + nll_errors, + } } -fn dump_mir_results<'a, 'tcx>( +pub(super) fn dump_mir_results<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, source: MirSource<'tcx>, body: &Body<'tcx>, @@ -400,7 +383,7 @@ fn dump_mir_results<'a, 'tcx>( }; } -fn dump_annotation<'a, 'tcx>( +pub(super) fn dump_annotation<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, body: &Body<'tcx>, mir_def_id: DefId, diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index dedc6b9b09af2..210106c8e6415 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -2,7 +2,6 @@ use std::rc::Rc; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryOutlivesConstraint; -use rustc::infer::opaque_types; use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; use rustc::mir::{ @@ -11,6 +10,7 @@ use rustc::mir::{ }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::ErrorReported; +use rustc_errors::DiagnosticBuilder; use rustc_data_structures::binary_search_util; use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -18,9 +18,7 @@ use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_index::vec::IndexVec; -use rustc_errors::{Diagnostic, DiagnosticBuilder}; use syntax_pos::Span; -use syntax_pos::symbol::Symbol; use crate::borrow_check::{ constraints::{ @@ -35,12 +33,9 @@ use crate::borrow_check::{ RegionValues, }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, - diagnostics::{ - OutlivesSuggestionBuilder, RegionErrorNamingCtx, - }, + diagnostics::{RegionErrors, RegionErrorKind}, nll::{ToRegionVid, PoloniusOutput}, universal_regions::UniversalRegions, - Upvar, }; mod dump_mir; @@ -477,14 +472,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], mir_def_id: DefId, - errors_buffer: &mut Vec, polonius_output: Option>, - ) -> Option> { + ) -> (Option>, RegionErrors<'tcx>) { self.propagate_constraints(body); + let mut errors_buffer = RegionErrors::new(); + // If this is a closure, we can propagate unsatisfied // `outlives_requirements` to our creator, so create a vector // to store those. Otherwise, we'll pass in `None` to the @@ -496,17 +490,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_type_tests( infcx, body, - mir_def_id, outlives_requirements.as_mut(), - errors_buffer, + &mut errors_buffer, ); - // If we produce any errors, we keep track of the names of all regions, so that we can use - // the same error names in any suggestions we produce. Note that we need names to be unique - // across different errors for the same MIR def so that we can make suggestions that fix - // multiple problems. - let mut region_naming = RegionErrorNamingCtx::new(); - // In Polonius mode, the errors about missing universal region relations are in the output // and need to be emitted or propagated. Otherwise, we need to check whether the // constraints were too strong, and if so, emit or propagate those errors. @@ -514,36 +501,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_polonius_subset_errors( infcx, body, - local_names, - upvars, mir_def_id, outlives_requirements.as_mut(), - errors_buffer, - &mut region_naming, + &mut errors_buffer, polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { self.check_universal_regions( infcx, body, - local_names, - upvars, mir_def_id, outlives_requirements.as_mut(), - errors_buffer, - &mut region_naming, + &mut errors_buffer, ); } - self.check_member_constraints(infcx, mir_def_id, errors_buffer); + self.check_member_constraints(infcx, &mut errors_buffer); let outlives_requirements = outlives_requirements.unwrap_or(vec![]); if outlives_requirements.is_empty() { - None + (None, errors_buffer) } else { let num_external_vids = self.universal_regions.num_global_and_external_regions(); - Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }) + ( + Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), + errors_buffer, + ) } } @@ -838,9 +822,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut Vec, + errors_buffer: &mut RegionErrors<'tcx>, ) { let tcx = infcx.tcx; @@ -898,32 +881,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { } if let Some(lower_bound_region) = lower_bound_region { - let region_scope_tree = &tcx.region_scope_tree(mir_def_id); - infcx - .construct_generic_bound_failure( - region_scope_tree, - type_test_span, - None, - type_test.generic_kind, - lower_bound_region, - ) - .buffer(errors_buffer); + errors_buffer.push(RegionErrorKind::TypeTestGenericBoundError { + span: type_test_span, + generic: type_test.generic_kind, + lower_bound_region, + }); } else { - // FIXME. We should handle this case better. It - // indicates that we have e.g., some region variable - // whose value is like `'a+'b` where `'a` and `'b` are - // distinct unrelated univesal regions that are not - // known to outlive one another. It'd be nice to have - // some examples where this arises to decide how best - // to report it; we could probably handle it by - // iterating over the universal regions and reporting - // an error that multiple bounds are required. - tcx.sess - .struct_span_err( - type_test_span, - &format!("`{}` does not live long enough", type_test.generic_kind,), - ) - .buffer(errors_buffer); + errors_buffer.push(RegionErrorKind::TypeTestDoesNotLiveLongEnough { + span: type_test_span, + generic: type_test.generic_kind, + }); } } } @@ -1138,7 +1105,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. - pub (in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { + pub(in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); // Find the smallest universal region that contains all other @@ -1318,15 +1285,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut Vec, - region_naming: &mut RegionErrorNamingCtx, + errors_buffer: &mut RegionErrors<'tcx>, ) { - let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id, local_names); - for (fr, fr_definition) in self.definitions.iter_enumerated() { match fr_definition.origin { NLLRegionVariableOrigin::FreeRegion => { @@ -1334,16 +1296,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. self.check_universal_region( - infcx, body, - local_names, - upvars, - mir_def_id, fr, &mut propagated_outlives_requirements, - &mut outlives_suggestion, errors_buffer, - region_naming, ); } @@ -1356,9 +1312,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } } - - // Emit outlives suggestions - outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming); } /// Checks if Polonius has found any unexpected free region relations. @@ -1386,12 +1339,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut Vec, - region_naming: &mut RegionErrorNamingCtx, + errors_buffer: &mut RegionErrors<'tcx>, polonius_output: Rc, ) { debug!( @@ -1399,8 +1349,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { polonius_output.subset_errors.len() ); - let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id, local_names); - // Similarly to `check_universal_regions`: a free region relation, which was not explicitly // declared ("known") was found by Polonius, so emit an error, or propagate the // requirements for our caller into the `propagated_outlives_requirements` vector. @@ -1439,26 +1387,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut propagated_outlives_requirements, ); if !propagated { - // If we are not in a context where we can't propagate errors, or we - // could not shrink `fr` to something smaller, then just report an - // error. - // - // Note: in this case, we use the unapproximated regions to report the - // error. This gives better error messages in some cases. - let db = self.report_error( - body, - local_names, - upvars, - infcx, - mir_def_id, - *longer_fr, - NLLRegionVariableOrigin::FreeRegion, - *shorter_fr, - &mut outlives_suggestion, - region_naming, - ); - - db.buffer(errors_buffer); + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr: *longer_fr, + shorter_fr: *shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); } } @@ -1480,8 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - // Emit outlives suggestions - outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming); } /// Checks the final value for the free region `fr` to see if it @@ -1494,16 +1425,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `outlives_requirements` vector. fn check_universal_region( &self, - infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], - mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, - outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>, - errors_buffer: &mut Vec, - region_naming: &mut RegionErrorNamingCtx, + errors_buffer: &mut RegionErrors<'tcx>, ) { debug!("check_universal_region(fr={:?})", longer_fr); @@ -1525,15 +1450,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_region_relation( longer_fr, representative, - infcx, body, - local_names, - upvars, - mir_def_id, propagated_outlives_requirements, - outlives_suggestion, errors_buffer, - region_naming, ); return; } @@ -1544,21 +1463,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(ErrorReported) = self.check_universal_region_relation( longer_fr, shorter_fr, - infcx, body, - local_names, - upvars, - mir_def_id, propagated_outlives_requirements, - outlives_suggestion, errors_buffer, - region_naming, ) { // continuing to iterate just reports more errors than necessary // // FIXME It would also allow us to report more Outlives Suggestions, though, so // it's not clear that that's a bad thing. Somebody should try commenting out this // line and see it is actually a regression. + // + // TODO(mark-i-m): perhaps we could add them to the `RegionErrors` with a flag that + // says "don't report me"? return; } } @@ -1568,15 +1484,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, longer_fr: RegionVid, shorter_fr: RegionVid, - infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - local_names: &IndexVec>, - upvars: &[Upvar], - mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, - outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>, - errors_buffer: &mut Vec, - region_naming: &mut RegionErrorNamingCtx, + errors_buffer: &mut RegionErrors<'tcx>, ) -> Option { // If it is known that `fr: o`, carry on. if self.universal_region_relations.outlives(longer_fr, shorter_fr) { @@ -1599,20 +1509,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - let db = self.report_error( - body, - local_names, - upvars, - infcx, - mir_def_id, - longer_fr, - NLLRegionVariableOrigin::FreeRegion, - shorter_fr, - outlives_suggestion, - region_naming, - ); - - db.buffer(errors_buffer); + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); Some(ErrorReported) } @@ -1727,8 +1627,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_member_constraints( &self, infcx: &InferCtxt<'_, 'tcx>, - mir_def_id: DefId, - errors_buffer: &mut Vec, + errors_buffer: &mut RegionErrors<'tcx>, ) { let member_constraints = self.member_constraints.clone(); for m_c_i in member_constraints.all_indices() { @@ -1752,16 +1651,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // If not, report an error. - let region_scope_tree = &infcx.tcx.region_scope_tree(mir_def_id); let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); - opaque_types::unexpected_hidden_region_diagnostic( - infcx.tcx, - Some(region_scope_tree), - m_c.opaque_type_def_id, - m_c.hidden_ty, + errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { + opaque_type_def_id: m_c.opaque_type_def_id, + hidden_ty: m_c.hidden_ty, member_region, - ) - .buffer(errors_buffer); + }); } } } From 94a9c6262bba181ca97e5df75ee7a305348cf036 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 17 Dec 2019 10:43:00 -0600 Subject: [PATCH 04/21] add unreported error variant --- .../borrow_check/diagnostics/region_errors.rs | 11 +++++++++++ src/librustc_mir/borrow_check/mod.rs | 19 ++++++++++++++++++- .../borrow_check/region_infer/mod.rs | 16 +++++++--------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 1cb6643e7d091..58f2991088355 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -107,6 +107,17 @@ crate enum RegionErrorKind<'tcx> { /// The region that should be shorter, but we can't prove it shorter_fr: RegionVid, }, + + /// The same as `RegionError`, but this is an unreported error. We currently only report the + /// first error encountered and leave the rest unreported so as not to overwhelm the user. + UnreportedError { + /// The origin of the region + fr_origin: NLLRegionVariableOrigin, + /// The region that should outlive `shorter_fr` + longer_fr: RegionVid, + /// The region that should be shorter, but we can't prove it + shorter_fr: RegionVid, + } } /// Various pieces of state used when reporting borrow checker errors. diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1f45da083bce2..0d40b571cf3fa 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1664,7 +1664,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { db.buffer(&mut self.errors_buffer); // Emit outlives suggestions - //outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming); + outlives_suggestion.add_suggestion( + &self.body, + &self.nonlexical_regioncx, + self.infcx, + &mut self.errors_buffer, + &mut region_naming + ); + } + + RegionErrorKind::UnreportedError { + longer_fr, shorter_fr, + fr_origin: _, + } => { + // FIXME: currently we do nothing with these, but perhaps we can do better? + debug!( + "Unreported region error: can't prove that {:?}: {:?}", + longer_fr, shorter_fr + ); } } } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 210106c8e6415..c3e469e3b9f7b 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1467,15 +1467,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements, errors_buffer, ) { - // continuing to iterate just reports more errors than necessary - // - // FIXME It would also allow us to report more Outlives Suggestions, though, so - // it's not clear that that's a bad thing. Somebody should try commenting out this - // line and see it is actually a regression. - // - // TODO(mark-i-m): perhaps we could add them to the `RegionErrors` with a flag that - // says "don't report me"? - return; + // We only report the first region error. Subsequent errors are hidden so as not to + // overwhelm the user, but we do record them so as to potentially print better + // diagnostics elsewhere... + errors_buffer.push(RegionErrorKind::UnreportedError { + longer_fr, shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); } } } From 3902e563fb1054aa0fb4e142fdef8dc59d5845d5 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 13:27:01 -0600 Subject: [PATCH 05/21] tidy --- src/librustc_mir/borrow_check/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 0d40b571cf3fa..d669a75071c59 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1592,9 +1592,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are // buffered in the `MirBorrowckCtxt`. - // TODO(mark-i-m): Would be great to get rid of the naming context. + // FIXME(mark-i-m): Would be great to get rid of the naming context. let mut region_naming = RegionErrorNamingCtx::new(); - let mut outlives_suggestion = OutlivesSuggestionBuilder::new(self.mir_def_id, &self.local_names); + let mut outlives_suggestion = OutlivesSuggestionBuilder::new( + self.mir_def_id, &self.local_names + ); for nll_error in nll_errors.into_iter() { match nll_error { From e5a1f48fa7e6ada9c1bd6ab5a00afd07eac94fac Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 17:00:00 -0600 Subject: [PATCH 06/21] fix outlives suggestions --- .../diagnostics/outlives_suggestion.rs | 4 +++- src/librustc_mir/borrow_check/mod.rs | 20 ++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs index b61c37b061396..dc5fed4822984 100644 --- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs +++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs @@ -250,7 +250,9 @@ impl OutlivesSuggestionBuilder<'a> { // If there is only one constraint to suggest, then we already suggested it in the // intermediate suggestion above. - if self.constraints_to_add.len() == 1 { + if self.constraints_to_add.len() == 1 + && self.constraints_to_add.values().next().unwrap().len() == 1 + { debug!("Only 1 suggestion. Skipping."); return; } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d669a75071c59..4171190805665 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1664,15 +1664,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); db.buffer(&mut self.errors_buffer); - - // Emit outlives suggestions - outlives_suggestion.add_suggestion( - &self.body, - &self.nonlexical_regioncx, - self.infcx, - &mut self.errors_buffer, - &mut region_naming - ); } RegionErrorKind::UnreportedError { @@ -1680,6 +1671,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fr_origin: _, } => { // FIXME: currently we do nothing with these, but perhaps we can do better? + // FIXME: try collecting these constraints on the outlives suggestion builder. + // Does it make the suggestions any better? debug!( "Unreported region error: can't prove that {:?}: {:?}", longer_fr, shorter_fr @@ -1687,6 +1680,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } + + // Emit one outlives suggestions for each MIR def we borrowck + outlives_suggestion.add_suggestion( + &self.body, + &self.nonlexical_regioncx, + self.infcx, + &mut self.errors_buffer, + &mut region_naming + ); } } From 5d9e74ebd1d5cc02be354a0791df1f6ed295f09f Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 17:02:49 -0600 Subject: [PATCH 07/21] some more refactoring + maintain diagnostic status quo --- .../borrow_check/region_infer/mod.rs | 90 ++++++++++--------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index c3e469e3b9f7b..05a21e6958e3e 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -9,7 +9,6 @@ use rustc::mir::{ ConstraintCategory, Local, Location, }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; -use rustc::util::common::ErrorReported; use rustc_errors::DiagnosticBuilder; use rustc_data_structures::binary_search_util; use rustc_index::bit_set::BitSet; @@ -225,6 +224,15 @@ pub struct TypeTest<'tcx> { pub verify_bound: VerifyBound<'tcx>, } +/// When we have an unmet lifetime constraint, we try to propagate it outward (e.g. to a closure +/// environment). If we can't, it is an error. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum RegionRelationCheckResult { + Ok, + Propagated, + Error, +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -1386,7 +1394,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { body, &mut propagated_outlives_requirements, ); - if !propagated { + if propagated == RegionRelationCheckResult::Error { errors_buffer.push(RegionErrorKind::RegionError { longer_fr: *longer_fr, shorter_fr: *shorter_fr, @@ -1412,7 +1420,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } } - } /// Checks the final value for the free region `fr` to see if it @@ -1447,59 +1454,64 @@ impl<'tcx> RegionInferenceContext<'tcx> { // one in this SCC, so we will always check the representative here. let representative = self.scc_representatives[longer_fr_scc]; if representative != longer_fr { - self.check_universal_region_relation( + if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, representative, body, propagated_outlives_requirements, - errors_buffer, - ); + ) { + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, + shorter_fr: representative, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); + } return; } // Find every region `o` such that `fr: o` // (because `fr` includes `end(o)`). + let mut error_reported = false; for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { - if let Some(ErrorReported) = self.check_universal_region_relation( + if let RegionRelationCheckResult::Error = self.check_universal_region_relation( longer_fr, shorter_fr, body, propagated_outlives_requirements, - errors_buffer, ) { - // We only report the first region error. Subsequent errors are hidden so as not to - // overwhelm the user, but we do record them so as to potentially print better - // diagnostics elsewhere... - errors_buffer.push(RegionErrorKind::UnreportedError { - longer_fr, shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, - }); + // We only report the first region error. Subsequent errors are hidden so as + // not to overwhelm the user, but we do record them so as to potentially print + // better diagnostics elsewhere... + if error_reported { + errors_buffer.push(RegionErrorKind::UnreportedError { + longer_fr, shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); + } else { + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + }); + } + + error_reported = true; } } } + /// Checks that we can prove that `longer_fr: shorter_fr`. If we can't we attempt to propagate + /// the constraint outward (e.g. to a closure environment), but if that fails, there is an + /// error. fn check_universal_region_relation( &self, longer_fr: RegionVid, shorter_fr: RegionVid, body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) -> Option { + ) -> RegionRelationCheckResult { // If it is known that `fr: o`, carry on. if self.universal_region_relations.outlives(longer_fr, shorter_fr) { - return None; - } - - let propagated = self.try_propagate_universal_region_error( - longer_fr, - shorter_fr, - body, - propagated_outlives_requirements, - ); - - if propagated { - None + RegionRelationCheckResult::Ok } else { // If we are not in a context where we can't propagate errors, or we // could not shrink `fr` to something smaller, then just report an @@ -1507,26 +1519,24 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, - }); - - Some(ErrorReported) + self.try_propagate_universal_region_error( + longer_fr, + shorter_fr, + body, + propagated_outlives_requirements, + ) } } /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's /// creator. If we cannot, then the caller should report an error to the user. - /// - /// Returns `true` if the error was propagated, and `false` otherwise. fn try_propagate_universal_region_error( &self, longer_fr: RegionVid, shorter_fr: RegionVid, body: &Body<'tcx>, propagated_outlives_requirements: &mut Option<&mut Vec>>, - ) -> bool { + ) -> RegionRelationCheckResult { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `longer_fr` until we find a non-local region (if we do). // We'll call it `fr-` -- it's ever so slightly smaller than @@ -1558,11 +1568,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { category: blame_span_category.0, }); } - return true; + return RegionRelationCheckResult::Propagated; } } - false + RegionRelationCheckResult::Error } fn check_bound_universal_region( From e4379e66ff2c1af052b7714f54433ef2e2afe0ff Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 17:45:05 -0600 Subject: [PATCH 08/21] make regionerrors a typedef --- .../borrow_check/diagnostics/region_errors.rs | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 58f2991088355..59bd81c52ddc8 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -63,10 +63,7 @@ enum Trace { /// A collection of errors encountered during region inference. This is needed to efficiently /// report errors after borrow checking. -#[derive(Clone, Debug)] -crate struct RegionErrors<'tcx> { - errors: smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>, -} +crate type RegionErrors<'tcx> = smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>; #[derive(Clone, Debug)] crate enum RegionErrorKind<'tcx> { @@ -155,22 +152,6 @@ pub struct ErrorConstraintInfo { pub(super) span: Span, } -impl<'tcx> RegionErrors<'tcx> { - pub fn new() -> Self { - RegionErrors { - errors: smallvec::SmallVec::new(), - } - } - - pub fn push(&mut self, error: RegionErrorKind<'tcx>) { - self.errors.push(error) - } - - pub fn into_iter(self) -> impl Iterator> { - self.errors.into_iter() - } -} - impl<'tcx> RegionInferenceContext<'tcx> { /// Converts a region inference variable into a `ty::Region` that /// we can use for error reporting. If `r` is universally bound, From 69038363986ed1fcc46dc5c5d53c6b95ab97f9e8 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sat, 21 Dec 2019 15:16:00 +0900 Subject: [PATCH 09/21] Remove iter_private.rs The contents of this file have been moved in #56932 (520e8b0) and the file should have been removed as well. --- src/libcore/iter_private.rs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/libcore/iter_private.rs diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs deleted file mode 100644 index 890db47b19700..0000000000000 --- a/src/libcore/iter_private.rs +++ /dev/null @@ -1,17 +0,0 @@ -/// An iterator whose items are random accessible efficiently -/// -/// # Safety -/// -/// The iterator's .len() and size_hint() must be exact. -/// `.len()` must be cheap to call. -/// -/// .get_unchecked() must return distinct mutable references for distinct -/// indices (if applicable), and must return a valid reference if index is in -/// 0..self.len(). -#[doc(hidden)] -pub unsafe trait TrustedRandomAccess : ExactSizeIterator { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; - /// Returns `true` if getting an iterator element may have - /// side effects. Remember to take inner iterators into account. - fn may_have_side_effect() -> bool; -} From 309f437e1d20ce93597eec0514a9cb80150d8861 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 21 Dec 2019 10:27:58 -0500 Subject: [PATCH 10/21] Change results to options --- src/librustc/mir/interpret/value.rs | 12 ++++++------ src/librustc_mir/interpret/operand.rs | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 4f196cda5ae2a..8f5fab4b00291 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -237,12 +237,12 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn try_from_uint(i: impl Into, size: Size) -> InterpResult<'tcx, Self> { + pub fn try_from_uint(i: impl Into, size: Size) -> Option { let i = i.into(); if truncate(i, size) == i { - Ok(Scalar::Raw { data: i, size: size.bytes() as u8 }) + Some(Scalar::Raw { data: i, size: size.bytes() as u8 }) } else { - throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()) + None } } @@ -272,14 +272,14 @@ impl<'tcx, Tag> Scalar { } #[inline] - pub fn try_from_int(i: impl Into, size: Size) -> InterpResult<'tcx, Self> { + pub fn try_from_int(i: impl Into, size: Size) -> Option { let i = i.into(); // `into` performed sign extension, we have to truncate let truncated = truncate(i as u128, size); if sign_extend(truncated, size) as i128 == i { - Ok(Scalar::Raw { data: truncated, size: size.bytes() as u8 }) + Some(Scalar::Raw { data: truncated, size: size.bytes() as u8 }) } else { - throw_unsup_format!("Signed value {:#x} does not fit in {} bits", i, size.bits()) + None } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 072152a388775..8dd50958350bb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -219,8 +219,8 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { } #[inline] - pub fn try_from_uint(i: impl Into, layout: TyLayout<'tcx>) -> InterpResult<'tcx, Self> { - Ok(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) + pub fn try_from_uint(i: impl Into, layout: TyLayout<'tcx>) -> Option { + Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) } #[inline] pub fn from_uint(i: impl Into, layout: TyLayout<'tcx>) -> Self { @@ -228,8 +228,8 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { } #[inline] - pub fn try_from_int(i: impl Into, layout: TyLayout<'tcx>) -> InterpResult<'tcx, Self> { - Ok(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) + pub fn try_from_int(i: impl Into, layout: TyLayout<'tcx>) -> Option { + Some(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) } #[inline] From 5b06025f99a68b39a49b7de5932a5b652edf4ac7 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Dec 2019 12:54:43 -0600 Subject: [PATCH 11/21] is_reported flag --- .../borrow_check/diagnostics/region_errors.rs | 14 ++--- src/librustc_mir/borrow_check/mod.rs | 51 +++++++++---------- .../borrow_check/region_infer/mod.rs | 18 +++---- 3 files changed, 34 insertions(+), 49 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 59bd81c52ddc8..4e85b110ddaf4 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -103,18 +103,10 @@ crate enum RegionErrorKind<'tcx> { longer_fr: RegionVid, /// The region that should be shorter, but we can't prove it shorter_fr: RegionVid, + /// Indicates whether this is a reported error. We currently only report the first error + /// encountered and leave the rest unreported so as not to overwhelm the user. + is_reported: bool, }, - - /// The same as `RegionError`, but this is an unreported error. We currently only report the - /// first error encountered and leave the rest unreported so as not to overwhelm the user. - UnreportedError { - /// The origin of the region - fr_origin: NLLRegionVariableOrigin, - /// The region that should outlive `shorter_fr` - longer_fr: RegionVid, - /// The region that should be shorter, but we can't prove it - shorter_fr: RegionVid, - } } /// Various pieces of state used when reporting borrow checker errors. diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4171190805665..751ebc155f5ce 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1648,35 +1648,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } RegionErrorKind::RegionError { - fr_origin, longer_fr, shorter_fr, + fr_origin, longer_fr, shorter_fr, is_reported, } => { - let db = self.nonlexical_regioncx.report_error( - &self.body, - &self.local_names, - &self.upvars, - self.infcx, - self.mir_def_id, - longer_fr, - fr_origin, - shorter_fr, - &mut outlives_suggestion, - &mut region_naming, - ); - - db.buffer(&mut self.errors_buffer); - } + if is_reported { + let db = self.nonlexical_regioncx.report_error( + &self.body, + &self.local_names, + &self.upvars, + self.infcx, + self.mir_def_id, + longer_fr, + fr_origin, + shorter_fr, + &mut outlives_suggestion, + &mut region_naming, + ); - RegionErrorKind::UnreportedError { - longer_fr, shorter_fr, - fr_origin: _, - } => { - // FIXME: currently we do nothing with these, but perhaps we can do better? - // FIXME: try collecting these constraints on the outlives suggestion builder. - // Does it make the suggestions any better? - debug!( - "Unreported region error: can't prove that {:?}: {:?}", - longer_fr, shorter_fr - ); + db.buffer(&mut self.errors_buffer); + } else { + // FIXME: currently we do nothing with these, but perhaps we can do better? + // FIXME: try collecting these constraints on the outlives suggestion + // builder. Does it make the suggestions any better? + debug!( + "Unreported region error: can't prove that {:?}: {:?}", + longer_fr, shorter_fr + ); + } } } } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 05a21e6958e3e..3afe2056a926f 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1399,6 +1399,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr: *longer_fr, shorter_fr: *shorter_fr, fr_origin: NLLRegionVariableOrigin::FreeRegion, + is_reported: true, }); } } @@ -1464,6 +1465,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr, shorter_fr: representative, fr_origin: NLLRegionVariableOrigin::FreeRegion, + is_reported: true, }); } return; @@ -1482,17 +1484,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // We only report the first region error. Subsequent errors are hidden so as // not to overwhelm the user, but we do record them so as to potentially print // better diagnostics elsewhere... - if error_reported { - errors_buffer.push(RegionErrorKind::UnreportedError { - longer_fr, shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, - }); - } else { - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, - }); - } + errors_buffer.push(RegionErrorKind::RegionError { + longer_fr, shorter_fr, + fr_origin: NLLRegionVariableOrigin::FreeRegion, + is_reported: !error_reported, + }); error_reported = true; } From bd0ea19eaa96dc607c285d0aeba2fffa44fc1019 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Dec 2019 13:27:00 -0600 Subject: [PATCH 12/21] add comments --- src/librustc_mir/borrow_check/diagnostics/region_errors.rs | 3 +++ src/librustc_mir/borrow_check/mod.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 4e85b110ddaf4..4ce0311f3bb4c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -63,6 +63,9 @@ enum Trace { /// A collection of errors encountered during region inference. This is needed to efficiently /// report errors after borrow checking. +/// +/// Usually we expect this to either be empty or contain a small number of items, so we can avoid +/// allocation most of the time. crate type RegionErrors<'tcx> = smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>; #[derive(Clone, Debug)] diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 751ebc155f5ce..153ee23811e92 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1666,6 +1666,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { db.buffer(&mut self.errors_buffer); } else { + // We only report the first error, so as not to overwhelm the user. See + // `RegRegionErrorKind` docs. + // // FIXME: currently we do nothing with these, but perhaps we can do better? // FIXME: try collecting these constraints on the outlives suggestion // builder. Does it make the suggestions any better? From a155a9b67d9688a3d5b90361e5ea8a4a9bf3b0d6 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Dec 2019 13:35:21 -0600 Subject: [PATCH 13/21] use vec instead of smallvec --- src/librustc_mir/borrow_check/diagnostics/region_errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 4ce0311f3bb4c..481494f6a3abe 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -66,7 +66,7 @@ enum Trace { /// /// Usually we expect this to either be empty or contain a small number of items, so we can avoid /// allocation most of the time. -crate type RegionErrors<'tcx> = smallvec::SmallVec<[RegionErrorKind<'tcx>; 4]>; +crate type RegionErrors<'tcx> = Vec>; #[derive(Clone, Debug)] crate enum RegionErrorKind<'tcx> { From 4f0dc7b06c72d4b1f5caf2c40c8f7407cdb9c5ab Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 20 Dec 2019 18:05:45 +0100 Subject: [PATCH 14/21] misc cleanup in match MIR building --- src/librustc_mir/build/matches/mod.rs | 42 ++++++++++++-------------- src/librustc_mir/build/matches/test.rs | 2 +- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index bf0b2439c00b5..c0a7439b5ce57 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -26,6 +26,7 @@ mod simplify; mod test; mod util; +use itertools::Itertools; use std::convert::TryFrom; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -822,9 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); - let block: BasicBlock; - - if !matched_candidates.is_empty() { + let block: BasicBlock = if !matched_candidates.is_empty() { let otherwise_block = self.select_matched_candidates( matched_candidates, start_block, @@ -832,17 +831,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); if let Some(last_otherwise_block) = otherwise_block { - block = last_otherwise_block + last_otherwise_block } else { // Any remaining candidates are unreachable. if unmatched_candidates.is_empty() { return; } - block = self.cfg.start_new_block(); - }; + self.cfg.start_new_block() + } } else { - block = *start_block.get_or_insert_with(|| self.cfg.start_new_block()); - } + *start_block.get_or_insert_with(|| self.cfg.start_new_block()) + }; // If there are no candidates that still need testing, we're // done. Since all matches are exhaustive, execution should @@ -885,7 +884,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// ... /// /// We generate real edges from: - /// * `block` to the prebinding_block of the first pattern, + /// * `start_block` to the `prebinding_block` of the first pattern, /// * the otherwise block of the first pattern to the second pattern, /// * the otherwise block of the third pattern to the a block with an /// Unreachable terminator. @@ -948,6 +947,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let first_candidate = &reachable_candidates[0]; let first_prebinding_block = first_candidate.pre_binding_block; + // `goto -> first_prebinding_block` from the `start_block` if there is one. if let Some(start_block) = *start_block { let source_info = self.source_info(first_candidate.span); self.cfg.terminate( @@ -959,21 +959,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { *start_block = Some(first_prebinding_block); } - for window in reachable_candidates.windows(2) { - if let [first_candidate, second_candidate] = window { - let source_info = self.source_info(first_candidate.span); - if let Some(otherwise_block) = first_candidate.otherwise_block { - self.false_edges( - otherwise_block, - second_candidate.pre_binding_block, - first_candidate.next_candidate_pre_binding_block, - source_info, - ); - } else { - bug!("candidate other than the last has no guard"); - } + for (first_candidate, second_candidate) in reachable_candidates.iter().tuple_windows() { + let source_info = self.source_info(first_candidate.span); + if let Some(otherwise_block) = first_candidate.otherwise_block { + self.false_edges( + otherwise_block, + second_candidate.pre_binding_block, + first_candidate.next_candidate_pre_binding_block, + source_info, + ); } else { - bug!("<[_]>::windows returned incorrectly sized window"); + bug!("candidate other than the last has no guard"); } } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index e320811ca0556..bdc1bdd5b9855 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -30,7 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Test { span: match_pair.pattern.span, kind: TestKind::Switch { - adt_def: adt_def.clone(), + adt_def, variants: BitSet::new_empty(adt_def.variants.len()), }, } From f5a8d1ab034c48b69eef8ee3618f7eb97d72810f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 20 Dec 2019 18:27:05 +0100 Subject: [PATCH 15/21] simplify MIR building with cfg.goto(...) --- src/librustc_mir/build/block.rs | 3 +-- src/librustc_mir/build/cfg.rs | 5 ++++ src/librustc_mir/build/expr/into.rs | 28 +++++---------------- src/librustc_mir/build/matches/mod.rs | 35 ++++++-------------------- src/librustc_mir/build/matches/util.rs | 10 +------- src/librustc_mir/build/mod.rs | 9 +++---- src/librustc_mir/build/scope.rs | 18 +++++-------- 7 files changed, 29 insertions(+), 79 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 7353ca9285ddb..aceed09757e7e 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -33,8 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) }); - this.cfg.terminate(unpack!(block_exit), source_info, - TerminatorKind::Goto { target: exit_block }); + this.cfg.goto(unpack!(block_exit), source_info, exit_block); exit_block.unit() } else { this.ast_block_stmts(destination, block, span, stmts, expr, diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 6bd8d2f7c0792..0e685486c3f99 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -85,4 +85,9 @@ impl<'tcx> CFG<'tcx> { kind, }); } + + /// In the `origin` block, push a `goto -> target` terminator. + pub fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) { + self.terminate(origin, source_info, TerminatorKind::Goto { target }) + } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 608415408e35c..a9fa7cfa04a89 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -140,17 +140,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); - this.cfg.terminate( - true_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - this.cfg.terminate( - false_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - + // Link up both branches: + this.cfg.goto(true_block, source_info, join_block); + this.cfg.goto(false_block, source_info, join_block); join_block.unit() } ExprKind::Loop { body } => { @@ -167,12 +159,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let loop_block = this.cfg.start_new_block(); let exit_block = this.cfg.start_new_block(); - // start the loop - this.cfg.terminate( - block, - source_info, - TerminatorKind::Goto { target: loop_block }, - ); + // Start the loop. + this.cfg.goto(block, source_info, loop_block); this.in_breakable_scope( Some(loop_block), @@ -196,11 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. let body_block_end = unpack!(this.into(&tmp, body_block, body)); - this.cfg.terminate( - body_block_end, - source_info, - TerminatorKind::Goto { target: loop_block }, - ); + this.cfg.goto(body_block_end, source_info, loop_block); }, ); exit_block.unit() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index c0a7439b5ce57..6869930509cbe 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -259,11 +259,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, match_scope, ); - this.cfg.terminate( - binding_end, - source_info, - TerminatorKind::Goto { target: arm_block }, - ); + this.cfg.goto(binding_end, source_info, arm_block); } } @@ -279,11 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let end_block = self.cfg.start_new_block(); for arm_block in arm_end_blocks { - self.cfg.terminate( - unpack!(arm_block), - outer_source_info, - TerminatorKind::Goto { target: end_block }, - ); + self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); } self.source_scope = outer_source_info.scope; @@ -848,18 +840,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // never reach this point. if unmatched_candidates.is_empty() { let source_info = self.source_info(span); - if let Some(otherwise) = otherwise_block { - self.cfg.terminate( - block, - source_info, - TerminatorKind::Goto { target: otherwise }, - ); - } else { - self.cfg.terminate( - block, - source_info, - TerminatorKind::Unreachable, - ) + match otherwise_block { + Some(otherwise) => self.cfg.goto(block, source_info, otherwise), + None => self.cfg.terminate(block, source_info, TerminatorKind::Unreachable), } return; } @@ -950,11 +933,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `goto -> first_prebinding_block` from the `start_block` if there is one. if let Some(start_block) = *start_block { let source_info = self.source_info(first_candidate.span); - self.cfg.terminate( - start_block, - source_info, - TerminatorKind::Goto { target: first_prebinding_block }, - ); + self.cfg.goto(start_block, source_info, first_prebinding_block); } else { *start_block = Some(first_prebinding_block); } @@ -988,8 +967,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let last_candidate = reachable_candidates.last().unwrap(); + let last_candidate = reachable_candidates.last().unwrap(); if let Some(otherwise) = last_candidate.otherwise_block { let source_info = self.source_info(last_candidate.span); let block = self.cfg.start_new_block(); diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index ec8b3c5e24bf2..87481d1d69bc7 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -109,15 +109,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); } - _ => { - self.cfg.terminate( - from_block, - source_info, - TerminatorKind::Goto { - target: real_target - } - ); - } + _ => self.cfg.goto(from_block, source_info, real_target), } } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 3479ad6749a90..1ecae105694ed 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -606,14 +606,11 @@ where let fn_end = span.shrink_to_hi(); let source_info = builder.source_info(fn_end); let return_block = builder.return_block(); - builder.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: return_block }); - builder.cfg.terminate(return_block, source_info, - TerminatorKind::Return); + builder.cfg.goto(block, source_info, return_block); + builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); // Attribute any unreachable codepaths to the function's closing brace if let Some(unreachable_block) = builder.cached_unreachable_block { - builder.cfg.terminate(unreachable_block, source_info, - TerminatorKind::Unreachable); + builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable); } return_block.unit() })); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 00a30af806a89..9c5966263dfc0 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -564,14 +564,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = scope.source_info(span); block = match scope.cached_exits.entry((target, region_scope)) { Entry::Occupied(e) => { - self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: *e.get() }); + self.cfg.goto(block, source_info, *e.get()); return; } Entry::Vacant(v) => { let b = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: b }); + self.cfg.goto(block, source_info, b); v.insert(b); b } @@ -596,8 +594,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scope = next_scope; } - let source_info = self.scopes.source_info(scope_count, span); - self.cfg.terminate(block, source_info, TerminatorKind::Goto { target }); + self.cfg.goto(block, self.scopes.source_info(scope_count, span), target); } /// Creates a path that performs all required cleanup for dropping a generator. @@ -616,14 +613,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { while let Some(scope) = scopes.next() { block = if let Some(b) = scope.cached_generator_drop { - self.cfg.terminate(block, src_info, - TerminatorKind::Goto { target: b }); + self.cfg.goto(block, src_info, b); return Some(result); } else { let b = self.cfg.start_new_block(); scope.cached_generator_drop = Some(b); - self.cfg.terminate(block, src_info, - TerminatorKind::Goto { target: b }); + self.cfg.goto(block, src_info, b); b }; @@ -1243,8 +1238,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, // block for our StorageDead statements. let block = cfg.start_new_cleanup_block(); let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope }; - cfg.terminate(block, source_info, - TerminatorKind::Goto { target: target }); + cfg.goto(block, source_info, target); target = block; target_built_by_us = true; } From d85578287c40031b61c252daba0572181b6117f4 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Dec 2019 15:31:52 -0600 Subject: [PATCH 16/21] convert hrtb error --- .../borrow_check/diagnostics/region_errors.rs | 10 ++++++ src/librustc_mir/borrow_check/mod.rs | 19 ++++++++++ .../borrow_check/region_infer/mod.rs | 36 +++++-------------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 481494f6a3abe..98a1d7dad94bd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -98,6 +98,16 @@ crate enum RegionErrorKind<'tcx> { member_region: ty::Region<'tcx>, }, + /// Higher-ranked subtyping error + BoundUniversalRegionError { + /// The placeholder free region. + longer_fr: RegionVid, + /// The region that erroneously must be outlived by `longer_fr`. + error_region: RegionVid, + /// The origin of the placeholder region + fr_origin: NLLRegionVariableOrigin, + }, + /// Any other lifetime error RegionError { /// The origin of the region diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 153ee23811e92..9fc6b0ffb2d59 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1647,6 +1647,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .buffer(&mut self.errors_buffer); } + RegionErrorKind::BoundUniversalRegionError { + longer_fr, fr_origin, error_region, + } => { + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. + let (_, span) = self.nonlexical_regioncx.find_outlives_blame_span( + &self.body, + longer_fr, + fr_origin, + error_region, + ); + + // FIXME: improve this error message + self.infcx + .tcx + .sess + .struct_span_err(span, "higher-ranked subtype error") + .buffer(&mut self.errors_buffer); + } + RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported, } => { diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 3afe2056a926f..5310ac6c48faa 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -9,7 +9,6 @@ use rustc::mir::{ ConstraintCategory, Local, Location, }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; -use rustc_errors::DiagnosticBuilder; use rustc_data_structures::binary_search_util; use rustc_index::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -435,7 +434,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut rustc_errors::DiagnosticBuilder<'_>) { self.universal_regions.annotate(tcx, err) } @@ -507,18 +506,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraints were too strong, and if so, emit or propagate those errors. if infcx.tcx.sess.opts.debugging_opts.polonius { self.check_polonius_subset_errors( - infcx, body, - mir_def_id, outlives_requirements.as_mut(), &mut errors_buffer, polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { self.check_universal_regions( - infcx, body, - mir_def_id, outlives_requirements.as_mut(), &mut errors_buffer, ); @@ -1291,9 +1286,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_universal_regions( &self, - infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { @@ -1312,7 +1305,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } NLLRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder); + self.check_bound_universal_region(fr, placeholder, errors_buffer); } NLLRegionVariableOrigin::Existential { .. } => { @@ -1345,9 +1338,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_polonius_subset_errors( &self, - infcx: &InferCtxt<'_, 'tcx>, body: &Body<'tcx>, - mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, polonius_output: Rc, @@ -1413,7 +1404,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } NLLRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder); + self.check_bound_universal_region(fr, placeholder, errors_buffer); } NLLRegionVariableOrigin::Existential { .. } => { @@ -1573,11 +1564,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_bound_universal_region( &self, - infcx: &InferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - _mir_def_id: DefId, longer_fr: RegionVid, placeholder: ty::PlaceholderRegion, + errors_buffer: &mut RegionErrors<'tcx>, ) { debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); @@ -1614,18 +1603,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { .unwrap(), }; - // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.find_outlives_blame_span( - body, longer_fr, NLLRegionVariableOrigin::Placeholder(placeholder), error_region - ); - - // Obviously, this error message is far from satisfactory. - // At present, though, it only appears in unit tests -- - // the AST-based checker uses a more conservative check, - // so to even see this error, one must pass in a special - // flag. - let mut diag = infcx.tcx.sess.struct_span_err(span, "higher-ranked subtype error"); - diag.emit(); + errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { + longer_fr, + error_region, + fr_origin: NLLRegionVariableOrigin::Placeholder(placeholder), + }); } fn check_member_constraints( From 1d9c56189f4b6f09ffd269e63bff98ede0b93b11 Mon Sep 17 00:00:00 2001 From: mark Date: Sat, 21 Dec 2019 15:33:34 -0600 Subject: [PATCH 17/21] minor updates to comments --- .../borrow_check/diagnostics/region_errors.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 98a1d7dad94bd..801f801fc9097 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -70,51 +70,51 @@ crate type RegionErrors<'tcx> = Vec>; #[derive(Clone, Debug)] crate enum RegionErrorKind<'tcx> { - /// An error for a type test: `T: 'a` does not live long enough + /// An error for a type test: `T: 'a` does not live long enough. TypeTestDoesNotLiveLongEnough { - /// The span of the type test + /// The span of the type test. span: Span, - /// The generic type of the type test + /// The generic type of the type test. generic: GenericKind<'tcx>, }, - /// A generic bound failure for a type test + /// A generic bound failure for a type test. TypeTestGenericBoundError { - /// The span of the type test + /// The span of the type test. span: Span, - /// The generic type of the type test + /// The generic type of the type test. generic: GenericKind<'tcx>, - /// The lower bound region + /// The lower bound region. lower_bound_region: ty::Region<'tcx>, }, - /// An unexpected hidden region for an opaque type + /// An unexpected hidden region for an opaque type. UnexpectedHiddenRegion { - /// The def id of the opaque type + /// The def id of the opaque type. opaque_type_def_id: DefId, - /// The hidden type + /// The hidden type. hidden_ty: Ty<'tcx>, - /// The unexpected region + /// The unexpected region. member_region: ty::Region<'tcx>, }, - /// Higher-ranked subtyping error + /// Higher-ranked subtyping error. BoundUniversalRegionError { /// The placeholder free region. longer_fr: RegionVid, /// The region that erroneously must be outlived by `longer_fr`. error_region: RegionVid, - /// The origin of the placeholder region + /// The origin of the placeholder region. fr_origin: NLLRegionVariableOrigin, }, - /// Any other lifetime error + /// Any other lifetime error. RegionError { - /// The origin of the region + /// The origin of the region. fr_origin: NLLRegionVariableOrigin, - /// The region that should outlive `shorter_fr` + /// The region that should outlive `shorter_fr`. longer_fr: RegionVid, - /// The region that should be shorter, but we can't prove it + /// The region that should be shorter, but we can't prove it. shorter_fr: RegionVid, /// Indicates whether this is a reported error. We currently only report the first error /// encountered and leave the rest unreported so as not to overwhelm the user. From c010d843aacc32ed2bc03d36121aa7f6e08ef045 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 30 Nov 2019 08:42:56 +1300 Subject: [PATCH 18/21] Add simpler entry points to const eval for common usages. --- src/librustc/mir/interpret/mod.rs | 4 +- src/librustc/mir/interpret/queries.rs | 89 ++++++++++++++++++++++ src/librustc/query/mod.rs | 11 ++- src/librustc/traits/fulfill.rs | 29 ++----- src/librustc/traits/select.rs | 22 ++---- src/librustc/ty/mod.rs | 10 +-- src/librustc/ty/sty.rs | 12 +-- src/librustc_codegen_llvm/consts.rs | 10 +-- src/librustc_codegen_llvm/intrinsic.rs | 9 +-- src/librustc_codegen_ssa/mir/block.rs | 7 +- src/librustc_codegen_ssa/mir/constant.rs | 19 ++--- src/librustc_codegen_ssa/mir/place.rs | 7 +- src/librustc_lint/builtin.rs | 12 +-- src/librustc_mir/const_eval.rs | 4 +- src/librustc_mir/hair/cx/expr.rs | 18 ++--- src/librustc_mir/hair/pattern/mod.rs | 81 +++++++++----------- src/librustc_mir/interpret/intrinsics.rs | 10 +-- src/librustc_mir/interpret/place.rs | 7 +- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 38 ++------- src/librustc_typeck/check/expr.rs | 17 +---- src/librustc_typeck/check/mod.rs | 10 +-- src/librustdoc/clean/mod.rs | 20 +---- 23 files changed, 195 insertions(+), 253 deletions(-) create mode 100644 src/librustc/mir/interpret/queries.rs diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index fff876752db55..80bac92d00354 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -101,6 +101,7 @@ mod error; mod value; mod allocation; mod pointer; +mod queries; pub use self::error::{ InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error, @@ -116,9 +117,10 @@ pub use self::pointer::{Pointer, PointerArithmetic, CheckInAllocMsg}; use crate::mir; use crate::hir::def_id::DefId; -use crate::ty::{self, TyCtxt, Instance, subst::GenericArgKind}; +use crate::ty::{self, TyCtxt, Instance}; use crate::ty::codec::TyDecoder; use crate::ty::layout::{self, Size}; +use crate::ty::subst::GenericArgKind; use std::io; use std::fmt; use std::num::NonZeroU32; diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs new file mode 100644 index 0000000000000..5fd49a056d22c --- /dev/null +++ b/src/librustc/mir/interpret/queries.rs @@ -0,0 +1,89 @@ +use super::{ConstEvalResult, ErrorHandled, GlobalId}; + +use crate::mir; +use crate::hir::def_id::DefId; +use crate::ty::{self, TyCtxt}; +use crate::ty::subst::{InternalSubsts, SubstsRef}; +use syntax_pos::Span; + + +impl<'tcx> TyCtxt<'tcx> { + + /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts + /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { + // In some situations def_id will have substitutions within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions + // into `const_eval` which will return `ErrorHandled::ToGeneric` if any og them are + // encountered. + let substs = InternalSubsts::identity_for_item(self, def_id); + let instance = ty::Instance::new(def_id, substs); + let cid = GlobalId { + instance, + promoted: None, + }; + let param_env = self.param_env(def_id); + self.const_eval_validated(param_env.and(cid)) + } + + /// Resolves and evaluates a constant. + /// + /// The constant can be located on a trait like `::C`, in which case the given + /// substitutions and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still + /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is + /// returned. + pub fn const_eval_resolve( + self, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + span: Option + ) -> ConstEvalResult<'tcx> { + let instance = ty::Instance::resolve( + self, + param_env, + def_id, + substs, + ); + if let Some(instance) = instance { + self.const_eval_instance(param_env, instance, span) + } else { + Err(ErrorHandled::TooGeneric) + } + } + + pub fn const_eval_instance( + self, + param_env: ty::ParamEnv<'tcx>, + instance: ty::Instance<'tcx>, + span: Option + ) -> ConstEvalResult<'tcx> { + let cid = GlobalId { + instance, + promoted: None, + }; + if let Some(span) = span { + self.at(span).const_eval_validated(param_env.and(cid)) + } else { + self.const_eval_validated(param_env.and(cid)) + } + } + + /// Evaluate a promoted constant. + pub fn const_eval_promoted( + self, + instance: ty::Instance<'tcx>, + promoted: mir::Promoted + ) -> ConstEvalResult<'tcx> { + let cid = GlobalId { + instance, + promoted: Some(promoted), + }; + let param_env = ty::ParamEnv::reveal_all(); + self.const_eval_validated(param_env.and(cid)) + } +} diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index cc02165f60579..a9dd856e75857 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -448,7 +448,8 @@ rustc_queries! { /// /// **Do not use this** outside const eval. Const eval uses this to break query cycles /// during validation. Please add a comment to every use site explaining why using - /// `const_eval` isn't sufficient. + /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable + /// form to be used outside of const eval. query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalRawResult<'tcx> { no_force @@ -460,7 +461,13 @@ rustc_queries! { /// Results of evaluating const items or constants embedded in /// other items (such as enum variant explicit discriminants). - query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + /// + /// In contrast to `const_eval_raw` this performs some validation on the constant, and + /// returns a proper constant that is usable by the rest of the compiler. + /// + /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, + /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`. + query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalResult<'tcx> { no_force desc { |tcx| diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 27731990d2b62..3fd2415c83c0c 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -1,5 +1,4 @@ use crate::infer::{InferCtxt, ShallowResolver}; -use crate::mir::interpret::{GlobalId, ErrorHandled}; use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef}; use crate::ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; @@ -501,27 +500,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ProcessResult::Unchanged } else { if !substs.has_local_value() { - let instance = ty::Instance::resolve( - self.selcx.tcx(), - obligation.param_env, - def_id, - substs, - ); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - match self.selcx.tcx().at(obligation.cause.span) - .const_eval(obligation.param_env.and(cid)) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => ProcessResult::Error( - CodeSelectionError(ConstEvalFailure(err))) - } - } else { - ProcessResult::Error(CodeSelectionError( - ConstEvalFailure(ErrorHandled::TooGeneric) - )) + match self.selcx.tcx().const_eval_resolve(obligation.param_env, + def_id, + substs, + Some(obligation.cause.span)) { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(err))) } } else { pending_obligation.stalled_on = diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 94a77c553e53a..8d04c832f266c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -33,7 +33,6 @@ use crate::dep_graph::{DepKind, DepNodeIndex}; use crate::hir::def_id::DefId; use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; use crate::middle::lang_items; -use crate::mir::interpret::GlobalId; use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; @@ -820,22 +819,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Predicate::ConstEvaluatable(def_id, substs) => { - let tcx = self.tcx(); if !(obligation.param_env, substs).has_local_value() { - let param_env = obligation.param_env; - let instance = - ty::Instance::resolve(tcx, param_env, def_id, substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - match self.tcx().const_eval(param_env.and(cid)) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), - } - } else { - Ok(EvaluatedToErr) + match self.tcx().const_eval_resolve(obligation.param_env, + def_id, + substs, + None) { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), } } else { // Inference variables still left in param_env or substs. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 15bbfa7860fa7..c60d4a46935ad 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,7 +19,7 @@ use crate::middle::cstore::CrateStoreDyn; use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::mir::ReadOnlyBodyAndCache; -use crate::mir::interpret::{GlobalId, ErrorHandled}; +use crate::mir::interpret::ErrorHandled; use crate::mir::GeneratorLayout; use crate::session::CrateDisambiguator; use crate::traits::{self, Reveal}; @@ -2344,13 +2344,7 @@ impl<'tcx> AdtDef { pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option> { let param_env = tcx.param_env(expr_did); let repr_type = self.repr.discr_type(); - let substs = InternalSubsts::identity_for_item(tcx, expr_did); - let instance = ty::Instance::new(expr_did, substs); - let cid = GlobalId { - instance, - promoted: None - }; - match tcx.const_eval(param_env.and(cid)) { + match tcx.const_eval_poly(expr_did) { Ok(val) => { // FIXME: Find the right type and use it instead of `val.ty` here if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 6cb0d1e9946b5..1e08c36ca50a0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -15,7 +15,7 @@ use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFolda use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv}; use crate::ty::layout::VariantIdx; use crate::util::captures::Captures; -use crate::mir::interpret::{Scalar, GlobalId}; +use crate::mir::interpret::Scalar; use polonius_engine::Atom; use rustc_index::vec::Idx; @@ -2340,13 +2340,9 @@ impl<'tcx> Const<'tcx> { let (param_env, substs) = param_env_and_substs.into_parts(); - // try to resolve e.g. associated constants to their definition on an impl - let instance = ty::Instance::resolve(tcx, param_env, did, substs)?; - let gid = GlobalId { - instance, - promoted: None, - }; - tcx.const_eval(param_env.and(gid)).ok() + // try to resolve e.g. associated constants to their definition on an impl, and then + // evaluate the const. + tcx.const_eval_resolve(param_env, did, substs, None).ok() }; match self.val { diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 11a105c1828ca..c048321e383fb 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -8,7 +8,7 @@ use crate::value::Value; use libc::c_uint; use rustc::hir::def_id::DefId; use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint, - Pointer, ErrorHandled, GlobalId}; + Pointer, ErrorHandled}; use rustc::mir::mono::MonoItem; use rustc::hir::Node; use rustc_target::abi::HasDataLayout; @@ -81,13 +81,7 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let instance = ty::Instance::mono(cx.tcx, def_id); - let cid = GlobalId { - instance, - promoted: None, - }; - let param_env = ty::ParamEnv::reveal_all(); - let static_ = cx.tcx.const_eval(param_env.and(cid))?; + let static_ = cx.tcx.const_eval_poly(def_id)?; let alloc = match static_.val { ty::ConstKind::Value(ConstValue::ByRef { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 900f2d2defc0f..da776757fdfc2 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -14,7 +14,6 @@ use rustc_codegen_ssa::glue; use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types}; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, FnAbiExt, LayoutOf, HasTyCtxt, Primitive}; -use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use rustc_target::abi::HasDataLayout; @@ -202,11 +201,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "needs_drop" | "type_id" | "type_name" => { - let gid = GlobalId { - instance, - promoted: None, - }; - let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap(); + let ty_name = self.tcx + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) + .unwrap(); OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self) } "init" => { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index dabd097b000b5..a532c23a6e0a2 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -638,12 +638,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { projection: &[], } = place.as_ref() { - let param_env = ty::ParamEnv::reveal_all(); - let cid = mir::interpret::GlobalId { - instance: self.instance, - promoted: Some(promoted), - }; - let c = bx.tcx().const_eval(param_env.and(cid)); + let c = bx.tcx().const_eval_promoted(self.instance, promoted); let (llval, ty) = self.simd_shuffle_indices( &bx, terminator.source_info.span, diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index fb8f504d04b10..fc17e2c0c71b7 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -43,17 +43,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match constant.literal.val { ty::ConstKind::Unevaluated(def_id, substs) => { let substs = self.monomorphize(&substs); - let instance = ty::Instance::resolve( - self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs, - ).unwrap(); - let cid = mir::interpret::GlobalId { - instance, - promoted: None, - }; - self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| { - self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); - err - }) + self.cx.tcx() + .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None) + .map_err(|err| { + self.cx.tcx().sess.span_err( + constant.span, + "erroneous constant encountered"); + err + }) }, _ => Ok(self.monomorphize(&constant.literal)), } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 5e13cabced000..1132f9b2f033e 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -473,14 +473,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }), projection: [], } => { - let param_env = ty::ParamEnv::reveal_all(); let instance = Instance::new(*def_id, self.monomorphize(substs)); - let cid = mir::interpret::GlobalId { - instance: instance, - promoted: Some(*promoted), - }; let layout = cx.layout_of(self.monomorphize(&ty)); - match bx.tcx().const_eval(param_env.and(cid)) { + match bx.tcx().const_eval_promoted(instance, *promoted) { Ok(val) => match val.val { ty::ConstKind::Value(mir::interpret::ConstValue::ByRef { alloc, offset diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 10b00d35d9bca..b46e8a8438fbe 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1134,19 +1134,9 @@ declare_lint_pass!( fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { let def_id = cx.tcx.hir().body_owner_def_id(body_id); - let param_env = if cx.tcx.is_static(def_id) { - // Use the same param_env as `codegen_static_initializer`, to reuse the cache. - ty::ParamEnv::reveal_all() - } else { - cx.tcx.param_env(def_id) - }; - let cid = ::rustc::mir::interpret::GlobalId { - instance: ty::Instance::mono(cx.tcx, def_id), - promoted: None - }; // trigger the query once for all constants since that will already report the errors // FIXME: Use ensure here - let _ = cx.tcx.const_eval(param_env.and(cid)); + let _ = cx.tcx.const_eval_poly(def_id); } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index b219fec31dc59..a2f066bee08d1 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -652,7 +652,7 @@ fn validate_and_turn_into_const<'tcx>( }) } -pub fn const_eval_provider<'tcx>( +pub fn const_eval_validated_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { @@ -660,7 +660,7 @@ pub fn const_eval_provider<'tcx>( if key.param_env.reveal == Reveal::All { let mut key = key.clone(); key.param_env.reveal = Reveal::UserFacing; - match tcx.const_eval(key) { + match tcx.const_eval_validated(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => { // Promoteds should never be "too generic" when getting evaluated. diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8c852854be1f9..f116f7d14da70 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -5,7 +5,7 @@ use crate::hair::cx::to_ref::ToRef; use crate::hair::util::UserAnnotatedTyHelpers; use rustc_index::vec::Idx; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; -use rustc::mir::interpret::{GlobalId, ErrorHandled, Scalar}; +use rustc::mir::interpret::{ErrorHandled, Scalar}; use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; @@ -514,21 +514,15 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Repeat(ref v, ref count) => { let def_id = cx.tcx.hir().local_def_id(count.hir_id); let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::resolve( - cx.tcx, - cx.param_env, - def_id, - substs, - ).unwrap(); - let global_id = GlobalId { - instance, - promoted: None - }; let span = cx.tcx.def_span(def_id); - let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) { + let count = match cx.tcx.const_eval_resolve(cx.param_env, + def_id, + substs, + Some(span)) { Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env), Err(ErrorHandled::Reported) => 0, Err(ErrorHandled::TooGeneric) => { + let span = cx.tcx.def_span(def_id); cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters"); 0 }, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 0086c3b0e103f..e12f0322564bf 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -11,7 +11,7 @@ use crate::hair::constant::*; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; -use rustc::mir::interpret::{GlobalId, ConstValue, get_slice_bytes, sign_extend}; +use rustc::mir::interpret::{ConstValue, ErrorHandled, get_slice_bytes, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; use rustc::ty::subst::{SubstsRef, GenericArg}; @@ -854,57 +854,37 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let kind = match res { Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let substs = self.tables.node_substs(id); - match ty::Instance::resolve( - self.tcx, - self.param_env, - def_id, - substs, - ) { - Some(instance) => { - let cid = GlobalId { - instance, - promoted: None, - }; - match self.tcx.at(span).const_eval(self.param_env.and(cid)) { - Ok(value) => { - let pattern = self.const_to_pat(value, id, span); - if !is_associated_const { - return pattern; - } + match self.tcx.const_eval_resolve(self.param_env, def_id, substs, Some(span)) { + Ok(value) => { + let pattern = self.const_to_pat(value, id, span); + if !is_associated_const { + return pattern; + } - let user_provided_types = self.tables().user_provided_types(); - return if let Some(u_ty) = user_provided_types.get(id) { - let user_ty = PatTyProj::from_user_type(*u_ty); - Pat { - span, - kind: Box::new( - PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - /// Note that use `Contravariant` here. See the - /// `variance` field documentation for details. - variance: ty::Variance::Contravariant, - user_ty, - user_ty_span: span, - }, - } - ), - ty: value.ty, + let user_provided_types = self.tables().user_provided_types(); + return if let Some(u_ty) = user_provided_types.get(id) { + let user_ty = PatTyProj::from_user_type(*u_ty); + Pat { + span, + kind: Box::new( + PatKind::AscribeUserType { + subpattern: pattern, + ascription: Ascription { + /// Note that use `Contravariant` here. See the + /// `variance` field documentation for details. + variance: ty::Variance::Contravariant, + user_ty, + user_ty_span: span, + }, } - } else { - pattern - } - }, - Err(_) => { - self.tcx.sess.span_err( - span, - "could not evaluate constant pattern", - ); - PatKind::Wild + ), + ty: value.ty, } + } else { + pattern } }, - None => { + Err(ErrorHandled::TooGeneric) => { self.errors.push(if is_associated_const { PatternError::AssocConstInPattern(span) } else { @@ -912,6 +892,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }); PatKind::Wild }, + Err(_) => { + self.tcx.sess.span_err( + span, + "could not evaluate constant pattern", + ); + PatKind::Wild + } } } _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]), diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 67f0aed243da1..46782ef0a806b 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -11,7 +11,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; use rustc::mir::{ self, BinOp, - interpret::{InterpResult, Scalar, GlobalId, ConstValue} + interpret::{InterpResult, Scalar, ConstValue} }; use super::{ @@ -123,11 +123,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::size_of | sym::type_id | sym::type_name => { - let gid = GlobalId { - instance, - promoted: None, - }; - let val = self.tcx.const_eval(self.param_env.and(gid))?; + let val = self.tcx.const_eval_instance(self.param_env, + instance, + Some(self.tcx.span))?; let val = self.eval_const_to_op(val, None)?; self.copy_op(val, dest)?; } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 42fbfeca3f05d..70ea3745b4d7e 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -619,11 +619,6 @@ where let ty = place_static.ty; assert!(!ty.needs_subst()); let layout = self.layout_of(ty)?; - let instance = ty::Instance::mono(*self.tcx, place_static.def_id); - let cid = GlobalId { - instance, - promoted: None - }; // Just create a lazy reference, so we can support recursive statics. // tcx takes care of assigning every static one and only one unique AllocId. // When the data here is ever actually used, memory will notice, @@ -639,7 +634,7 @@ where // Notice that statics have *two* AllocIds: the lazy one, and the resolved // one. Here we make sure that the interpreted program never sees the // resolved ID. Also see the doc comment of `Memory::get_static_alloc`. - let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id()); + let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(place_static.def_id); let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id)); MPlaceTy::from_aligned_ptr(ptr, layout) } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f6b3c5b8e5e82..cf54530317c43 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -56,7 +56,7 @@ pub fn provide(providers: &mut Providers<'_>) { shim::provide(providers); transform::provide(providers); monomorphize::partitioning::provide(providers); - providers.const_eval = const_eval::const_eval_provider; + providers.const_eval_validated = const_eval::const_eval_validated_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; providers.const_caller_location = const_eval::const_caller_location; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 93a76712b2869..ab95c795c4324 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -189,7 +189,7 @@ use rustc::session::config::EntryFnType; use rustc::mir::{self, Location, PlaceBase, Static, StaticKind}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::{MonoItem, InstantiationMode}; -use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled}; +use rustc::mir::interpret::{Scalar, GlobalAlloc, ErrorHandled}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use rustc::util::common::time; @@ -379,13 +379,7 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; - let cid = GlobalId { - instance, - promoted: None, - }; - let param_env = ty::ParamEnv::reveal_all(); - - if let Ok(val) = tcx.const_eval(param_env.and(cid)) { + if let Ok(val) = tcx.const_eval_poly(def_id) { collect_const(tcx, val, InternalSubsts::empty(), &mut neighbors); } } @@ -681,12 +675,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { def_id, .. }) => { - let param_env = ty::ParamEnv::reveal_all(); - let cid = GlobalId { - instance: Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)), - promoted: Some(*promoted), - }; - match self.tcx.const_eval(param_env.and(cid)) { + let instance = Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)); + match self.tcx.const_eval_promoted(instance, *promoted) { Ok(val) => collect_const(self.tcx, val, substs, self.output), Err(ErrorHandled::Reported) => {}, Err(ErrorHandled::TooGeneric) => { @@ -1041,14 +1031,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { // but even just declaring them must collect the items they refer to let def_id = self.tcx.hir().local_def_id(item.hir_id); - let instance = Instance::mono(self.tcx, def_id); - let cid = GlobalId { - instance, - promoted: None, - }; - let param_env = ty::ParamEnv::reveal_all(); - - if let Ok(val) = self.tcx.const_eval(param_env.and(cid)) { + if let Ok(val) = self.tcx.const_eval_poly(def_id) { collect_const(self.tcx, val, InternalSubsts::empty(), &mut self.output); } } @@ -1288,16 +1271,7 @@ fn collect_const<'tcx>( } } ty::ConstKind::Unevaluated(def_id, substs) => { - let instance = ty::Instance::resolve(tcx, - param_env, - def_id, - substs).unwrap(); - - let cid = GlobalId { - instance, - promoted: None, - }; - match tcx.const_eval(param_env.and(cid)) { + match tcx.const_eval_resolve(param_env, def_id, substs, None) { Ok(val) => collect_const(tcx, val, param_substs, output), Err(ErrorHandled::Reported) => {}, Err(ErrorHandled::TooGeneric) => span_bug!( diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 19441be87b959..b287b39cb99c4 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -31,7 +31,6 @@ use rustc::hir::ptr::P; use rustc::infer; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::middle::lang_items; -use rustc::mir::interpret::GlobalId; use rustc::ty; use rustc::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -39,7 +38,6 @@ use rustc::ty::adjustment::{ use rustc::ty::{AdtKind, Visibility}; use rustc::ty::Ty; use rustc::ty::TypeFoldable; -use rustc::ty::subst::InternalSubsts; use rustc::traits::{self, ObligationCauseCode}; use rustc_error_codes::*; @@ -1023,20 +1021,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count = if self.const_param_def_id(count).is_some() { Ok(self.to_const(count, tcx.type_of(count_def_id))) } else { - let param_env = ty::ParamEnv::empty(); - let substs = InternalSubsts::identity_for_item(tcx, count_def_id); - let instance = ty::Instance::resolve( - tcx, - param_env, - count_def_id, - substs, - ).unwrap(); - let global_id = GlobalId { - instance, - promoted: None - }; - - tcx.const_eval(param_env.and(global_id)) + tcx.const_eval_poly(count_def_id) }; let uty = match expected { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 09771bb762536..84f5847ddd325 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,7 +106,7 @@ use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::middle::region; -use rustc::mir::interpret::{ConstValue, GlobalId}; +use rustc::mir::interpret::ConstValue; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{ self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, @@ -1836,13 +1836,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - let instance = ty::Instance::mono(tcx, id); - let cid = GlobalId { - instance, - promoted: None - }; - let param_env = ty::ParamEnv::reveal_all(); - if let Ok(static_) = tcx.const_eval(param_env.and(cid)) { + if let Ok(static_) = tcx.const_eval_poly(id) { let alloc = if let ty::ConstKind::Value(ConstValue::ByRef { alloc, .. }) = static_.val { alloc } else { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e5f684cbca87b..7eb1370c342d3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,7 +15,6 @@ use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::middle::stability; -use rustc::mir::interpret::GlobalId; use rustc::hir; use rustc::hir::def::{CtorKind, DefKind, Res}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; @@ -1334,13 +1333,7 @@ impl Clean for hir::Ty { TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); - let param_env = cx.tcx.param_env(def_id); - let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); - let cid = GlobalId { - instance: ty::Instance::new(def_id, substs), - promoted: None - }; - let length = match cx.tcx.const_eval(param_env.and(cid)) { + let length = match cx.tcx.const_eval_poly(def_id) { Ok(length) => print_const(cx, length), Err(_) => cx.sess() .source_map() @@ -1534,16 +1527,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { let mut n = cx.tcx.lift(&n).expect("array lift failed"); - if let ty::ConstKind::Unevaluated(def_id, substs) = n.val { - let param_env = cx.tcx.param_env(def_id); - let cid = GlobalId { - instance: ty::Instance::new(def_id, substs), - promoted: None - }; - if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) { - n = new_n; - } - }; + n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); Array(box ty.clean(cx), n) } From 687891309659fd2942f4c8bc8f9fd2feaf85d864 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 22 Dec 2019 07:54:18 -0500 Subject: [PATCH 19/21] Document why Any is not an unsafe trait --- src/libcore/any.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index a2aa6b3fea50c..5126fe01a3f00 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -74,6 +74,16 @@ use crate::intrinsics; /// See the [module-level documentation][mod] for more details. /// /// [mod]: index.html +// This trait is not unsafe, though we rely on the specifics of it's sole impl's +// `type_id` function in unsafe code (e.g., `downcast`). Normally, that would be +// a problem, but because the only impl of `Any` is a blanket implementation, no +// other code can implement `Any`. +// +// We could plausibly make this trait unsafe -- it would not cause breakage, +// since we control all the implementations -- but we choose not to as that's +// both not really necessary and may confuse users about the distinction of +// unsafe traits and unsafe methods (i.e., `type_id` would still be safe to call, +// but we would likely want to indicate as such in documentation). #[stable(feature = "rust1", since = "1.0.0")] pub trait Any: 'static { /// Gets the `TypeId` of `self`. From 683c4c788f36d67fbc873629b431105c7758dd68 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 22 Dec 2019 08:22:14 -0500 Subject: [PATCH 20/21] Add error message if `Scalar::from_(u)int` fails --- src/librustc/mir/interpret/value.rs | 10 ++++++++-- src/librustc_mir/interpret/operand.rs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8f5fab4b00291..f48d22291c6a4 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -248,7 +248,10 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_uint(i: impl Into, size: Size) -> Self { - Self::try_from_uint(i, size).unwrap() + let i = i.into(); + Self::try_from_uint(i, size).unwrap_or_else(|| { + bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()) + }) } #[inline] @@ -285,7 +288,10 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_int(i: impl Into, size: Size) -> Self { - Self::try_from_int(i, size).unwrap() + let i = i.into(); + Self::try_from_int(i, size).unwrap_or_else(|| { + bug!("Signed value {:#x} does not fit in {} bits", i, size.bits()) + }) } #[inline] diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8dd50958350bb..294b361ee2721 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -224,7 +224,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { } #[inline] pub fn from_uint(i: impl Into, layout: TyLayout<'tcx>) -> Self { - Self::try_from_uint(i, layout).unwrap() + Self::from_scalar(Scalar::from_uint(i, layout.size), layout) } #[inline] @@ -234,7 +234,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { #[inline] pub fn from_int(i: impl Into, layout: TyLayout<'tcx>) -> Self { - Self::try_from_int(i, layout).unwrap() + Self::from_scalar(Scalar::from_int(i, layout.size), layout) } #[inline] From a6df38ec9f3c1c1126ba750e50a0a40741913ebb Mon Sep 17 00:00:00 2001 From: Rust Toolstate Update <7378925+rust-toolstate-update@users.noreply.github.com> Date: Sun, 22 Dec 2019 09:21:08 -0500 Subject: [PATCH 21/21] Utilize rust-lang/rust commit hashes in toolstate When moving the script out of CI configuration and into a proper script we lost track of the current directory changing (and as such the parameters of the script needing to be different now). --- src/ci/publish_toolstate.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh index d8ff74078220e..4c047069571bd 100755 --- a/src/ci/publish_toolstate.sh +++ b/src/ci/publish_toolstate.sh @@ -14,12 +14,15 @@ printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \ > "$HOME/.git-credentials" git clone --depth=1 $TOOLSTATE_REPO +GIT_COMMIT="$(git rev-parse HEAD)" +GIT_COMMIT_MSG="$(git log --format=%s -n1 HEAD)" + cd rust-toolstate FAILURE=1 for RETRY_COUNT in 1 2 3 4 5; do # The purpose is to publish the new "current" toolstate in the toolstate repo. - "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \ - "$(git log --format=%s -n1 HEAD)" \ + "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$GIT_COMMIT" \ + "$GIT_COMMIT_MSG" \ "$MESSAGE_FILE" \ "$TOOLSTATE_REPO_ACCESS_TOKEN" # `git commit` failing means nothing to commit.