From a8e9708aeb7907979d103f0b56eebba7706c7d0e Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 10 Feb 2022 16:09:49 +0800 Subject: [PATCH 01/34] More practical examples for `Option::and_then` --- library/core/src/option.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ec04692d3e0c8..f8758056db9df 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1207,13 +1207,22 @@ impl Option { /// # Examples /// /// ``` - /// fn sq(x: u32) -> Option { Some(x * x) } - /// fn nope(_: u32) -> Option { None } + /// fn squared_string(x: u32) -> Option { Some((x * x).to_string()) } /// - /// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16)); - /// assert_eq!(Some(2).and_then(sq).and_then(nope), None); - /// assert_eq!(Some(2).and_then(nope).and_then(sq), None); - /// assert_eq!(None.and_then(sq).and_then(sq), None); + /// assert_eq!(Some(2).and_then(squared_string), Some(4.to_string())); + /// assert_eq!(None.and_then(squared_string), None); + /// ``` + /// + /// Often used to chain fallible operations that may return [`None`]. + /// + /// ``` + /// let arr_2d = [["A1", "A2"], ["B1", "B2"]]; + /// + /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1)); + /// assert_eq!(item_0_1, Some(&"A2")); + /// + /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0)); + /// assert_eq!(item_2_0, None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 73a5f01263ffb80d113a9afe7004d940eebb0114 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 10 Feb 2022 16:32:53 +0800 Subject: [PATCH 02/34] Use 0-based idx for array content --- library/core/src/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f8758056db9df..9fe38a505abb3 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1216,10 +1216,10 @@ impl Option { /// Often used to chain fallible operations that may return [`None`]. /// /// ``` - /// let arr_2d = [["A1", "A2"], ["B1", "B2"]]; + /// let arr_2d = [["A0", "A1"], ["B0", "B1"]]; /// /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1)); - /// assert_eq!(item_0_1, Some(&"A2")); + /// assert_eq!(item_0_1, Some(&"A1")); /// /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0)); /// assert_eq!(item_2_0, None); From bd421e2880d3c67ce77c3286d933be8171d0aaa9 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 10 Feb 2022 17:59:46 +0800 Subject: [PATCH 03/34] More practical examples for `Result::and_then` --- library/core/src/result.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 05b4fa035b1ae..bd7333a33e1f6 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1281,16 +1281,22 @@ impl Result { /// /// # Examples /// - /// Basic usage: + /// ``` + /// fn squared_string(x: u32) -> Result { + /// Ok((x * x).to_string()) + /// } /// + /// assert_eq!(Ok(2).and_then(squared_string), Ok(4.to_string())); + /// assert_eq!(Err("not a number").and_then(squared_string), Err("not a number")); /// ``` - /// fn sq(x: u32) -> Result { Ok(x * x) } - /// fn err(x: u32) -> Result { Err(x) } /// - /// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16)); - /// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4)); - /// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2)); - /// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3)); + /// Often used to chain fallible operations that may return [`Err`]. + /// + /// ``` + /// use std::path::Path; + /// + /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); + /// assert!(root_modified_time.is_ok()) /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 942eaa7ffcebad5592bf6865ef8c9e8959ec5b79 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Fri, 11 Feb 2022 09:55:47 +0800 Subject: [PATCH 04/34] Add negative example for `Result::and_then` --- library/core/src/result.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index bd7333a33e1f6..58d58ff0f72eb 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1293,10 +1293,14 @@ impl Result { /// Often used to chain fallible operations that may return [`Err`]. /// /// ``` - /// use std::path::Path; + /// use std::{io::ErrorKind, path::Path}; /// /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); - /// assert!(root_modified_time.is_ok()) + /// assert!(root_modified_time.is_ok()); + /// + /// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); + /// assert!(should_fail.is_err()); + /// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From cb3cff37617a313e0d1a78583355d2abe9f9364b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 17 Jan 2022 22:06:02 +0000 Subject: [PATCH 05/34] Stop using a placeholder for empty regions in Chalk --- compiler/rustc_traits/src/chalk/db.rs | 12 +----- compiler/rustc_traits/src/chalk/lowering.rs | 45 +++++---------------- compiler/rustc_traits/src/chalk/mod.rs | 17 ++------ 3 files changed, 14 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 3f51442277f59..d938a2809ae8d 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -20,11 +20,10 @@ use rustc_span::symbol::sym; use std::fmt; use std::sync::Arc; -use crate::chalk::lowering::{self, LowerInto}; +use crate::chalk::lowering::LowerInto; pub struct RustIrDatabase<'tcx> { pub(crate) interner: RustInterner<'tcx>, - pub(crate) reempty_placeholder: ty::Region<'tcx>, } impl fmt::Debug for RustIrDatabase<'_> { @@ -40,12 +39,9 @@ impl<'tcx> RustIrDatabase<'tcx> { bound_vars: SubstsRef<'tcx>, ) -> Vec>> { let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates; - let mut regions_substitutor = - lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder); predicates .iter() .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars)) - .map(|wc| wc.fold_with(&mut regions_substitutor)) .filter_map(|wc| LowerInto::< Option>> >::lower_into(wc, self.interner)).collect() @@ -287,9 +283,6 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl"); let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars); - let mut regions_substitutor = - lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder); - let trait_ref = trait_ref.fold_with(&mut regions_substitutor); let where_clauses = self.where_clauses_for(def_id, bound_vars); @@ -335,9 +328,6 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let self_ty = trait_ref.self_ty(); let self_ty = self_ty.subst(self.interner.tcx, bound_vars); - let mut regions_substitutor = - lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder); - let self_ty = self_ty.fold_with(&mut regions_substitutor); let lowered_ty = self_ty.lower_into(self.interner); parameters[0].assert_ty_ref(self.interner).could_match( diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 67d0ba39667d3..1f0a99e0e8989 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -464,9 +464,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t }) .intern(interner) } - ReEmpty(_) => unimplemented!(), - // FIXME(chalk): need to handle ReErased - ReErased => unimplemented!(), + ReEmpty(ui) => { + chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() }) + .intern(interner) + } + ReErased => chalk_ir::LifetimeData::Erased.intern(interner), } } } @@ -488,12 +490,12 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime ty::RegionKind::ReStatic, - chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), + chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static, chalk_ir::LifetimeData::Empty(ui) => { - ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter)) + ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter)) } - chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased, + chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased, + chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, }; interner.tcx.mk_region(kind) } @@ -1110,32 +1112,3 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { r.super_visit_with(self) } } - -/// Used to substitute specific `Regions`s with placeholders. -crate struct RegionsSubstitutor<'tcx> { - tcx: TyCtxt<'tcx>, - reempty_placeholder: ty::Region<'tcx>, -} - -impl<'tcx> RegionsSubstitutor<'tcx> { - crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self { - RegionsSubstitutor { tcx, reempty_placeholder } - } -} - -impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - match r { - ty::ReEmpty(ui) => { - assert_eq!(ui.as_usize(), 0); - self.reempty_placeholder - } - - _ => r.super_fold_with(self), - } - } -} diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index 09bfdabf47373..8c42b019554cc 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -22,9 +22,8 @@ use rustc_infer::infer::canonical::{ use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; -use crate::chalk::lowering::{ - LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor, -}; +use crate::chalk::lowering::LowerInto; +use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector}; use chalk_solve::Solution; @@ -42,20 +41,11 @@ crate fn evaluate_goal<'tcx>( let mut placeholders_collector = PlaceholdersCollector::new(); obligation.visit_with(&mut placeholders_collector); - let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { - universe: ty::UniverseIndex::ROOT, - name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), - })); - let mut params_substitutor = ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); let obligation = obligation.fold_with(&mut params_substitutor); - // FIXME(chalk): we really should be substituting these back in the solution let _params: FxHashMap = params_substitutor.params; - let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder); - let obligation = obligation.fold_with(&mut regions_substitutor); - let max_universe = obligation.max_universe.index(); let lowered_goal: chalk_ir::UCanonical< @@ -96,7 +86,8 @@ crate fn evaluate_goal<'tcx>( use chalk_solve::Solver; let mut solver = chalk_engine::solve::SLGSolver::new(32, None); - let db = ChalkRustIrDatabase { interner, reempty_placeholder }; + let db = ChalkRustIrDatabase { interner }; + debug!(?lowered_goal); let solution = solver.solve(&db, &lowered_goal); debug!(?obligation, ?solution, "evaluate goal"); From d4fa173ed31d97aedee04f04e134badb67495293 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 9 Feb 2022 09:50:08 +0000 Subject: [PATCH 06/34] Fix more chalk lowering issues - Implement lowering for subtype goals - Use correct lang item for Generator trait - Use `lower_into` for lowering `ty::Variance` --- compiler/rustc_traits/src/chalk/db.rs | 20 +++++--------------- compiler/rustc_traits/src/chalk/lowering.rs | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index d938a2809ae8d..0170ab223b031 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -546,11 +546,11 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t Fn => lang_items.fn_trait(), FnMut => lang_items.fn_mut_trait(), FnOnce => lang_items.fn_once_trait(), + Generator => lang_items.gen_trait(), Unsize => lang_items.unsize_trait(), Unpin => lang_items.unpin_trait(), CoerceUnsized => lang_items.coerce_unsized_trait(), DiscriminantKind => lang_items.discriminant_kind_trait(), - Generator => lang_items.generator_return(), }; def_id.map(chalk_ir::TraitId) } @@ -674,28 +674,18 @@ impl<'tcx> chalk_ir::UnificationDatabase> for RustIrDatabase< let variances = self.interner.tcx.variances_of(def_id.0); chalk_ir::Variances::from_iter( self.interner, - variances.iter().map(|v| match v { - ty::Variance::Invariant => chalk_ir::Variance::Invariant, - ty::Variance::Covariant => chalk_ir::Variance::Covariant, - ty::Variance::Contravariant => chalk_ir::Variance::Contravariant, - ty::Variance::Bivariant => unimplemented!(), - }), + variances.iter().map(|v| v.lower_into(self.interner)), ) } fn adt_variance( &self, - def_id: chalk_ir::AdtId>, + adt_id: chalk_ir::AdtId>, ) -> chalk_ir::Variances> { - let variances = self.interner.tcx.variances_of(def_id.0.did); + let variances = self.interner.tcx.variances_of(adt_id.0.did); chalk_ir::Variances::from_iter( self.interner, - variances.iter().map(|v| match v { - ty::Variance::Invariant => chalk_ir::Variance::Invariant, - ty::Variance::Covariant => chalk_ir::Variance::Covariant, - ty::Variance::Contravariant => chalk_ir::Variance::Contravariant, - ty::Variance::Bivariant => unimplemented!(), - }), + variances.iter().map(|v| v.lower_into(self.interner)), ) } } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 1f0a99e0e8989..e4d94fd7beb31 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -188,12 +188,18 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)), ), + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { + chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal { + a: a.lower_into(interner), + b: b.lower_into(interner), + }) + } + // FIXME(chalk): other predicates // // We can defer this, but ultimately we'll want to express // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { @@ -790,6 +796,16 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity } } } +impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance { + fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance { + match self { + ty::Variance::Covariant => chalk_ir::Variance::Covariant, + ty::Variance::Invariant => chalk_ir::Variance::Invariant, + ty::Variance::Contravariant => chalk_ir::Variance::Contravariant, + ty::Variance::Bivariant => unimplemented!(), + } + } +} impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound>> for ty::ProjectionPredicate<'tcx> From 1e6d38230ff072cd02827dcb039f7f08fce68d30 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 9 Feb 2022 10:03:47 +0000 Subject: [PATCH 07/34] Reverse parameter to placeholder substitution in chalk results --- compiler/rustc_traits/src/chalk/lowering.rs | 43 +++++++++++++++++---- compiler/rustc_traits/src/chalk/mod.rs | 7 ++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e4d94fd7beb31..6f143c1c607b3 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -1034,10 +1034,6 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - // FIXME(chalk): currently we convert params to placeholders starting at - // index `0`. To support placeholders, we'll actually need to do a - // first pass to collect placeholders. Then we can insert params after. - ty::Placeholder(_) => unimplemented!(), ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), @@ -1053,15 +1049,15 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { })) } }, - _ => t.super_fold_with(self), } } fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { - // FIXME(chalk) - jackh726 - this currently isn't hit in any tests. - // This covers any region variables in a goal, right? + // FIXME(chalk) - jackh726 - this currently isn't hit in any tests, + // since canonicalization will already change these to canonical + // variables (ty::ReLateBound). ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) { Some(idx) => { let br = ty::BoundRegion { @@ -1084,6 +1080,39 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } } +crate struct ReverseParamsSubstitutor<'tcx> { + tcx: TyCtxt<'tcx>, + params: rustc_data_structures::fx::FxHashMap, +} + +impl<'tcx> ReverseParamsSubstitutor<'tcx> { + crate fn new( + tcx: TyCtxt<'tcx>, + params: rustc_data_structures::fx::FxHashMap, + ) -> Self { + Self { tcx, params } + } +} + +impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => { + match self.params.get(&name.as_usize()) { + Some(param) => self.tcx.mk_ty(ty::Param(*param)), + None => t, + } + } + + _ => t.super_fold_with(self), + } + } +} + /// Used to collect `Placeholder`s. crate struct PlaceholdersCollector { universe_index: ty::UniverseIndex, diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index 8c42b019554cc..3c2a266dab9bc 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -23,7 +23,7 @@ use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; use crate::chalk::lowering::LowerInto; -use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector}; +use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor}; use chalk_solve::Solution; @@ -44,7 +44,7 @@ crate fn evaluate_goal<'tcx>( let mut params_substitutor = ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); let obligation = obligation.fold_with(&mut params_substitutor); - let _params: FxHashMap = params_substitutor.params; + let params: FxHashMap = params_substitutor.params; let max_universe = obligation.max_universe.index(); @@ -101,8 +101,9 @@ crate fn evaluate_goal<'tcx>( use rustc_middle::infer::canonical::CanonicalVarInfo; let mut var_values: IndexVec> = IndexVec::new(); + let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params); subst.as_slice(interner).iter().for_each(|p| { - var_values.push(p.lower_into(interner)); + var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor)); }); let variables: Vec<_> = binders .iter(interner) From caa10dc57200a71839ad72d2bf1fd64611721851 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 9 Feb 2022 10:18:32 +0000 Subject: [PATCH 08/34] Renumber universes when canonicalizing for Chalk This is required to avoid creating large numbers of universes from each Chalk query, while still having enough universe information for lifetime errors. --- .../src/infer/canonical/canonicalizer.rs | 173 ++++++++++++++++-- compiler/rustc_middle/src/infer/canonical.rs | 6 +- .../src/traits/chalk_fulfill.rs | 8 +- 3 files changed, 165 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9d40b3cba2952..7446f24968803 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -49,6 +49,29 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state) } + /// Like [Self::canonicalize_query], but preserves distinct universes. For + /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and + /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1` + /// in `U2`. + pub fn canonicalize_chalk_query( + &self, + value: V, + query_state: &mut OriginalQueryValues<'tcx>, + ) -> Canonicalized<'tcx, V> + where + V: TypeFoldable<'tcx>, + { + self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); + + Canonicalizer::canonicalize( + value, + self, + self.tcx, + &CanonicalizeAllFreeRegionsPreservingUniverses, + query_state, + ) + } + /// Canonicalizes a query *response* `V`. When we canonicalize a /// query response, we only canonicalize unbound inference /// variables, and we leave other free regions alone. So, @@ -133,7 +156,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// maximally general query. But if we are canonicalizing a *query /// response*, then we don't typically replace free regions, as they /// must have been introduced from other parts of the system. -trait CanonicalizeRegionMode { +trait CanonicalizeMode { fn canonicalize_free_region<'tcx>( &self, canonicalizer: &mut Canonicalizer<'_, 'tcx>, @@ -141,11 +164,14 @@ trait CanonicalizeRegionMode { ) -> ty::Region<'tcx>; fn any(&self) -> bool; + + // Do we preserve universe of variables. + fn preserve_universes(&self) -> bool; } struct CanonicalizeQueryResponse; -impl CanonicalizeRegionMode for CanonicalizeQueryResponse { +impl CanonicalizeMode for CanonicalizeQueryResponse { fn canonicalize_free_region<'tcx>( &self, canonicalizer: &mut Canonicalizer<'_, 'tcx>, @@ -198,11 +224,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse { fn any(&self) -> bool { false } + + fn preserve_universes(&self) -> bool { + true + } } struct CanonicalizeUserTypeAnnotation; -impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation { +impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { fn canonicalize_free_region<'tcx>( &self, canonicalizer: &mut Canonicalizer<'_, 'tcx>, @@ -221,11 +251,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation { fn any(&self) -> bool { false } + + fn preserve_universes(&self) -> bool { + false + } } struct CanonicalizeAllFreeRegions; -impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions { +impl CanonicalizeMode for CanonicalizeAllFreeRegions { fn canonicalize_free_region<'tcx>( &self, canonicalizer: &mut Canonicalizer<'_, 'tcx>, @@ -237,11 +271,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions { fn any(&self) -> bool { true } + + fn preserve_universes(&self) -> bool { + false + } +} + +struct CanonicalizeAllFreeRegionsPreservingUniverses; + +impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses { + fn canonicalize_free_region<'tcx>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + let universe = canonicalizer.infcx.universe_of_region(r); + canonicalizer.canonical_var_for_region( + CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }, + r, + ) + } + + fn any(&self) -> bool { + true + } + + fn preserve_universes(&self) -> bool { + true + } } struct CanonicalizeFreeRegionsOtherThanStatic; -impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { +impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic { fn canonicalize_free_region<'tcx>( &self, canonicalizer: &mut Canonicalizer<'_, 'tcx>, @@ -257,6 +319,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { fn any(&self) -> bool { true } + + fn preserve_universes(&self) -> bool { + false + } } struct Canonicalizer<'cx, 'tcx> { @@ -267,7 +333,7 @@ struct Canonicalizer<'cx, 'tcx> { // Note that indices is only used once `var_values` is big enough to be // heap-allocated. indices: FxHashMap, BoundVar>, - canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, + canonicalize_mode: &'cx dyn CanonicalizeMode, needs_canonical_flags: TypeFlags, binder_index: ty::DebruijnIndex, @@ -311,7 +377,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { vid, r ); let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid)); - self.canonicalize_region_mode.canonicalize_free_region(self, r) + self.canonicalize_mode.canonicalize_free_region(self, r) } ty::ReStatic @@ -319,7 +385,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::ReFree(_) | ty::ReEmpty(_) | ty::RePlaceholder(..) - | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), + | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r), } } @@ -337,8 +403,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { // `TyVar(vid)` is unresolved, track its universe index in the canonicalized // result. Err(mut ui) => { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; + if !self.canonicalize_mode.preserve_universes() { + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; + } self.canonicalize_ty_var( CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), @@ -422,8 +490,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { // `ConstVar(vid)` is unresolved, track its universe index in the // canonicalized result Err(mut ui) => { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; + if !self.canonicalize_mode.preserve_universes() { + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; + } return self.canonicalize_const_var( CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) }, ct, @@ -462,7 +532,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { value: V, infcx: &InferCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>, - canonicalize_region_mode: &dyn CanonicalizeRegionMode, + canonicalize_region_mode: &dyn CanonicalizeMode, query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'tcx, V> where @@ -493,7 +563,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let mut canonicalizer = Canonicalizer { infcx, tcx, - canonicalize_region_mode, + canonicalize_mode: canonicalize_region_mode, needs_canonical_flags, variables: SmallVec::new(), query_state, @@ -504,10 +574,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // Once we have canonicalized `out_value`, it should not // contain anything that ties it to this inference context - // anymore, so it should live in the global arena. - debug_assert!(!out_value.needs_infer()); + // anymore. + debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders()); - let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables); + let canonical_variables = + tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables()); let max_universe = canonical_variables .iter() @@ -527,6 +598,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let var_values = &mut query_state.var_values; + let universe = info.universe(); + if universe != ty::UniverseIndex::ROOT { + assert!(self.canonicalize_mode.preserve_universes()); + + // Insert universe into the universe map. To preserve the order of the + // universes in the value being canonicalized, we don't update the + // universe in `info` until we have finished canonicalizing. + match query_state.universe_map.binary_search(&universe) { + Err(idx) => query_state.universe_map.insert(idx, universe), + Ok(_) => {} + } + } + // This code is hot. `variables` and `var_values` are usually small // (fewer than 8 elements ~95% of the time). They are SmallVec's to // avoid allocations in those cases. We also don't use `indices` to @@ -569,6 +653,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } } + /// Replaces the universe indexes used in `var_values` with their index in + /// `query_state.universe_map`. This minimizes the maximum universe used in + /// the canonicalized value. + fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> { + if self.query_state.universe_map.len() == 1 { + return self.variables; + } + + let reverse_universe_map: FxHashMap = self + .query_state + .universe_map + .iter() + .enumerate() + .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx))) + .collect(); + + self.variables + .iter() + .map(|v| CanonicalVarInfo { + kind: match v.kind { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { + return *v; + } + CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) + } + CanonicalVarKind::Region(u) => { + CanonicalVarKind::Region(reverse_universe_map[&u]) + } + CanonicalVarKind::Const(u, t) => { + CanonicalVarKind::Const(reverse_universe_map[&u], t) + } + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + }, + }) + .collect() + } + /// Shorthand helper that creates a canonical region variable for /// `r` (always in the root universe). The reason that we always /// put these variables into the root universe is because this diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 28217aeab13ee..4efe3640dfac6 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -64,9 +64,9 @@ pub struct CanonicalVarValues<'tcx> { /// result. #[derive(Clone, Debug)] pub struct OriginalQueryValues<'tcx> { - /// Map from the universes that appear in the query to the - /// universes in the caller context. For the time being, we only - /// ever put ROOT values into the query, so this map is very + /// Map from the universes that appear in the query to the universes in the + /// caller context. For all queries except `evaluate_goal` (used by Chalk), + /// we only ever put ROOT values into the query, so this map is very /// simple. pub universe_map: SmallVec<[ty::UniverseIndex; 4]>, diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 34fc4ca8fead7..28b0ce9a171f8 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -8,7 +8,7 @@ use crate::traits::{ PredicateObligation, SelectionError, TraitEngine, }; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeFoldable}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, @@ -91,7 +91,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { let environment = obligation.param_env.caller_bounds(); let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); + if goal.references_error() { + continue; + } + + let canonical_goal = infcx.canonicalize_chalk_query(goal, &mut orig_values); match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { From 7eaecc6508149da3a0e76982f1259f5bf3cf54a8 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:12:11 +0800 Subject: [PATCH 09/34] `Result::and_then`: improve basic example --- library/core/src/result.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 58d58ff0f72eb..d6a0c7dc29291 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1282,12 +1282,14 @@ impl Result { /// # Examples /// /// ``` - /// fn squared_string(x: u32) -> Result { - /// Ok((x * x).to_string()) + /// fn sq(x: u32) -> Result { + /// x.checked_mul(x).ok_or("overflowed") /// } /// - /// assert_eq!(Ok(2).and_then(squared_string), Ok(4.to_string())); - /// assert_eq!(Err("not a number").and_then(squared_string), Err("not a number")); + /// assert_eq!(Ok(2).and_then(sq), Ok(4)); + /// assert_eq!(Ok(1_000_000).and_then(sq), Err("overflowed")); + /// assert_eq!(Err("not a number").and_then(sq), Err("not a number")); + /// ``` /// /// Often used to chain fallible operations that may return [`Err`]. From adfac00f458c7b68efb759335a804949d2f64d8b Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:19:03 +0800 Subject: [PATCH 10/34] `Result::and_then`: show type conversion --- library/core/src/result.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index d6a0c7dc29291..334a899078702 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1282,14 +1282,13 @@ impl Result { /// # Examples /// /// ``` - /// fn sq(x: u32) -> Result { - /// x.checked_mul(x).ok_or("overflowed") + /// fn sq_then_to_string(x: u32) -> Result { + /// x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed") /// } /// - /// assert_eq!(Ok(2).and_then(sq), Ok(4)); - /// assert_eq!(Ok(1_000_000).and_then(sq), Err("overflowed")); - /// assert_eq!(Err("not a number").and_then(sq), Err("not a number")); - + /// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string())); + /// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed")); + /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number")); /// ``` /// /// Often used to chain fallible operations that may return [`Err`]. From 160faf1b30d22b6a6958267e6f7bc3fb2b03754f Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:23:38 +0800 Subject: [PATCH 11/34] `Option::and_then` basic example: show failure --- library/core/src/option.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9fe38a505abb3..508837f63c3be 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1207,10 +1207,13 @@ impl Option { /// # Examples /// /// ``` - /// fn squared_string(x: u32) -> Option { Some((x * x).to_string()) } + /// fn sq_then_to_string(x: u32) -> Option { + /// x.checked_mul(x).map(|sq| sq.to_string()) + /// } /// - /// assert_eq!(Some(2).and_then(squared_string), Some(4.to_string())); - /// assert_eq!(None.and_then(squared_string), None); + /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string())); + /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed! + /// assert_eq!(None.and_then(sq_then_to_string), None); /// ``` /// /// Often used to chain fallible operations that may return [`None`]. From daa3c795dcf05b76b4b54778972e1059181b1f61 Mon Sep 17 00:00:00 2001 From: "yuhaixin.hx" Date: Sat, 12 Feb 2022 12:35:30 +0800 Subject: [PATCH 12/34] add link to format_args! when being mentioned in doc --- library/core/src/macros/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a9e90556f6c26..628b679236e1d 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -872,7 +872,7 @@ pub(crate) mod builtin { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } - /// Same as `format_args`, but can be used in some const contexts. + /// Same as [`format_args`], but can be used in some const contexts. /// /// This macro is used by the panic macros for the `const_panic` feature. /// @@ -886,7 +886,7 @@ pub(crate) mod builtin { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } - /// Same as `format_args`, but adds a newline in the end. + /// Same as [`format_args`], but adds a newline in the end. #[unstable( feature = "format_args_nl", issue = "none", From f6f93fd7ba348a4e0e2e9ca7af597d117d6337a1 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Sat, 12 Feb 2022 12:52:42 +0800 Subject: [PATCH 13/34] Add note on Windows path behaviour --- library/core/src/result.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 334a899078702..801e3a0b3a4cc 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1296,6 +1296,7 @@ impl Result { /// ``` /// use std::{io::ErrorKind, path::Path}; /// + /// // Note: on Windows "/" maps to "C:\" /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); /// assert!(root_modified_time.is_ok()); /// From 1b0dcdc341ea3659fd8d91ff85605069098ca34b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 3 Nov 2021 17:34:30 +0800 Subject: [PATCH 14/34] More informative error message for E0015 --- .../src/transform/check_consts/check.rs | 6 +- .../src/transform/check_consts/ops.rs | 94 ++++++++++--------- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 12a8b8c6d7790..ec96064222b57 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -797,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if let Some(trait_id) = tcx.trait_of_item(callee) { trace!("attempting to call a trait method"); if !self.tcx.features().const_trait_impl { - self.check_op(ops::FnCallNonConst(Some((callee, substs)))); + self.check_op(ops::FnCallNonConst(callee, substs)); return; } @@ -856,7 +856,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(None)); + self.check_op(ops::FnCallNonConst(callee, substs)); return; } } @@ -925,7 +925,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(None)); + self.check_op(ops::FnCallNonConst(callee, substs)); return; } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 24c4a4915e5e8..a6da3ebba6ef6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -74,65 +74,67 @@ impl NonConstOp for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug)] -pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>); +pub struct FnCallNonConst<'tcx>(pub DefId, pub SubstsRef<'tcx>); impl<'a> NonConstOp for FnCallNonConst<'a> { fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let FnCallNonConst(def_id, substs) = *self; let mut err = struct_span_err!( ccx.tcx.sess, span, E0015, + "cannot call non-const fn `{}` in {}s", + ccx.tcx.def_path_str_with_substs(def_id, substs), + ccx.const_kind() + ); + err.note(&format!( "calls in {}s are limited to constant functions, \ tuple structs and tuple variants", ccx.const_kind(), - ); - - if let FnCallNonConst(Some((callee, substs))) = *self { - if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() { - if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind( - ccx.tcx, - Ident::with_dummy_span(sym::eq), - AssocKind::Fn, - trait_def_id, - ) { - if callee == eq_item.def_id && substs.len() == 2 { - match (substs[0].unpack(), substs[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = - ccx.tcx.sess.source_map().span_to_snippet(span) - { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = call_str[(eq_idx + 2)..] - .find(|c: char| !c.is_whitespace()) - { - let rhs_pos = span.lo() - + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - err.multipart_suggestion( - "consider dereferencing here", - vec![ - (span.shrink_to_lo(), deref.clone()), - (rhs_span, deref), - ], - Applicability::MachineApplicable, - ); - } + )); + + if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() { + if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind( + ccx.tcx, + Ident::with_dummy_span(sym::eq), + AssocKind::Fn, + trait_def_id, + ) { + if callee == eq_item.def_id && substs.len() == 2 { + match (substs[0].unpack(), substs[1].unpack()) { + (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) + if self_ty == rhs_ty + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = + call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) + { + let rhs_pos = + span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + err.multipart_suggestion( + "consider dereferencing here", + vec![ + (span.shrink_to_lo(), deref.clone()), + (rhs_span, deref), + ], + Applicability::MachineApplicable, + ); } } } - _ => {} } + _ => {} } } } From f7f0f843b70f1b6c4ac9e22789d93d7bf5569dc3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 9 Dec 2021 22:42:17 +0800 Subject: [PATCH 15/34] Improve error messages even more --- .../src/diagnostics/conflict_errors.rs | 23 +- .../rustc_borrowck/src/diagnostics/mod.rs | 115 ++---- .../src/diagnostics/move_errors.rs | 6 +- .../src/transform/check_consts/check.rs | 30 +- .../src/transform/check_consts/ops.rs | 337 +++++++++++------- .../rustc_const_eval/src/util/call_kind.rs | 145 ++++++++ compiler/rustc_const_eval/src/util/mod.rs | 2 + compiler/rustc_hir/src/lang_items.rs | 11 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ops/try_trait.rs | 1 + 10 files changed, 433 insertions(+), 238 deletions(-) create mode 100644 compiler/rustc_const_eval/src/util/call_kind.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7b8b5974fe758..75913910f14c1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,4 +1,5 @@ use either::Either; +use rustc_const_eval::util::{CallDesugaringKind, CallKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -26,7 +27,7 @@ use crate::{ use super::{ explain_borrow::{BorrowExplanation, LaterUseKind}, - FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans, + IncludingDowncast, RegionName, RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -195,7 +196,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - FnSelfUseKind::FnOnceCall => { + CallKind::FnCall(once_did) if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => { err.span_label( fn_call_span, &format!( @@ -208,7 +209,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "this value implements `FnOnce`, which causes it to be moved when called", ); } - FnSelfUseKind::Operator { self_arg } => { + CallKind::Operator { self_arg, .. } => { + let self_arg = self_arg.unwrap(); err.span_label( fn_call_span, &format!( @@ -235,12 +237,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - FnSelfUseKind::Normal { - self_arg, - implicit_into_iter, - is_option_or_result, - } => { - if implicit_into_iter { + CallKind::Normal { self_arg, desugaring, is_option_or_result } => { + let self_arg = self_arg.unwrap(); + if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { err.span_label( fn_call_span, &format!( @@ -305,8 +304,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - // Deref::deref takes &self, which cannot cause a move - FnSelfUseKind::DerefCoercion { .. } => unreachable!(), + // Other desugarings takes &self, which cannot cause a move + _ => unreachable!(), } } else { err.span_label( @@ -433,7 +432,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if let UseSpans::FnSelfUse { - kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, + kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. }, .. } = use_spans { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 84acfbf941d05..4400fed13b741 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,10 +1,10 @@ //! Borrow checker diagnostics. +use rustc_const_eval::util::call_kind; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItemGroup; use rustc_hir::GeneratorKind; use rustc_middle::mir::{ AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, @@ -13,7 +13,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span}; +use rustc_span::{symbol::sym, Span}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -37,7 +37,7 @@ crate use mutability_errors::AccessKind; crate use outlives_suggestion::OutlivesSuggestionBuilder; crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; crate use region_name::{RegionName, RegionNameSource}; -use rustc_span::symbol::Ident; +crate use rustc_const_eval::util::CallKind; pub(super) struct IncludingDowncast(pub(super) bool); @@ -563,7 +563,7 @@ pub(super) enum UseSpans<'tcx> { fn_call_span: Span, /// The definition span of the method being called fn_span: Span, - kind: FnSelfUseKind<'tcx>, + kind: CallKind<'tcx>, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -571,38 +571,15 @@ pub(super) enum UseSpans<'tcx> { OtherUse(Span), } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind<'tcx> { - /// A normal method call of the form `receiver.foo(a, b, c)` - Normal { - self_arg: Ident, - implicit_into_iter: bool, - /// Whether the self type of the method call has an `.as_ref()` method. - /// Used for better diagnostics. - is_option_or_result: bool, - }, - /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` - FnOnceCall, - /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) - Operator { self_arg: Ident }, - DerefCoercion { - /// The `Span` of the `Target` associated type - /// in the `Deref` impl we are using. - deref_target: Span, - /// The type `T::Deref` we are dereferencing to - deref_target_ty: Ty<'tcx>, - }, -} - impl UseSpans<'_> { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, + UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { + fn_call_span + } UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -613,9 +590,9 @@ impl UseSpans<'_> { UseSpans::ClosureUse { path_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, + UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { + fn_call_span + } UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -626,9 +603,9 @@ impl UseSpans<'_> { UseSpans::ClosureUse { capture_kind_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { - fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. - } => fn_call_span, + UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { + fn_call_span + } UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -904,67 +881,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return normal_ret; }; - let tcx = self.infcx.tcx; - let parent = tcx.parent(method_did); - let is_fn_once = parent == tcx.lang_items().fn_once_trait(); - let is_operator = !from_hir_call - && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); - let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); - let fn_call_span = *fn_span; - - let self_arg = tcx.fn_arg_names(method_did)[0]; - - debug!( - "terminator = {:?} from_hir_call={:?}", - self.body[location.block].terminator, from_hir_call + let kind = call_kind( + self.infcx.tcx, + self.param_env, + method_did, + method_substs, + *fn_span, + *from_hir_call, + Some(self.infcx.tcx.fn_arg_names(method_did)[0]), ); - // Check for a 'special' use of 'self' - - // an FnOnce call, an operator (e.g. `<<`), or a - // deref coercion. - let kind = if is_fn_once { - Some(FnSelfUseKind::FnOnceCall) - } else if is_operator { - Some(FnSelfUseKind::Operator { self_arg }) - } else if is_deref { - let deref_target = - tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_substs) - .transpose() - }); - if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.param_env); - Some(FnSelfUseKind::DerefCoercion { - deref_target: tcx.def_span(instance.def_id()), - deref_target_ty, - }) - } else { - None - } - } else { - None - }; - - let kind = kind.unwrap_or_else(|| { - // This isn't a 'special' use of `self` - debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); - let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn() - && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop); - let parent_self_ty = parent - .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) - .and_then(|did| match tcx.type_of(did).kind() { - ty::Adt(def, ..) => Some(def.did), - _ => None, - }); - let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) - }); - FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } - }); - return FnSelfUse { var_span: stmt.source_info.span, - fn_call_span, + fn_call_span: *fn_span, fn_span: self .infcx .tcx diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 2934d921868a8..b33b779eddadd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,3 +1,4 @@ +use rustc_const_eval::util::CallDesugaringKind; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; @@ -8,7 +9,7 @@ use rustc_mir_dataflow::move_paths::{ use rustc_span::{sym, Span, DUMMY_SP}; use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; -use crate::diagnostics::{FnSelfUseKind, UseSpans}; +use crate::diagnostics::{CallKind, UseSpans}; use crate::prefixes::PrefixSet; use crate::MirBorrowckCtxt; @@ -410,7 +411,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } else if let Some(UseSpans::FnSelfUse { - kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. }, + kind: + CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. }, .. }) = use_spans { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index ec96064222b57..bd16a8853a624 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -293,13 +293,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { } /// Emits an error if an expression cannot be evaluated in the current context. - pub fn check_op(&mut self, op: impl NonConstOp) { + pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) { self.check_op_spanned(op, self.span); } /// Emits an error at the given `span` if an expression cannot be evaluated in the current /// context. - pub fn check_op_spanned(&mut self, op: O, span: Span) { + pub fn check_op_spanned>(&mut self, op: O, span: Span) { let gate = match op.status_in_item(self.ccx) { Status::Allowed => return, @@ -773,7 +773,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { + TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; let caller = self.def_id().to_def_id(); @@ -797,7 +797,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if let Some(trait_id) = tcx.trait_of_item(callee) { trace!("attempting to call a trait method"); if !self.tcx.features().const_trait_impl { - self.check_op(ops::FnCallNonConst(callee, substs)); + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); return; } @@ -856,7 +862,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(callee, substs)); + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); return; } } @@ -925,7 +937,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(callee, substs)); + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); return; } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index a6da3ebba6ef6..c26b1e550ba23 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -3,14 +3,20 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; +use rustc_middle::mir; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::{mir, ty::AssocKind}; +use rustc_middle::ty::{suggest_constraining_type_param, Adt, Param, TraitPredicate, Ty}; +use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{symbol::Ident, Span, Symbol}; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; +use crate::util::{call_kind, CallDesugaringKind, CallKind}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { @@ -29,9 +35,9 @@ pub enum DiagnosticImportance { } /// An operation that is not *always* allowed in a const context. -pub trait NonConstOp: std::fmt::Debug { +pub trait NonConstOp<'tcx>: std::fmt::Debug { /// Returns an enum indicating whether this operation is allowed within the given item. - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -39,13 +45,13 @@ pub trait NonConstOp: std::fmt::Debug { DiagnosticImportance::Primary } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; } #[derive(Debug)] pub struct FloatingPointOp; -impl NonConstOp for FloatingPointOp { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() == hir::ConstContext::ConstFn { Status::Unstable(sym::const_fn_floating_point_arithmetic) } else { @@ -53,7 +59,7 @@ impl NonConstOp for FloatingPointOp { } } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_floating_point_arithmetic, @@ -66,40 +72,120 @@ impl NonConstOp for FloatingPointOp { /// A function call where the callee is a pointer. #[derive(Debug)] pub struct FnCallIndirect; -impl NonConstOp for FnCallIndirect { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") } } /// A function call where the callee is not marked as `const`. -#[derive(Debug)] -pub struct FnCallNonConst<'tcx>(pub DefId, pub SubstsRef<'tcx>); -impl<'a> NonConstOp for FnCallNonConst<'a> { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - let FnCallNonConst(def_id, substs) = *self; - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(def_id, substs), - ccx.const_kind() - ); - err.note(&format!( - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - )); +#[derive(Debug, Clone, Copy)] +pub struct FnCallNonConst<'tcx> { + pub caller: DefId, + pub callee: DefId, + pub substs: SubstsRef<'tcx>, + pub span: Span, + pub from_hir_call: bool, +} - if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() { - if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind( - ccx.tcx, - Ident::with_dummy_span(sym::eq), - AssocKind::Fn, - trait_def_id, - ) { - if callee == eq_item.def_id && substs.len() == 2 { +impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> { + let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self; + let ConstCx { tcx, param_env, .. } = *ccx; + + let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| { + let trait_ref = TraitRef::from_method(tcx, trait_id, substs); + + match self_ty.kind() { + Param(param_ty) => { + debug!(?param_ty); + if let Some(generics) = caller + .as_local() + .map(|id| tcx.hir().local_def_id_to_hir_id(id)) + .map(|id| tcx.hir().get(id)) + .as_ref() + .and_then(|node| node.generics()) + { + let constraint = with_no_trimmed_paths(|| { + format!("~const {}", trait_ref.print_only_trait_path()) + }); + suggest_constraining_type_param( + tcx, + generics, + &mut err, + ¶m_ty.name.as_str(), + &constraint, + None, + ); + } + } + Adt(..) => { + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + Binder::dummy(TraitPredicate { + trait_ref, + constness: BoundConstness::ConstIfConst, + polarity: ImplPolarity::Positive, + }), + ); + + let implsrc = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + selcx.select(&obligation) + }); + + if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { + let span = + tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id)); + err.span_note(span, "impl defined here, but it is not `const`"); + } + } + _ => {} + } + + err + }; + + let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None); + + debug!(?call_kind); + + let mut err = match call_kind { + CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { + macro_rules! error { + ($fmt:literal) => { + struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind(),) + }; + } + + let err = match kind { + CallDesugaringKind::ForLoopIntoIter => { + error!("cannot convert `{}` into an iterator in {}s") + } + CallDesugaringKind::QuestionBranch => { + error!("`?` cannot determine the branch of `{}` in {}s") + } + CallDesugaringKind::QuestionFromResidual => { + error!("`?` cannot convert from residual of `{}` in {}s") + } + CallDesugaringKind::TryBlockFromOutput => { + error!("`try` block cannot convert `{}` to the result in {}s") + } + }; + + diag_trait(err, self_ty, kind.trait_def_id(tcx)) + } + CallKind::Operator { trait_id, self_ty, .. } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot call non-const operator in {}s", + ccx.const_kind() + ); + + if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { match (substs[0].unpack(), substs[1].unpack()) { (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) if self_ty == rhs_ty @@ -137,8 +223,43 @@ impl<'a> NonConstOp for FnCallNonConst<'a> { _ => {} } } + + diag_trait(err, self_ty, trait_id) } - } + CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot perform deref coercion on `{}` in {}s", + self_ty, + ccx.const_kind() + ); + + err.note(&format!("attempting to deref into `{}`", deref_target_ty)); + + // Check first whether the source is accessible (issue #87060) + if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + err.span_note(deref_target, "deref defined here"); + } + + diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap()) + } + _ => struct_span_err!( + ccx.tcx.sess, + span, + E0015, + "cannot call non-const fn `{}` in {}s", + ccx.tcx.def_path_str_with_substs(callee, substs), + ccx.const_kind(), + ), + }; + + err.note(&format!( + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + ccx.const_kind(), + )); err } @@ -150,8 +271,8 @@ impl<'a> NonConstOp for FnCallNonConst<'a> { #[derive(Debug)] pub struct FnCallUnstable(pub DefId, pub Option); -impl NonConstOp for FnCallUnstable { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let FnCallUnstable(def_id, feature) = *self; let mut err = ccx.tcx.sess.struct_span_err( @@ -176,8 +297,8 @@ impl NonConstOp for FnCallUnstable { #[derive(Debug)] pub struct FnPtrCast; -impl NonConstOp for FnPtrCast { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for FnPtrCast { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() != hir::ConstContext::ConstFn { Status::Allowed } else { @@ -185,7 +306,7 @@ impl NonConstOp for FnPtrCast { } } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_fn_ptr_basics, @@ -197,8 +318,8 @@ impl NonConstOp for FnPtrCast { #[derive(Debug)] pub struct Generator(pub hir::GeneratorKind); -impl NonConstOp for Generator { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for Generator { + fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { Status::Unstable(sym::const_async_blocks) } else { @@ -206,7 +327,7 @@ impl NonConstOp for Generator { } } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) @@ -218,8 +339,8 @@ impl NonConstOp for Generator { #[derive(Debug)] pub struct HeapAllocation; -impl NonConstOp for HeapAllocation { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for HeapAllocation { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -242,8 +363,8 @@ impl NonConstOp for HeapAllocation { #[derive(Debug)] pub struct InlineAsm; -impl NonConstOp for InlineAsm { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for InlineAsm { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { struct_span_err!( ccx.tcx.sess, span, @@ -258,8 +379,8 @@ impl NonConstOp for InlineAsm { pub struct LiveDrop { pub dropped_at: Option, } -impl NonConstOp for LiveDrop { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for LiveDrop { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -278,8 +399,8 @@ impl NonConstOp for LiveDrop { /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to /// the final value of the constant. pub struct TransientCellBorrow; -impl NonConstOp for TransientCellBorrow { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { + fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_refs_to_cell) } fn importance(&self) -> DiagnosticImportance { @@ -287,7 +408,7 @@ impl NonConstOp for TransientCellBorrow { // not additionally emit a feature gate error if activating the feature gate won't work. DiagnosticImportance::Secondary } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_refs_to_cell, @@ -302,8 +423,8 @@ impl NonConstOp for TransientCellBorrow { /// the final value of the constant, and thus we cannot allow this (for now). We may allow /// it in the future for static items. pub struct CellBorrow; -impl NonConstOp for CellBorrow { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for CellBorrow { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -339,8 +460,8 @@ impl NonConstOp for CellBorrow { /// static or const items. pub struct MutBorrow(pub hir::BorrowKind); -impl NonConstOp for MutBorrow { - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for MutBorrow { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -350,7 +471,7 @@ impl NonConstOp for MutBorrow { DiagnosticImportance::Secondary } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let raw = match self.0 { hir::BorrowKind::Raw => "raw ", hir::BorrowKind::Ref => "", @@ -384,12 +505,12 @@ impl NonConstOp for MutBorrow { #[derive(Debug)] pub struct TransientMutBorrow(pub hir::BorrowKind); -impl NonConstOp for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { + fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_mut_refs) } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let raw = match self.0 { hir::BorrowKind::Raw => "raw ", hir::BorrowKind::Ref => "", @@ -406,8 +527,8 @@ impl NonConstOp for TransientMutBorrow { #[derive(Debug)] pub struct MutDeref; -impl NonConstOp for MutDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for MutDeref { + fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_mut_refs) } @@ -416,7 +537,7 @@ impl NonConstOp for MutDeref { DiagnosticImportance::Secondary } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -429,8 +550,8 @@ impl NonConstOp for MutDeref { /// A call to a `panic()` lang item where the first argument is _not_ a `&str`. #[derive(Debug)] pub struct PanicNonStr; -impl NonConstOp for PanicNonStr { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for PanicNonStr { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx.sess.struct_span_err( span, "argument to `panic!()` in a const context must have type `&str`", @@ -443,8 +564,8 @@ impl NonConstOp for PanicNonStr { /// allocation base addresses that are not known at compile-time. #[derive(Debug)] pub struct RawPtrComparison; -impl NonConstOp for RawPtrComparison { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = ccx .tcx .sess @@ -459,12 +580,12 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawMutPtrDeref; -impl NonConstOp for RawMutPtrDeref { +impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { Status::Unstable(sym::const_mut_refs) } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -479,8 +600,8 @@ impl NonConstOp for RawMutPtrDeref { /// allocation base addresses that are not known at compile-time. #[derive(Debug)] pub struct RawPtrToIntCast; -impl NonConstOp for RawPtrToIntCast { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = ccx .tcx .sess @@ -496,8 +617,8 @@ impl NonConstOp for RawPtrToIntCast { /// An access to a (non-thread-local) `static`. #[derive(Debug)] pub struct StaticAccess; -impl NonConstOp for StaticAccess { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { +impl<'tcx> NonConstOp<'tcx> for StaticAccess { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if let hir::ConstContext::Static(_) = ccx.const_kind() { Status::Allowed } else { @@ -505,7 +626,7 @@ impl NonConstOp for StaticAccess { } } - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -530,8 +651,8 @@ impl NonConstOp for StaticAccess { /// An access to a thread-local `static`. #[derive(Debug)] pub struct ThreadLocalAccess; -impl NonConstOp for ThreadLocalAccess { - fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { +impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { struct_span_err!( ccx.tcx.sess, span, @@ -548,8 +669,8 @@ pub mod ty { #[derive(Debug)] pub struct MutRef(pub mir::LocalKind); - impl NonConstOp for MutRef { - fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + impl<'tcx> NonConstOp<'tcx> for MutRef { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_mut_refs) } @@ -562,11 +683,7 @@ pub mod ty { } } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -578,7 +695,7 @@ pub mod ty { #[derive(Debug)] pub struct FnPtr(pub mir::LocalKind); - impl NonConstOp for FnPtr { + impl<'tcx> NonConstOp<'tcx> for FnPtr { fn importance(&self) -> DiagnosticImportance { match self.0 { mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, @@ -588,7 +705,7 @@ pub mod ty { } } - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() != hir::ConstContext::ConstFn { Status::Allowed } else { @@ -596,11 +713,7 @@ pub mod ty { } } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_fn_ptr_basics, @@ -612,16 +725,12 @@ pub mod ty { #[derive(Debug)] pub struct ImplTrait; - impl NonConstOp for ImplTrait { + impl<'tcx> NonConstOp<'tcx> for ImplTrait { fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { Status::Unstable(sym::const_impl_trait) } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_impl_trait, @@ -633,7 +742,7 @@ pub mod ty { #[derive(Debug)] pub struct TraitBound(pub mir::LocalKind); - impl NonConstOp for TraitBound { + impl<'tcx> NonConstOp<'tcx> for TraitBound { fn importance(&self) -> DiagnosticImportance { match self.0 { mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, @@ -643,7 +752,7 @@ pub mod ty { } } - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() != hir::ConstContext::ConstFn { Status::Allowed } else { @@ -651,11 +760,7 @@ pub mod ty { } } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_trait_bound, @@ -676,7 +781,7 @@ pub mod ty { #[derive(Debug)] pub struct DynTrait(pub mir::LocalKind); - impl NonConstOp for DynTrait { + impl<'tcx> NonConstOp<'tcx> for DynTrait { fn importance(&self) -> DiagnosticImportance { match self.0 { mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, @@ -686,7 +791,7 @@ pub mod ty { } } - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { if ccx.const_kind() != hir::ConstContext::ConstFn { Status::Allowed } else { @@ -694,11 +799,7 @@ pub mod ty { } } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_trait_bound, @@ -720,16 +821,12 @@ pub mod ty { /// A trait bound with the `?const Trait` opt-out #[derive(Debug)] pub struct TraitBoundNotConst; - impl NonConstOp for TraitBoundNotConst { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst { + fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_trait_bound_opt_out) } - fn build_error<'tcx>( - &self, - ccx: &ConstCx<'_, 'tcx>, - span: Span, - ) -> DiagnosticBuilder<'tcx> { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_trait_bound_opt_out, diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs new file mode 100644 index 0000000000000..34925692664be --- /dev/null +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -0,0 +1,145 @@ +//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`, +//! as well as errors when attempting to call a non-const function in a const +//! context. + +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItemGroup; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, DesugaringKind, Span}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CallDesugaringKind { + /// for _ in x {} calls x.into_iter() + ForLoopIntoIter, + /// x? calls x.branch() + QuestionBranch, + /// x? calls type_of(x)::from_residual() + QuestionFromResidual, + /// try { ..; x } calls type_of(x)::from_output(x) + TryBlockFromOutput, +} + +impl CallDesugaringKind { + pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { + match self { + Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), + Self::QuestionBranch | Self::TryBlockFromOutput => { + tcx.lang_items().try_trait().unwrap() + } + Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CallKind<'tcx> { + /// A normal method call of the form `receiver.foo(a, b, c)` + Normal { + self_arg: Option, + desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>, + /// Whether the self type of the method call has an `.as_ref()` method. + /// Used for better diagnostics. + is_option_or_result: bool, + }, + /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` + FnCall(DefId), + /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) + Operator { self_arg: Option, trait_id: DefId, self_ty: Ty<'tcx> }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + }, +} + +pub fn call_kind<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + method_did: DefId, + method_substs: SubstsRef<'tcx>, + fn_call_span: Span, + from_hir_call: bool, + self_arg: Option, +) -> CallKind<'tcx> { + let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container { + AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did), + AssocItemContainer::TraitContainer(trait_did) => Some(trait_did), + }); + + let fn_call = (!from_hir_call) + .then(|| parent) + .flatten() + .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p)); + + let operator = (!from_hir_call) + .then(|| parent) + .flatten() + .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p)); + + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. + let kind = if let Some(&trait_id) = fn_call { + Some(CallKind::FnCall(trait_id)) + } else if let Some(&trait_id) = operator { + Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) + } else if is_deref { + let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, param_env, deref_target, method_substs).transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, param_env); + Some(CallKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + self_ty: method_substs.type_at(0), + }) + } else { + None + } + } else { + None + }; + + kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` + debug!(?method_did, ?fn_call_span); + let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) + { + Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0))) + } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { + if Some(method_did) == tcx.lang_items().branch_fn() { + Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0))) + } else if Some(method_did) == tcx.lang_items().from_residual_fn() { + Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0))) + } else { + None + } + } else if Some(method_did) == tcx.lang_items().from_output_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) + { + Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0))) + } else { + None + }; + let parent_self_ty = tcx + .parent(method_did) + .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) + .and_then(|did| match tcx.type_of(did).kind() { + ty::Adt(def, ..) => Some(def.did), + _ => None, + }); + let is_option_or_result = parent_self_ty.map_or(false, |def_id| { + matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) + }); + CallKind::Normal { self_arg, desugaring, is_option_or_result } + }) +} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 4a406f8bfd088..a1876bed83eca 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,8 +1,10 @@ pub mod aggregate; mod alignment; +mod call_kind; pub mod collect_writes; mod find_self_call; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; +pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; pub use self::find_self_call::find_self_call; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 603971a6a9161..3e0bc2e58fc4c 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -21,6 +21,7 @@ use std::lazy::SyncLazy; pub enum LangItemGroup { Op, + Fn, } const NUM_GROUPS: usize = 1; @@ -251,9 +252,9 @@ language_item_table! { DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; - Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); - FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); - FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); + FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; @@ -264,8 +265,8 @@ language_item_table! { Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; - PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); - PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); + PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); + PartialOrd(Op), sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cab1d4e21c9b5..2e45150226366 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -184,6 +184,7 @@ symbols! { Formatter, From, FromIterator, + FromResidual, Future, FxHashMap, FxHashSet, diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index eac426ad31164..ba369e7f3aaa0 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -302,6 +302,7 @@ pub trait Try: FromResidual { enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), )] +#[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual::Residual> { /// Constructs the type from a compatible `Residual` type. From b5235ea732dcb517338eaf2e35fda8ddcf515771 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 10 Dec 2021 01:10:05 +0800 Subject: [PATCH 16/34] bless you --- src/test/ui/borrowck/issue-64453.rs | 2 +- src/test/ui/borrowck/issue-64453.stderr | 3 ++- src/test/ui/check-static-values-constraints.rs | 2 +- .../ui/check-static-values-constraints.stderr | 8 +++++--- .../ui/const-generics/nested-type.full.stderr | 4 +++- .../ui/const-generics/nested-type.min.stderr | 4 +++- src/test/ui/const-generics/nested-type.rs | 2 +- src/test/ui/consts/const-call.rs | 2 +- src/test/ui/consts/const-call.stderr | 4 +++- .../const-extern-fn-call-extern-fn.rs | 4 ++-- .../const-extern-fn-call-extern-fn.stderr | 8 ++++++-- src/test/ui/consts/const-fn-error.rs | 5 +++-- src/test/ui/consts/const-fn-error.stderr | 13 +++++++++++-- .../ui/consts/const-fn-not-safe-for-const.stderr | 4 +++- src/test/ui/consts/const-for.rs | 4 ++-- src/test/ui/consts/const-for.stderr | 13 +++++++++++-- src/test/ui/consts/control-flow/issue-46843.rs | 2 +- .../ui/consts/control-flow/issue-46843.stderr | 4 +++- .../ui/consts/intrinsic_without_const_stab.rs | 2 +- .../consts/intrinsic_without_const_stab.stderr | 4 +++- .../consts/intrinsic_without_const_stab_fail.rs | 2 +- .../intrinsic_without_const_stab_fail.stderr | 4 +++- src/test/ui/consts/issue-28113.rs | 2 +- src/test/ui/consts/issue-28113.stderr | 4 +++- src/test/ui/consts/issue-32829-2.rs | 6 +++--- src/test/ui/consts/issue-32829-2.stderr | 12 +++++++++--- src/test/ui/consts/issue-43105.rs | 2 +- src/test/ui/consts/issue-43105.stderr | 4 +++- src/test/ui/consts/issue-56164.rs | 2 +- src/test/ui/consts/issue-56164.stderr | 4 +++- .../consts/issue-68542-closure-in-array-len.rs | 2 +- .../issue-68542-closure-in-array-len.stderr | 4 +++- .../consts/min_const_fn/bad_const_fn_body_ice.rs | 2 +- .../min_const_fn/bad_const_fn_body_ice.stderr | 3 ++- src/test/ui/consts/mir_check_nonconst.rs | 2 +- src/test/ui/consts/mir_check_nonconst.stderr | 4 +++- .../consts/unstable-const-fn-in-libcore.stderr | 4 +++- src/test/ui/issues/issue-16538.mir.stderr | 4 +++- src/test/ui/issues/issue-16538.thir.stderr | 4 +++- src/test/ui/issues/issue-25901.rs | 2 +- src/test/ui/issues/issue-25901.stderr | 15 ++++++++++++++- src/test/ui/issues/issue-39559-2.stderr | 8 ++++++-- src/test/ui/never_type/issue-52443.rs | 4 ++-- src/test/ui/never_type/issue-52443.stderr | 13 +++++++++++-- .../call-const-trait-method-fail.rs | 2 +- .../call-const-trait-method-fail.stderr | 8 +++++--- .../call-generic-method-fail.rs | 2 +- .../call-generic-method-fail.stderr | 8 +++++++- .../const-check-fns-in-const-impl.rs | 2 +- .../const-check-fns-in-const-impl.stderr | 4 +++- .../const-default-method-bodies.rs | 2 +- .../const-default-method-bodies.stderr | 8 +++++--- .../cross-crate.gated.stderr | 8 +++++--- .../ui/rfc-2632-const-trait-impl/cross-crate.rs | 4 ++-- .../cross-crate.stock.stderr | 16 ++++++++++------ .../ui/rfc-2632-const-trait-impl/issue-88155.rs | 2 +- .../rfc-2632-const-trait-impl/issue-88155.stderr | 4 +++- .../rfc-2632-const-trait-impl/std-impl-gate.rs | 2 +- .../std-impl-gate.stock.stderr | 4 +++- .../static/static-vec-repeat-not-constant.stderr | 4 +++- 60 files changed, 200 insertions(+), 87 deletions(-) diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 9e70a847457c0..33d55be5812e7 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -2,7 +2,7 @@ struct Project; struct Value; static settings_dir: String = format!(""); -//~^ ERROR calls in statics are limited to constant functions +//~^ ERROR cannot call non-const fn //~| ERROR is not yet stable as a const fn from_string(_: String) -> Value { diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 14e1667038965..f3436fbec66a6 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -7,12 +7,13 @@ LL | static settings_dir: String = format!(""); = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `format` in statics --> $DIR/issue-64453.rs:4:31 | LL | static settings_dir: String = format!(""); | ^^^^^^^^^^^ | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `settings_dir` diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs index 3d1b5a0822756..eb4ecd8baca96 100644 --- a/src/test/ui/check-static-values-constraints.rs +++ b/src/test/ui/check-static-values-constraints.rs @@ -87,7 +87,7 @@ static mut STATIC13: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, static mut STATIC14: SafeStruct = SafeStruct { field1: SafeEnum::Variant1, field2: SafeEnum::Variant4("str".to_string()) -//~^ ERROR calls in statics are limited to constant functions +//~^ ERROR cannot call non-const fn }; static STATIC15: &'static [Box] = &[ diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index eb640c88e026f..b28cf0d6bd0f5 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -15,11 +15,13 @@ error[E0010]: allocations are not allowed in statics LL | static STATIC11: Box = box MyOwned; | ^^^^^^^^^^^ allocation not allowed in statics -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/check-static-values-constraints.rs:89:32 +error[E0015]: cannot call non-const fn `::to_string` in statics + --> $DIR/check-static-values-constraints.rs:89:38 | LL | field2: SafeEnum::Variant4("str".to_string()) - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:94:5 diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 9d7ca36545c9c..52f1c58825823 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants --> $DIR/nested-type.rs:15:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 4f32284ecb1e0..0e3c988ae4d8c 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -14,11 +14,13 @@ LL | | }]>; = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants --> $DIR/nested-type.rs:15:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs index 039f996de96db..5240f5c3b0b64 100644 --- a/src/test/ui/const-generics/nested-type.rs +++ b/src/test/ui/const-generics/nested-type.rs @@ -13,7 +13,7 @@ struct Foo::value() - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR cannot call non-const fn }]>; fn main() {} diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index db642988971e0..28e89559fe538 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -4,5 +4,5 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR cannot call non-const fn } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index 9761348bab824..e46bcad0e1d0e 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `f` in constants --> $DIR/const-call.rs:6:17 | LL | let _ = [0; f(2)]; | ^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index ee07dfae47c38..eccda49db3eb5 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -7,7 +7,7 @@ extern "C" { const extern "C" fn bar() { unsafe { regular_in_block(); - //~^ ERROR: calls in constant functions + //~^ ERROR: cannot call non-const fn } } @@ -16,7 +16,7 @@ extern "C" fn regular() {} const extern "C" fn foo() { unsafe { regular(); - //~^ ERROR: calls in constant functions + //~^ ERROR: cannot call non-const fn } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index 348387ff5f827..5acf22e4bc66e 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,14 +1,18 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `regular_in_block` in constant functions --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `regular` in constant functions --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs index 065944ea7eaad..0b813e65621d3 100644 --- a/src/test/ui/consts/const-fn-error.rs +++ b/src/test/ui/consts/const-fn-error.rs @@ -4,8 +4,9 @@ const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { //~^ ERROR mutable references - //~| ERROR calls in constant functions - //~| ERROR calls in constant functions + //~| ERROR cannot convert + //~| ERROR cannot call non-const fn + //~| ERROR E0080 //~| ERROR `for` is not allowed in a `const fn` sum += i; } diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index e4b62f20a3318..4d53cfc35e1c4 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -13,11 +13,18 @@ LL | | } = note: see issue #87575 for more information = help: add `#![feature(const_for)]` to the crate attributes to enable -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot convert `std::ops::Range` into an iterator in constant functions --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | impl IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constant functions --> $DIR/const-fn-error.rs:5:14 @@ -28,11 +35,13 @@ LL | for i in 0..x { = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn ` as Iterator>::next` in constant functions --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr index df793d7dd7ec9..4c7effc0d1586 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr +++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `random` in constant functions --> $DIR/const-fn-not-safe-for-const.rs:14:5 | LL | random() | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0013]: constant functions cannot refer to statics --> $DIR/const-fn-not-safe-for-const.rs:20:5 diff --git a/src/test/ui/consts/const-for.rs b/src/test/ui/consts/const-for.rs index 5fc1ee0e36948..58bcb5f74ccf6 100644 --- a/src/test/ui/consts/const-for.rs +++ b/src/test/ui/consts/const-for.rs @@ -3,8 +3,8 @@ const _: () = { for _ in 0..5 {} - //~^ error: calls in constants are limited to - //~| error: calls in constants are limited to + //~^ error: cannot convert + //~| error: cannot call non-const fn }; fn main() {} diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr index a35c04b3570b2..b0dc43eb8e850 100644 --- a/src/test/ui/consts/const-for.stderr +++ b/src/test/ui/consts/const-for.stderr @@ -1,14 +1,23 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot convert `std::ops::Range` into an iterator in constants --> $DIR/const-for.rs:5:14 | LL | for _ in 0..5 {} | ^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | impl IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/const-for.rs:5:14 | LL | for _ in 0..5 {} | ^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/control-flow/issue-46843.rs b/src/test/ui/consts/control-flow/issue-46843.rs index edf62f2326619..ddddc8505c635 100644 --- a/src/test/ui/consts/control-flow/issue-46843.rs +++ b/src/test/ui/consts/control-flow/issue-46843.rs @@ -8,7 +8,7 @@ fn non_const() -> Thing { } pub const Q: i32 = match non_const() { - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR cannot call non-const fn Thing::This => 1, Thing::That => 0 }; diff --git a/src/test/ui/consts/control-flow/issue-46843.stderr b/src/test/ui/consts/control-flow/issue-46843.stderr index ea9ea25f9e12d..66227f61e3563 100644 --- a/src/test/ui/consts/control-flow/issue-46843.stderr +++ b/src/test/ui/consts/control-flow/issue-46843.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `non_const` in constants --> $DIR/issue-46843.rs:10:26 | LL | pub const Q: i32 = match non_const() { | ^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs index 810158a295792..d5f694986fc89 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab.rs +++ b/src/test/ui/consts/intrinsic_without_const_stab.rs @@ -11,7 +11,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { } unsafe { copy(src, dst, count) } - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr index 5a42823a6052a..b32b6398ece62 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab.stderr +++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `copy::copy::` in constant functions --> $DIR/intrinsic_without_const_stab.rs:13:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs index bf2c44169d48b..8b37268b0b205 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs @@ -9,7 +9,7 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] #[inline] pub const unsafe fn stuff(src: *const T, dst: *mut T, count: usize) { - unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited + unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr index d4a2989e785e0..fcbb3724567fe 100644 --- a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr +++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `copy::` in constant functions --> $DIR/intrinsic_without_const_stab_fail.rs:12:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/issue-28113.rs b/src/test/ui/consts/issue-28113.rs index e5bd7aafe41e6..1d93d454af786 100644 --- a/src/test/ui/consts/issue-28113.rs +++ b/src/test/ui/consts/issue-28113.rs @@ -2,7 +2,7 @@ const X: u8 = || -> u8 { 5 }() - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR cannot call non-const fn ; fn main() {} diff --git a/src/test/ui/consts/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr index 3d274d777b0c7..75fcc010a04f9 100644 --- a/src/test/ui/consts/issue-28113.stderr +++ b/src/test/ui/consts/issue-28113.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-28113.rs:4:5: 4:19] as Fn<()>>::call` in constants --> $DIR/issue-28113.rs:4:5 | LL | || -> u8 { 5 }() | ^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/issue-32829-2.rs b/src/test/ui/consts/issue-32829-2.rs index e0fcf27833096..d70b5a8c4e13a 100644 --- a/src/test/ui/consts/issue-32829-2.rs +++ b/src/test/ui/consts/issue-32829-2.rs @@ -8,7 +8,7 @@ const bad : u32 = { const bad_two : u32 = { { invalid(); - //~^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants + //~^ ERROR: cannot call non-const fn `invalid` 0 } }; @@ -30,7 +30,7 @@ static bad_four : u32 = { static bad_five : u32 = { { invalid(); - //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants + //~^ ERROR: cannot call non-const fn `invalid` 0 } }; @@ -52,7 +52,7 @@ static mut bad_seven : u32 = { static mut bad_eight : u32 = { { invalid(); - //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants + //~^ ERROR: cannot call non-const fn `invalid` 0 } }; diff --git a/src/test/ui/consts/issue-32829-2.stderr b/src/test/ui/consts/issue-32829-2.stderr index 1d265875c5c97..b94bdc0e3df11 100644 --- a/src/test/ui/consts/issue-32829-2.stderr +++ b/src/test/ui/consts/issue-32829-2.stderr @@ -1,20 +1,26 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `invalid` in constants --> $DIR/issue-32829-2.rs:10:9 | LL | invalid(); | ^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `invalid` in statics --> $DIR/issue-32829-2.rs:32:9 | LL | invalid(); | ^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `invalid` in statics --> $DIR/issue-32829-2.rs:54:9 | LL | invalid(); | ^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/issue-43105.rs b/src/test/ui/consts/issue-43105.rs index cc6a485085372..cac12b90970fe 100644 --- a/src/test/ui/consts/issue-43105.rs +++ b/src/test/ui/consts/issue-43105.rs @@ -1,7 +1,7 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); -//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants +//~^ ERROR cannot call non-const fn fn main() { match 1 { diff --git a/src/test/ui/consts/issue-43105.stderr b/src/test/ui/consts/issue-43105.stderr index e508cbdd1dd53..2d1174af71c86 100644 --- a/src/test/ui/consts/issue-43105.stderr +++ b/src/test/ui/consts/issue-43105.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `xyz` in constants --> $DIR/issue-43105.rs:3:17 | LL | const NUM: u8 = xyz(); | ^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: could not evaluate constant pattern --> $DIR/issue-43105.rs:8:9 diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs index 90ea217698d65..af65720916cd9 100644 --- a/src/test/ui/consts/issue-56164.rs +++ b/src/test/ui/consts/issue-56164.rs @@ -1,7 +1,7 @@ #![feature(const_fn_fn_ptr_basics)] const fn foo() { (||{})() } -//~^ ERROR calls in constant functions +//~^ ERROR cannot call non-const fn const fn bad(input: fn()) { input() diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index 500af0a40069a..af5d44d4814bf 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-56164.rs:3:18: 3:24] as Fn<()>>::call` in constant functions --> $DIR/issue-56164.rs:3:18 | LL | const fn foo() { (||{})() } | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: function pointers are not allowed in const fn --> $DIR/issue-56164.rs:7:5 diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.rs b/src/test/ui/consts/issue-68542-closure-in-array-len.rs index d77fd9aa831be..44f44da234a7c 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.rs +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.rs @@ -3,7 +3,7 @@ // in the length part of an array. struct Bug { - a: [(); (|| { 0 })()] //~ ERROR calls in constants are limited to + a: [(); (|| { 0 })()] //~ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 74d70e18a24cb..3787138afc37f 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-68542-closure-in-array-len.rs:6:13: 6:23] as Fn<()>>::call` in constants --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] | ^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 4e1b7bf119c6d..258997597ea9d 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,7 +1,7 @@ const fn foo(a: i32) -> Vec { vec![1, 2, 3] //~^ ERROR allocations are not allowed - //~| ERROR calls in constant functions + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index fee43864e20dc..74234108911dd 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -6,12 +6,13 @@ LL | vec![1, 2, 3] | = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `slice::::into_vec::` in constant functions --> $DIR/bad_const_fn_body_ice.rs:2:5 | LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/mir_check_nonconst.rs b/src/test/ui/consts/mir_check_nonconst.rs index b8ec0c3c449ff..b6f34b922fae5 100644 --- a/src/test/ui/consts/mir_check_nonconst.rs +++ b/src/test/ui/consts/mir_check_nonconst.rs @@ -6,6 +6,6 @@ fn bar() -> Foo { } static foo: Foo = bar(); -//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants +//~^ ERROR cannot call non-const fn fn main() {} diff --git a/src/test/ui/consts/mir_check_nonconst.stderr b/src/test/ui/consts/mir_check_nonconst.stderr index 30f68ba43722d..2bac995eebf09 100644 --- a/src/test/ui/consts/mir_check_nonconst.stderr +++ b/src/test/ui/consts/mir_check_nonconst.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `bar` in statics --> $DIR/mir_check_nonconst.rs:8:19 | LL | static foo: Foo = bar(); | ^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index 928605356a16e..435141134cb88 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `>::call_once` in constant functions --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:53 diff --git a/src/test/ui/issues/issue-16538.mir.stderr b/src/test/ui/issues/issue-16538.mir.stderr index 5a276f27886d2..60a2bf1e2d660 100644 --- a/src/test/ui/issues/issue-16538.mir.stderr +++ b/src/test/ui/issues/issue-16538.mir.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `Y::foo` in statics --> $DIR/issue-16538.rs:15:23 | LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-16538.rs:15:30 diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr index 8365a1dbf6e5e..2ba9dfa2bc5f8 100644 --- a/src/test/ui/issues/issue-16538.thir.stderr +++ b/src/test/ui/issues/issue-16538.thir.stderr @@ -14,11 +14,13 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `Y::foo` in statics --> $DIR/issue-16538.rs:15:23 | LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-25901.rs b/src/test/ui/issues/issue-25901.rs index a139ad0d3e323..ba12e1ad0211b 100644 --- a/src/test/ui/issues/issue-25901.rs +++ b/src/test/ui/issues/issue-25901.rs @@ -2,7 +2,7 @@ struct A; struct B; static S: &'static B = &A; -//~^ ERROR calls in statics are limited to constant functions +//~^ ERROR cannot perform deref coercion on `A` in statics use std::ops::Deref; diff --git a/src/test/ui/issues/issue-25901.stderr b/src/test/ui/issues/issue-25901.stderr index d6eb3760cdf40..5c35250bc3f39 100644 --- a/src/test/ui/issues/issue-25901.stderr +++ b/src/test/ui/issues/issue-25901.stderr @@ -1,8 +1,21 @@ -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot perform deref coercion on `A` in statics --> $DIR/issue-25901.rs:4:24 | LL | static S: &'static B = &A; | ^^ + | + = note: attempting to deref into `B` +note: deref defined here + --> $DIR/issue-25901.rs:10:5 + | +LL | type Target = B; + | ^^^^^^^^^^^^^^^^ +note: impl defined here, but it is not `const` + --> $DIR/issue-25901.rs:9:1 + | +LL | impl Deref for A { + | ^^^^^^^^^^^^^^^^ + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 3d765daa7cdef..ea27e7bd2508f 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -1,14 +1,18 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `::dim` in constants --> $DIR/issue-39559-2.rs:14:24 | LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `::dim` in constants --> $DIR/issue-39559-2.rs:16:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/never_type/issue-52443.rs b/src/test/ui/never_type/issue-52443.rs index 4519833b86486..cebcca944af82 100644 --- a/src/test/ui/never_type/issue-52443.rs +++ b/src/test/ui/never_type/issue-52443.rs @@ -8,7 +8,7 @@ fn main() { [(); { for _ in 0usize.. {}; 0}]; //~^ ERROR `for` is not allowed in a `const` - //~| ERROR calls in constants are limited to constant functions + //~| ERROR cannot convert //~| ERROR mutable references are not allowed in constants - //~| ERROR calls in constants are limited to constant functions + //~| ERROR cannot call non-const fn } diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 216b56f705904..8c1755205f025 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -38,11 +38,18 @@ LL | [(); loop { break }]; | expected `usize`, found `()` | help: give it a value of the expected type: `break 42` -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot convert `RangeFrom` into an iterator in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | impl IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constants --> $DIR/issue-52443.rs:9:21 @@ -53,11 +60,13 @@ LL | [(); { for _ in 0usize.. {}; 0}]; = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/issue-52443.rs:9:21 | LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index 33e839fd1203d..5f55d61f5fdcd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -22,7 +22,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 { pub const fn add_u32(a: u32, b: u32) -> u32 { a.plus(b) - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 5a73c4debb481..b5680c04a65a3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/call-const-trait-method-fail.rs:24:5 +error[E0015]: cannot call non-const fn `::plus` in constant functions + --> $DIR/call-const-trait-method-fail.rs:24:7 | LL | a.plus(b) - | ^^^^^^^^^ + | ^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs index e96249ff2fd5a..e3de75ea51943 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -3,7 +3,7 @@ pub const fn equals_self(t: &T) -> bool { *t == *t - //~^ ERROR calls in constant functions are limited to constant functions + //~^ ERROR cannot call non-const operator } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index 818c582869631..d50100d033e51 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -1,8 +1,14 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constant functions --> $DIR/call-generic-method-fail.rs:5:5 | LL | *t == *t | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | pub const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3a7074163523b..b3e3dd62be804 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -9,7 +9,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR calls in constant functions + //~^ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index aaec67161a6af..9e49785c589e1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `non_const` in constant functions --> $DIR/const-check-fns-in-const-impl.rs:11:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 7a0db9c98ea61..4b685b3b2b75a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -23,7 +23,7 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); - //~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants + //~^ ERROR cannot call non-const fn ConstImpl.a(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 63e4095af2943..853fa3d64781f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/const-default-method-bodies.rs:25:5 +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/const-default-method-bodies.rs:25:18 | LL | NonConstImpl.a(); - | ^^^^^^^^^^^^^^^^ + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr index 3f553a8ee7079..df960902133f3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/cross-crate.rs:15:5 +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs index 4bd3359947d94..670d06b85f281 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs @@ -13,9 +13,9 @@ fn non_const_context() { const fn const_context() { NonConst.func(); - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants + //~^ ERROR: cannot call non-const fn Const.func(); - //[stock]~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants + //[stock]~^ ERROR: cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr index 9908f47a7b288..ea75ad0aeaf8c 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -1,14 +1,18 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/cross-crate.rs:15:5 +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:15:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/cross-crate.rs:17:5 +error[E0015]: cannot call non-const fn `::func` in constant functions + --> $DIR/cross-crate.rs:17:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs index 157005bba7b75..e4fc65e3cb353 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs @@ -7,7 +7,7 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //~^ ERROR calls in constant functions are limited + //~^ ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr index 931baac5389e6..b94d655a9ffa2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `::assoc` in constant functions --> $DIR/issue-88155.rs:9:5 | LL | T::assoc() | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs index c6975da7121f9..2f54c09e31c9e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs @@ -11,7 +11,7 @@ fn non_const_context() -> Vec { const fn const_context() -> Vec { Default::default() - //[stock]~^ ERROR calls in constant functions are limited + //[stock]~^ ERROR cannot call non-const fn } fn main() { diff --git a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr index 55a0daaaec7bd..0b450a9474282 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn ` as Default>::default` in constant functions --> $DIR/std-impl-gate.rs:13:5 | LL | Default::default() | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/static/static-vec-repeat-not-constant.stderr b/src/test/ui/static/static-vec-repeat-not-constant.stderr index ef98aa546ebdd..84fc638a973cb 100644 --- a/src/test/ui/static/static-vec-repeat-not-constant.stderr +++ b/src/test/ui/static/static-vec-repeat-not-constant.stderr @@ -1,8 +1,10 @@ -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const fn `foo` in statics --> $DIR/static-vec-repeat-not-constant.rs:3:25 | LL | static a: [isize; 2] = [foo(); 2]; | ^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error From 6d6314f878bf489e15293498ecb4af082c8d53d8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 16:29:14 +0800 Subject: [PATCH 17/34] Rebased and improved errors --- .../src/diagnostics/conflict_errors.rs | 4 +++- .../src/transform/check_consts/ops.rs | 2 +- .../rustc_const_eval/src/util/call_kind.rs | 4 +--- compiler/rustc_hir/src/lang_items.rs | 5 +++-- .../ui/const-generics/issues/issue-90318.rs | 4 ++-- .../const-generics/issues/issue-90318.stderr | 20 +++++++++++++++++-- src/test/ui/consts/issue-90870.fixed | 6 +++--- src/test/ui/consts/issue-90870.rs | 6 +++--- src/test/ui/consts/issue-90870.stderr | 9 ++++++--- 9 files changed, 40 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 75913910f14c1..ff1d37bfccb76 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -196,7 +196,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - CallKind::FnCall(once_did) if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => { + CallKind::FnCall(once_did) + if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => + { err.span_label( fn_call_span, &format!( diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c26b1e550ba23..237201c547822 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -125,7 +125,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { param_env, Binder::dummy(TraitPredicate { trait_ref, - constness: BoundConstness::ConstIfConst, + constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, }), ); diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index 34925692664be..fe35d94234139 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -71,9 +71,7 @@ pub fn call_kind<'tcx>( AssocItemContainer::TraitContainer(trait_did) => Some(trait_did), }); - let fn_call = (!from_hir_call) - .then(|| parent) - .flatten() + let fn_call = parent .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p)); let operator = (!from_hir_call) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3e0bc2e58fc4c..b299e71c9c4c4 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -24,7 +24,7 @@ pub enum LangItemGroup { Fn, } -const NUM_GROUPS: usize = 1; +const NUM_GROUPS: usize = 2; macro_rules! expand_group { () => { @@ -99,11 +99,12 @@ macro_rules! language_item_table { /// Construct an empty collection of lang items and no missing ones. pub fn new() -> Self { fn init_none(_: LangItem) -> Option { None } + const EMPTY: Vec = Vec::new(); Self { items: vec![$(init_none(LangItem::$variant)),*], missing: Vec::new(), - groups: [vec![]; NUM_GROUPS], + groups: [EMPTY; NUM_GROUPS], } } diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs index 0c640a5ef7136..bebd0c6ac1202 100644 --- a/src/test/ui/const-generics/issues/issue-90318.rs +++ b/src/test/ui/const-generics/issues/issue-90318.rs @@ -13,7 +13,7 @@ fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR: overly complex generic constant - //~| ERROR: calls in constants are limited to constant functions + //~| ERROR: cannot call non-const operator in constants { } @@ -21,7 +21,7 @@ fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, //~^ ERROR: overly complex generic constant - //~| ERROR: calls in constants are limited to constant functions + //~| ERROR: cannot call non-const operator in constants { } diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr index 2b8afe2ef09ed..c8690ecd0da7e 100644 --- a/src/test/ui/const-generics/issues/issue-90318.stderr +++ b/src/test/ui/const-generics/issues/issue-90318.stderr @@ -9,11 +9,19 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constants --> $DIR/issue-90318.rs:14:10 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + | +LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + | ^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: overly complex generic constant --> $DIR/issue-90318.rs:22:8 @@ -26,11 +34,19 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constants --> $DIR/issue-90318.rs:22:10 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + | +LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] + | ^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/issue-90870.fixed b/src/test/ui/consts/issue-90870.fixed index e767effcdd06f..0d28e06e53258 100644 --- a/src/test/ui/consts/issue-90870.fixed +++ b/src/test/ui/consts/issue-90870.fixed @@ -6,20 +6,20 @@ const fn f(a: &u8, b: &u8) -> bool { *a == *b - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here } const fn g(a: &&&&i64, b: &&&&i64) -> bool { ****a == ****b - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here } const fn h(mut a: &[u8], mut b: &[u8]) -> bool { while let ([l, at @ ..], [r, bt @ ..]) = (a, b) { if *l == *r { - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here a = at; b = bt; diff --git a/src/test/ui/consts/issue-90870.rs b/src/test/ui/consts/issue-90870.rs index 35b3c8242aa0c..c6bfffd2c5c15 100644 --- a/src/test/ui/consts/issue-90870.rs +++ b/src/test/ui/consts/issue-90870.rs @@ -6,20 +6,20 @@ const fn f(a: &u8, b: &u8) -> bool { a == b - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here } const fn g(a: &&&&i64, b: &&&&i64) -> bool { a == b - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here } const fn h(mut a: &[u8], mut b: &[u8]) -> bool { while let ([l, at @ ..], [r, bt @ ..]) = (a, b) { if l == r { - //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015] + //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here a = at; b = bt; diff --git a/src/test/ui/consts/issue-90870.stderr b/src/test/ui/consts/issue-90870.stderr index 0e33e6ebe5a59..478445cfb39c5 100644 --- a/src/test/ui/consts/issue-90870.stderr +++ b/src/test/ui/consts/issue-90870.stderr @@ -1,31 +1,34 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-90870.rs:8:5 | LL | a == b | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants help: consider dereferencing here | LL | *a == *b | + + -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-90870.rs:14:5 | LL | a == b | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants help: consider dereferencing here | LL | ****a == ****b | ++++ ++++ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-90870.rs:21:12 | LL | if l == r { | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants help: consider dereferencing here | LL | if *l == *r { From d3acb9d00e64d68d8c91c9d9925b92cd79b33379 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 29 Dec 2021 17:05:54 +0800 Subject: [PATCH 18/34] Handle Fn family trait call errror --- .../src/diagnostics/conflict_errors.rs | 4 +- .../src/transform/check_consts/ops.rs | 41 ++++++++++++++++++- .../rustc_const_eval/src/util/call_kind.rs | 4 +- src/test/ui/consts/issue-28113.rs | 2 +- src/test/ui/consts/issue-28113.stderr | 3 +- src/test/ui/consts/issue-56164.rs | 2 +- src/test/ui/consts/issue-56164.stderr | 3 +- .../issue-68542-closure-in-array-len.rs | 2 +- .../issue-68542-closure-in-array-len.stderr | 3 +- .../unstable-const-fn-in-libcore.stderr | 6 ++- 10 files changed, 57 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ff1d37bfccb76..f6d21f879ff58 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -196,8 +196,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|n| format!("`{}`", n)) .unwrap_or_else(|| "value".to_owned()); match kind { - CallKind::FnCall(once_did) - if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => + CallKind::FnCall { fn_trait_id, .. } + if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => { err.span_label( fn_call_span, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 237201c547822..519b4c02b61e6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -8,7 +8,9 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{suggest_constraining_type_param, Adt, Param, TraitPredicate, Ty}; +use rustc_middle::ty::{ + suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty, +}; use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; @@ -155,7 +157,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { macro_rules! error { ($fmt:literal) => { - struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind(),) + struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind()) }; } @@ -176,6 +178,41 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { diag_trait(err, self_ty, kind.trait_def_id(tcx)) } + CallKind::FnCall { fn_trait_id, self_ty } => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0015, + "cannot call non-const closure in {}s", + ccx.const_kind(), + ); + + match self_ty.kind() { + FnDef(def_id, ..) => { + let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id)); + if ccx.tcx.is_const_fn_raw(*def_id) { + span_bug!(span, "calling const FnDef errored when it shouldn't"); + } + + err.span_note(span, "function defined here, but it is not `const`"); + } + FnPtr(..) => { + err.note(&format!( + "function pointers need an RFC before allowed to be called in {}s", + ccx.const_kind() + )); + } + Closure(..) => { + err.note(&format!( + "closures need an RFC before allowed to be called in {}s", + ccx.const_kind() + )); + } + _ => {} + } + + diag_trait(err, self_ty, fn_trait_id) + } CallKind::Operator { trait_id, self_ty, .. } => { let mut err = struct_span_err!( tcx.sess, diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index fe35d94234139..11bb9508a1f86 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -44,7 +44,7 @@ pub enum CallKind<'tcx> { is_option_or_result: bool, }, /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` - FnCall(DefId), + FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> }, /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) Operator { self_arg: Option, trait_id: DefId, self_ty: Ty<'tcx> }, DerefCoercion { @@ -85,7 +85,7 @@ pub fn call_kind<'tcx>( // an FnOnce call, an operator (e.g. `<<`), or a // deref coercion. let kind = if let Some(&trait_id) = fn_call { - Some(CallKind::FnCall(trait_id)) + Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) }) } else if let Some(&trait_id) = operator { Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) } else if is_deref { diff --git a/src/test/ui/consts/issue-28113.rs b/src/test/ui/consts/issue-28113.rs index 1d93d454af786..f8131c9f3b717 100644 --- a/src/test/ui/consts/issue-28113.rs +++ b/src/test/ui/consts/issue-28113.rs @@ -2,7 +2,7 @@ const X: u8 = || -> u8 { 5 }() - //~^ ERROR cannot call non-const fn + //~^ ERROR cannot call non-const closure ; fn main() {} diff --git a/src/test/ui/consts/issue-28113.stderr b/src/test/ui/consts/issue-28113.stderr index 75fcc010a04f9..7ad1f752eb085 100644 --- a/src/test/ui/consts/issue-28113.stderr +++ b/src/test/ui/consts/issue-28113.stderr @@ -1,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-28113.rs:4:5: 4:19] as Fn<()>>::call` in constants +error[E0015]: cannot call non-const closure in constants --> $DIR/issue-28113.rs:4:5 | LL | || -> u8 { 5 }() | ^^^^^^^^^^^^^^^^ | + = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs index af65720916cd9..9c673d20b2a95 100644 --- a/src/test/ui/consts/issue-56164.rs +++ b/src/test/ui/consts/issue-56164.rs @@ -1,7 +1,7 @@ #![feature(const_fn_fn_ptr_basics)] const fn foo() { (||{})() } -//~^ ERROR cannot call non-const fn +//~^ ERROR cannot call non-const closure const fn bad(input: fn()) { input() diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index af5d44d4814bf..62a7c7db6b83a 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -1,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-56164.rs:3:18: 3:24] as Fn<()>>::call` in constant functions +error[E0015]: cannot call non-const closure in constant functions --> $DIR/issue-56164.rs:3:18 | LL | const fn foo() { (||{})() } | ^^^^^^^^ | + = note: closures need an RFC before allowed to be called in constant functions = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: function pointers are not allowed in const fn diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.rs b/src/test/ui/consts/issue-68542-closure-in-array-len.rs index 44f44da234a7c..37958e7919d64 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.rs +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.rs @@ -3,7 +3,7 @@ // in the length part of an array. struct Bug { - a: [(); (|| { 0 })()] //~ ERROR cannot call non-const fn + a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure } fn main() {} diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 3787138afc37f..74fbbc680f7e4 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -1,9 +1,10 @@ -error[E0015]: cannot call non-const fn `<[closure@$DIR/issue-68542-closure-in-array-len.rs:6:13: 6:23] as Fn<()>>::call` in constants +error[E0015]: cannot call non-const closure in constants --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] | ^^^^^^^^^^^^ | + = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index 435141134cb88..4ef25bd1334f3 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,10 +1,14 @@ -error[E0015]: cannot call non-const fn `>::call_once` in constant functions +error[E0015]: cannot call non-const closure in constant functions --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn unwrap_or_else T + ~const std::ops::FnOnce<()>>(self, f: F) -> T { + | +++++++++++++++++++++++++++++ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:53 From cccf4b2fc3199f9647f8a4602964e0021d90eeea Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 28 Jan 2022 19:59:06 +1100 Subject: [PATCH 19/34] Adapt new change --- .../src/transform/check_consts/check.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index bd16a8853a624..2fd814c129c2a 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -832,10 +832,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } Ok(Some(ImplSource::UserDefined(data))) => { - if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) { - self.check_op(ops::FnCallNonConst(None)); - return; - } let callee_name = tcx.item_name(callee); if let Some(&did) = tcx .associated_item_def_ids(data.impl_def_id) @@ -847,6 +843,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { substs = InternalSubsts::identity_for_item(tcx, did); callee = did; } + + if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) { + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + }); + return; + } } _ if !tcx.is_const_fn_raw(callee) => { // At this point, it is only legal when the caller is marked with From 12397ab48ba9e14fbcc1f65954682f764f36e31b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 28 Jan 2022 21:57:29 +1100 Subject: [PATCH 20/34] Report the selection error when possible --- .../src/transform/check_consts/check.rs | 51 +++++++++++++------ .../call-const-trait-method-fail.rs | 3 +- .../call-const-trait-method-fail.stderr | 11 +++- .../call-generic-method-fail.rs | 3 +- .../call-generic-method-fail.stderr | 11 +++- .../const-default-method-bodies.rs | 3 +- .../const-default-method-bodies.stderr | 11 +++- .../cross-crate.gated.stderr | 11 +++- .../rfc-2632-const-trait-impl/cross-crate.rs | 4 +- ...ault-method-body-is-const-same-trait-ck.rs | 3 +- ...-method-body-is-const-same-trait-ck.stderr | 19 +++++-- .../rfc-2632-const-trait-impl/issue-88155.rs | 3 +- .../issue-88155.stderr | 11 +++- 13 files changed, 107 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 2fd814c129c2a..095c8f84f41ad 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::SelectionContext; use std::mem; @@ -808,15 +809,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } let trait_ref = TraitRef::from_method(tcx, trait_id, substs); - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - Binder::dummy(TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }), - ); + let poly_trait_pred = Binder::dummy(TraitPredicate { + trait_ref, + constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, + }); + let obligation = + Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred); let implsrc = tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); @@ -860,15 +859,37 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // #[default_method_body_is_const], and the callee is in the same // trait. let callee_trait = tcx.trait_of_item(callee); - if callee_trait.is_some() { - if tcx.has_attr(caller, sym::default_method_body_is_const) { - if tcx.trait_of_item(caller) == callee_trait { - nonconst_call_permission = true; - } - } + if callee_trait.is_some() + && tcx.has_attr(caller, sym::default_method_body_is_const) + && callee_trait == tcx.trait_of_item(caller) + // Can only call methods when it's `::f`. + && tcx.types.self_param == substs.type_at(0) + { + nonconst_call_permission = true; } if !nonconst_call_permission { + let obligation = Obligation::new( + ObligationCause::dummy_with_span(*fn_span), + param_env, + tcx.mk_predicate( + poly_trait_pred.map_bound(ty::PredicateKind::Trait), + ), + ); + + // improve diagnostics by showing what failed. Our requirements are stricter this time + // as we are going to error again anyways. + tcx.infer_ctxt().enter(|infcx| { + if let Err(e) = implsrc { + infcx.report_selection_error( + obligation.clone(), + &obligation, + &e, + false, + ); + } + }); + self.check_op(ops::FnCallNonConst { caller, callee, diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index 5f55d61f5fdcd..24b9235bb9a76 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -22,7 +22,8 @@ pub const fn add_i32(a: i32, b: i32) -> i32 { pub const fn add_u32(a: u32, b: u32) -> u32 { a.plus(b) - //~^ ERROR cannot call non-const fn + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index b5680c04a65a3..ee30d7a88405a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `u32: ~const Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:24:7 + | +LL | a.plus(b) + | ^^^^^^^ the trait `~const Plus` is not implemented for `u32` + error[E0015]: cannot call non-const fn `::plus` in constant functions --> $DIR/call-const-trait-method-fail.rs:24:7 | @@ -6,6 +12,7 @@ LL | a.plus(b) | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs index e3de75ea51943..e81e0d1e571c3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -3,7 +3,8 @@ pub const fn equals_self(t: &T) -> bool { *t == *t - //~^ ERROR cannot call non-const operator + //~^ ERROR can't compare + //~| ERROR cannot call non-const } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index d50100d033e51..2c9ee48ef6de2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -1,3 +1,9 @@ +error[E0277]: can't compare `T` with `T` in const contexts + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ no implementation for `T == T` + error[E0015]: cannot call non-const operator in constant functions --> $DIR/call-generic-method-fail.rs:5:5 | @@ -10,6 +16,7 @@ help: consider further restricting this bound LL | pub const fn equals_self(t: &T) -> bool { | ++++++++++++++++++++++++++++ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 4b685b3b2b75a..3e87787a09195 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -23,7 +23,8 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); - //~^ ERROR cannot call non-const fn + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn ConstImpl.a(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 853fa3d64781f..060d1ea53e3fc 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:25:18 + | +LL | NonConstImpl.a(); + | ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + error[E0015]: cannot call non-const fn `::a` in constant functions --> $DIR/const-default-method-bodies.rs:25:18 | @@ -6,6 +12,7 @@ LL | NonConstImpl.a(); | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr index df960902133f3..b145cd3db676f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + error[E0015]: cannot call non-const fn `::func` in constant functions --> $DIR/cross-crate.rs:15:14 | @@ -6,6 +12,7 @@ LL | NonConst.func(); | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs index 670d06b85f281..fa049ab86ff49 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs @@ -12,8 +12,8 @@ fn non_const_context() { } const fn const_context() { - NonConst.func(); - //~^ ERROR: cannot call non-const fn + NonConst.func(); //~ ERROR: cannot call non-const fn + //[gated]~^ ERROR: the trait bound Const.func(); //[stock]~^ ERROR: cannot call non-const fn } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index cccb856c2f675..4d087b5180be4 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -8,7 +8,8 @@ pub trait Tr { #[default_method_body_is_const] fn b(&self) { ().a() - //~^ ERROR calls in constant functions are limited + //~^ ERROR the trait bound + //~| ERROR cannot call } } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 91f4d2fd4b0e8..338563287a289 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -1,9 +1,18 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9 +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 | LL | ().a() - | ^^^^^^ + | ^^^ the trait `~const Tr` is not implemented for `()` -error: aborting due to previous error +error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 + | +LL | ().a() + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs index e4fc65e3cb353..cbe3fe0ce5f3f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs @@ -7,7 +7,8 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //~^ ERROR cannot call non-const fn + //~^ ERROR the trait bound + //~| ERROR cannot call non-const fn } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr index b94d655a9ffa2..eed15ab98beab 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `T: ~const A` is not satisfied + --> $DIR/issue-88155.rs:9:5 + | +LL | T::assoc() + | ^^^^^^^^^^ the trait `~const A` is not implemented for `T` + error[E0015]: cannot call non-const fn `::assoc` in constant functions --> $DIR/issue-88155.rs:9:5 | @@ -6,6 +12,7 @@ LL | T::assoc() | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. From 88d433e56fb6b9d94780e03d325d0f4d5260546a Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 10 Feb 2022 20:22:54 +1100 Subject: [PATCH 21/34] Rebless --- src/test/ui/const-generics/issue-93647.rs | 2 +- src/test/ui/const-generics/issue-93647.stderr | 5 ++++- src/test/ui/consts/const-fn-error.rs | 1 - .../call-const-trait-method-fail.stderr | 6 ++++++ .../call-generic-method-fail.stderr | 6 ++++++ .../const-default-method-bodies.stderr | 6 ++++++ .../ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr | 6 ++++++ .../default-method-body-is-const-same-trait-ck.stderr | 6 ++++++ src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr | 6 ++++++ 9 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/test/ui/const-generics/issue-93647.rs b/src/test/ui/const-generics/issue-93647.rs index 6a8fe64d1875d..c1a6bf6e34d0b 100644 --- a/src/test/ui/const-generics/issue-93647.rs +++ b/src/test/ui/const-generics/issue-93647.rs @@ -1,6 +1,6 @@ struct X; fn main() {} diff --git a/src/test/ui/const-generics/issue-93647.stderr b/src/test/ui/const-generics/issue-93647.stderr index 0fe54e7de41f0..e2048ecd60f6d 100644 --- a/src/test/ui/const-generics/issue-93647.stderr +++ b/src/test/ui/const-generics/issue-93647.stderr @@ -1,8 +1,11 @@ -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants +error[E0015]: cannot call non-const closure in constants --> $DIR/issue-93647.rs:2:5 | LL | (||1usize)() | ^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs index 0b813e65621d3..abe68c17a0d7f 100644 --- a/src/test/ui/consts/const-fn-error.rs +++ b/src/test/ui/consts/const-fn-error.rs @@ -6,7 +6,6 @@ const fn f(x: usize) -> usize { //~^ ERROR mutable references //~| ERROR cannot convert //~| ERROR cannot call non-const fn - //~| ERROR E0080 //~| ERROR `for` is not allowed in a `const fn` sum += i; } diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index ee30d7a88405a..1fc9db277610e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -3,6 +3,12 @@ error[E0277]: the trait bound `u32: ~const Plus` is not satisfied | LL | a.plus(b) | ^^^^^^^ the trait `~const Plus` is not implemented for `u32` + | +note: the trait `Plus` is implemented for `u32`, but that implementation is not `const` + --> $DIR/call-const-trait-method-fail.rs:24:7 + | +LL | a.plus(b) + | ^^^^^^^ error[E0015]: cannot call non-const fn `::plus` in constant functions --> $DIR/call-const-trait-method-fail.rs:24:7 diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr index 2c9ee48ef6de2..3963f64ad32b3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -3,6 +3,12 @@ error[E0277]: can't compare `T` with `T` in const contexts | LL | *t == *t | ^^^^^^^^ no implementation for `T == T` + | +note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const` + --> $DIR/call-generic-method-fail.rs:5:5 + | +LL | *t == *t + | ^^^^^^^^ error[E0015]: cannot call non-const operator in constant functions --> $DIR/call-generic-method-fail.rs:5:5 diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 060d1ea53e3fc..948830d6def58 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -3,6 +3,12 @@ error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satis | LL | NonConstImpl.a(); | ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | +note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const` + --> $DIR/const-default-method-bodies.rs:25:18 + | +LL | NonConstImpl.a(); + | ^^^ error[E0015]: cannot call non-const fn `::a` in constant functions --> $DIR/const-default-method-bodies.rs:25:18 diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr index b145cd3db676f..3ca9abb139b86 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr @@ -3,6 +3,12 @@ error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrai | LL | NonConst.func(); | ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | +note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` + --> $DIR/cross-crate.rs:15:14 + | +LL | NonConst.func(); + | ^^^^^^ error[E0015]: cannot call non-const fn `::func` in constant functions --> $DIR/cross-crate.rs:15:14 diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 338563287a289..db4d61f88ab2f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -3,6 +3,12 @@ error[E0277]: the trait bound `(): ~const Tr` is not satisfied | LL | ().a() | ^^^ the trait `~const Tr` is not implemented for `()` + | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 + | +LL | ().a() + | ^^^ error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr index eed15ab98beab..931c0b3658fd9 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr @@ -3,6 +3,12 @@ error[E0277]: the trait bound `T: ~const A` is not satisfied | LL | T::assoc() | ^^^^^^^^^^ the trait `~const A` is not implemented for `T` + | +note: the trait `A` is implemented for `T`, but that implementation is not `const` + --> $DIR/issue-88155.rs:9:5 + | +LL | T::assoc() + | ^^^^^^^^^^ error[E0015]: cannot call non-const fn `::assoc` in constant functions --> $DIR/issue-88155.rs:9:5 From bb45f5db78f00cbacf90d880eabf2def0a625048 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 Jun 2021 12:49:29 +0200 Subject: [PATCH 22/34] Remove the RustcDefaultCalls struct It is a leftover from before the introduction of rustc_interface --- compiler/rustc_driver/src/lib.rs | 289 +++++++++++++++---------------- 1 file changed, 138 insertions(+), 151 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index ca4e7b5142ee7..7eeae66d709e9 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -263,7 +263,7 @@ fn run_compiler( describe_lints(compiler.session(), &lint_store, registered_lints); return; } - let should_stop = RustcDefaultCalls::print_crate_info( + let should_stop = print_crate_info( &***compiler.codegen_backend(), compiler.session(), None, @@ -292,7 +292,7 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sess = compiler.session(); - let should_stop = RustcDefaultCalls::print_crate_info( + let should_stop = print_crate_info( &***compiler.codegen_backend(), sess, Some(compiler.input()), @@ -301,13 +301,9 @@ fn run_compiler( compiler.temps_dir(), ) .and_then(|| { - RustcDefaultCalls::list_metadata( - sess, - &*compiler.codegen_backend().metadata_loader(), - compiler.input(), - ) + list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input()) }) - .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler)); + .and_then(|| try_process_rlink(sess, compiler)); if should_stop == Compilation::Stop { return sess.compile_status(); @@ -512,10 +508,6 @@ impl Compilation { } } -/// CompilerCalls instance for a regular rustc build. -#[derive(Copy, Clone)] -pub struct RustcDefaultCalls; - fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { let upper_cased_code = code.to_ascii_uppercase(); let normalised = if upper_cased_code.starts_with('E') { @@ -588,162 +580,157 @@ fn show_content_with_pager(content: &str) { } } -impl RustcDefaultCalls { - pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { - if sess.opts.debugging_opts.link_only { - if let Input::File(file) = compiler.input() { - // FIXME: #![crate_type] and #![crate_name] support not implemented yet - sess.init_crate_types(collect_crate_types(sess, &[])); - let outputs = compiler.build_output_filenames(sess, &[]); - let rlink_data = fs::read(file).unwrap_or_else(|err| { - sess.fatal(&format!("failed to read rlink file: {}", err)); - }); - let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0); - let codegen_results: CodegenResults = - rustc_serialize::Decodable::decode(&mut decoder); - let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); - abort_on_err(result, sess); - } else { - sess.fatal("rlink must be a file") - } - Compilation::Stop +pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { + if sess.opts.debugging_opts.link_only { + if let Input::File(file) = compiler.input() { + // FIXME: #![crate_type] and #![crate_name] support not implemented yet + sess.init_crate_types(collect_crate_types(sess, &[])); + let outputs = compiler.build_output_filenames(sess, &[]); + let rlink_data = fs::read(file).unwrap_or_else(|err| { + sess.fatal(&format!("failed to read rlink file: {}", err)); + }); + let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0); + let codegen_results: CodegenResults = rustc_serialize::Decodable::decode(&mut decoder); + let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); + abort_on_err(result, sess); } else { - Compilation::Continue + sess.fatal("rlink must be a file") } + Compilation::Stop + } else { + Compilation::Continue } +} - pub fn list_metadata( - sess: &Session, - metadata_loader: &dyn MetadataLoader, - input: &Input, - ) -> Compilation { - if sess.opts.debugging_opts.ls { - match *input { - Input::File(ref ifile) => { - let path = &(*ifile); - let mut v = Vec::new(); - locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v) - .unwrap(); - println!("{}", String::from_utf8(v).unwrap()); - } - Input::Str { .. } => { - early_error(ErrorOutputType::default(), "cannot list metadata for stdin"); - } +pub fn list_metadata( + sess: &Session, + metadata_loader: &dyn MetadataLoader, + input: &Input, +) -> Compilation { + if sess.opts.debugging_opts.ls { + match *input { + Input::File(ref ifile) => { + let path = &(*ifile); + let mut v = Vec::new(); + locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap(); + println!("{}", String::from_utf8(v).unwrap()); + } + Input::Str { .. } => { + early_error(ErrorOutputType::default(), "cannot list metadata for stdin"); } - return Compilation::Stop; } - - Compilation::Continue + return Compilation::Stop; } - fn print_crate_info( - codegen_backend: &dyn CodegenBackend, - sess: &Session, - input: Option<&Input>, - odir: &Option, - ofile: &Option, - temps_dir: &Option, - ) -> Compilation { - use rustc_session::config::PrintRequest::*; - // NativeStaticLibs and LinkArgs are special - printed during linking - // (empty iterator returns true) - if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) { - return Compilation::Continue; - } + Compilation::Continue +} - let attrs = match input { - None => None, - Some(input) => { - let result = parse_crate_attrs(sess, input); - match result { - Ok(attrs) => Some(attrs), - Err(mut parse_error) => { - parse_error.emit(); - return Compilation::Stop; - } +fn print_crate_info( + codegen_backend: &dyn CodegenBackend, + sess: &Session, + input: Option<&Input>, + odir: &Option, + ofile: &Option, + temps_dir: &Option, +) -> Compilation { + use rustc_session::config::PrintRequest::*; + // NativeStaticLibs and LinkArgs are special - printed during linking + // (empty iterator returns true) + if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) { + return Compilation::Continue; + } + + let attrs = match input { + None => None, + Some(input) => { + let result = parse_crate_attrs(sess, input); + match result { + Ok(attrs) => Some(attrs), + Err(mut parse_error) => { + parse_error.emit(); + return Compilation::Stop; } } - }; - for req in &sess.opts.prints { - match *req { - TargetList => { - let mut targets = - rustc_target::spec::TARGETS.iter().copied().collect::>(); - targets.sort_unstable(); - println!("{}", targets.join("\n")); - } - Sysroot => println!("{}", sess.sysroot.display()), - TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()), - TargetSpec => println!("{}", sess.target.to_json().pretty()), - FileNames | CrateName => { - let input = input.unwrap_or_else(|| { - early_error(ErrorOutputType::default(), "no input file provided") - }); - let attrs = attrs.as_ref().unwrap(); - let t_outputs = rustc_interface::util::build_output_filenames( - input, odir, ofile, temps_dir, attrs, sess, - ); - let id = rustc_session::output::find_crate_name(sess, attrs, input); - if *req == PrintRequest::CrateName { - println!("{}", id); - continue; - } - let crate_types = collect_crate_types(sess, attrs); - for &style in &crate_types { - let fname = - rustc_session::output::filename_for_input(sess, style, &id, &t_outputs); - println!("{}", fname.file_name().unwrap().to_string_lossy()); - } + } + }; + for req in &sess.opts.prints { + match *req { + TargetList => { + let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::>(); + targets.sort_unstable(); + println!("{}", targets.join("\n")); + } + Sysroot => println!("{}", sess.sysroot.display()), + TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()), + TargetSpec => println!("{}", sess.target.to_json().pretty()), + FileNames | CrateName => { + let input = input.unwrap_or_else(|| { + early_error(ErrorOutputType::default(), "no input file provided") + }); + let attrs = attrs.as_ref().unwrap(); + let t_outputs = rustc_interface::util::build_output_filenames( + input, odir, ofile, temps_dir, attrs, sess, + ); + let id = rustc_session::output::find_crate_name(sess, attrs, input); + if *req == PrintRequest::CrateName { + println!("{}", id); + continue; } - Cfg => { - let mut cfgs = sess - .parse_sess - .config - .iter() - .filter_map(|&(name, value)| { - // Note that crt-static is a specially recognized cfg - // directive that's printed out here as part of - // rust-lang/rust#37406, but in general the - // `target_feature` cfg is gated under - // rust-lang/rust#29717. For now this is just - // specifically allowing the crt-static cfg and that's - // it, this is intended to get into Cargo and then go - // through to build scripts. - if (name != sym::target_feature || value != Some(sym::crt_dash_static)) - && !sess.is_nightly_build() - && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() - { - return None; - } - - if let Some(value) = value { - Some(format!("{}=\"{}\"", name, value)) - } else { - Some(name.to_string()) - } - }) - .collect::>(); - - cfgs.sort(); - for cfg in cfgs { - println!("{}", cfg); - } + let crate_types = collect_crate_types(sess, attrs); + for &style in &crate_types { + let fname = + rustc_session::output::filename_for_input(sess, style, &id, &t_outputs); + println!("{}", fname.file_name().unwrap().to_string_lossy()); } - RelocationModels - | CodeModels - | TlsModels - | TargetCPUs - | StackProtectorStrategies - | TargetFeatures => { - codegen_backend.print(*req, sess); + } + Cfg => { + let mut cfgs = sess + .parse_sess + .config + .iter() + .filter_map(|&(name, value)| { + // Note that crt-static is a specially recognized cfg + // directive that's printed out here as part of + // rust-lang/rust#37406, but in general the + // `target_feature` cfg is gated under + // rust-lang/rust#29717. For now this is just + // specifically allowing the crt-static cfg and that's + // it, this is intended to get into Cargo and then go + // through to build scripts. + if (name != sym::target_feature || value != Some(sym::crt_dash_static)) + && !sess.is_nightly_build() + && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() + { + return None; + } + + if let Some(value) = value { + Some(format!("{}=\"{}\"", name, value)) + } else { + Some(name.to_string()) + } + }) + .collect::>(); + + cfgs.sort(); + for cfg in cfgs { + println!("{}", cfg); } - // Any output here interferes with Cargo's parsing of other printed output - NativeStaticLibs => {} - LinkArgs => {} } + RelocationModels + | CodeModels + | TlsModels + | TargetCPUs + | StackProtectorStrategies + | TargetFeatures => { + codegen_backend.print(*req, sess); + } + // Any output here interferes with Cargo's parsing of other printed output + NativeStaticLibs => {} + LinkArgs => {} } - Compilation::Stop } + Compilation::Stop } /// Prints version information From 5730173763b32ada60d7653ca987562ba0dc66f6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 Jun 2021 13:03:39 +0200 Subject: [PATCH 23/34] Move setup_callbacks call to create_compiler_and_run This ensures that it is called even when run_in_thread_pool_with_globals is avoided and reduces code duplication between the parallel and non-parallel version of run_in_thread_pool_with_globals --- compiler/rustc_interface/src/interface.rs | 4 +++- compiler/rustc_interface/src/lib.rs | 1 + compiler/rustc_interface/src/util.rs | 8 ++------ src/librustdoc/lib.rs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 237aef1cf23aa..8bd24487b7843 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -186,6 +186,8 @@ pub struct Config { } pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { + crate::callbacks::setup_callbacks(); + let registry = &config.registry; let (mut sess, codegen_backend) = util::create_session( config.opts, @@ -238,7 +240,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { tracing::trace!("run_compiler"); let stderr = config.stderr.take(); - util::setup_callbacks_and_run_in_thread_pool_with_globals( + util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.debugging_opts.threads, &stderr, diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index eebeabbd45272..dcad3036cc24d 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -15,6 +15,7 @@ mod proc_macro_decls; mod queries; pub mod util; +pub use callbacks::setup_callbacks; pub use interface::{run_compiler, Config}; pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS}; pub use queries::Queries; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f74cadfebacba..d206f2644e02a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -128,7 +128,7 @@ fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) - } #[cfg(not(parallel_compiler))] -pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Send, R: Send>( +pub fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, stderr: &Option>>>, @@ -140,8 +140,6 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Se cfg = cfg.stack_size(size); } - crate::callbacks::setup_callbacks(); - let main_handler = move || { rustc_span::create_session_globals_then(edition, || { io::set_output_capture(stderr.clone()); @@ -176,14 +174,12 @@ unsafe fn handle_deadlock() { } #[cfg(parallel_compiler)] -pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Send, R: Send>( +pub fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, threads: usize, stderr: &Option>>>, f: F, ) -> R { - crate::callbacks::setup_callbacks(); - let mut config = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 68028604fa463..c320516504017 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -688,7 +688,7 @@ fn main_args(at_args: &[String]) -> MainResult { Ok(opts) => opts, Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) }, }; - rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals( + rustc_interface::util::run_in_thread_pool_with_globals( options.edition, 1, // this runs single-threaded, even in a parallel compiler &None, From f45ba82370f580fba0f1486f745607d7d30ef330 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 14 Jan 2022 19:34:01 +0100 Subject: [PATCH 24/34] Remove SPAN_DEBUG global The only difference between the default and rustc_interface set version is that the default accesses the source map from SESSION_GLOBALS while the rustc_interface version accesses the source map from the global TyCtxt. SESSION_GLOBALS is always set while running the compiler while the global TyCtxt is not always set. If the global TyCtxt is set, it's source map is identical to the one in SESSION_GLOBALS --- compiler/rustc_interface/src/callbacks.rs | 15 +-------- compiler/rustc_span/src/lib.rs | 38 +++++++---------------- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 3c7908fae79be..a18e2d1d63887 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -4,7 +4,7 @@ //! `rustc_data_structures::AtomicRef` type, which allows us to setup a global //! static which can then be set in this file at program startup. //! -//! See `SPAN_DEBUG` for an example of how to set things up. +//! See `SPAN_TRACK` for an example of how to set things up. //! //! The functions in this file should fall back to the default set in their //! origin crate when the `TyCtxt` is not present in TLS. @@ -13,18 +13,6 @@ use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_middle::ty::tls; use std::fmt; -/// This is a callback from `rustc_ast` as it cannot access the implicit state -/// in `rustc_middle` otherwise. -fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { - tls::with_opt(|tcx| { - if let Some(tcx) = tcx { - rustc_span::debug_with_source_map(span, f, tcx.sess.source_map()) - } else { - rustc_span::default_span_debug(span, f) - } - }) -} - fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { tls::with_opt(|tcx| { if let Some(tcx) = tcx { @@ -65,7 +53,6 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> /// Sets up the callbacks in prior crates which we want to refer to the /// TyCtxt in. pub fn setup_callbacks() { - rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 823a927fd8c74..3ce9f852c3d0f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1013,37 +1013,25 @@ pub fn with_source_map T>(source_map: Lrc, f: F) -> f() } -pub fn debug_with_source_map( - span: Span, - f: &mut fmt::Formatter<'_>, - source_map: &SourceMap, -) -> fmt::Result { - write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt()) -} - -pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { - with_session_globals(|session_globals| { - if let Some(source_map) = &*session_globals.source_map.borrow() { - debug_with_source_map(span, f, source_map) - } else { - f.debug_struct("Span") - .field("lo", &span.lo()) - .field("hi", &span.hi()) - .field("ctxt", &span.ctxt()) - .finish() - } - }) -} - impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (*SPAN_DEBUG)(*self, f) + with_session_globals(|session_globals| { + if let Some(source_map) = &*session_globals.source_map.borrow() { + write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt()) + } else { + f.debug_struct("Span") + .field("lo", &self.lo()) + .field("hi", &self.hi()) + .field("ctxt", &self.ctxt()) + .finish() + } + }) } } impl fmt::Debug for SpanData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f) + fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f) } } @@ -2003,8 +1991,6 @@ pub struct FileLines { pub lines: Vec, } -pub static SPAN_DEBUG: AtomicRef) -> fmt::Result> = - AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); pub static SPAN_TRACK: AtomicRef = AtomicRef::new(&((|_| {}) as fn(_))); // _____________________________________________________________________________ From 410145e0a7dfac0f9a09ac0cde7301f69a5e64b3 Mon Sep 17 00:00:00 2001 From: Badel2 <2badel2@gmail.com> Date: Fri, 11 Feb 2022 02:10:02 +0100 Subject: [PATCH 25/34] Suggest disabling download-ci-llvm option if url fails to download --- src/bootstrap/bootstrap.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 86115a9029465..6c1128b393fed 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -63,7 +63,7 @@ def support_xz(): except tarfile.CompressionError: return False -def get(base, url, path, checksums, verbose=False, do_verify=True): +def get(base, url, path, checksums, verbose=False, do_verify=True, help_on_error=None): with tempfile.NamedTemporaryFile(delete=False) as temp_file: temp_path = temp_file.name @@ -82,7 +82,7 @@ def get(base, url, path, checksums, verbose=False, do_verify=True): print("ignoring already-download file", path, "due to failed verification") os.unlink(path) - download(temp_path, "{}/{}".format(base, url), True, verbose) + download(temp_path, "{}/{}".format(base, url), True, verbose, help_on_error=help_on_error) if do_verify and not verify(temp_path, sha256, verbose): raise RuntimeError("failed verification") if verbose: @@ -95,17 +95,17 @@ def get(base, url, path, checksums, verbose=False, do_verify=True): os.unlink(temp_path) -def download(path, url, probably_big, verbose): +def download(path, url, probably_big, verbose, help_on_error=None): for _ in range(0, 4): try: - _download(path, url, probably_big, verbose, True) + _download(path, url, probably_big, verbose, True, help_on_error=help_on_error) return except RuntimeError: print("\nspurious failure, trying again") - _download(path, url, probably_big, verbose, False) + _download(path, url, probably_big, verbose, False, help_on_error=help_on_error) -def _download(path, url, probably_big, verbose, exception): +def _download(path, url, probably_big, verbose, exception, help_on_error=None): if probably_big or verbose: print("downloading {}".format(url)) # see https://serverfault.com/questions/301128/how-to-download @@ -126,7 +126,8 @@ def _download(path, url, probably_big, verbose, exception): "--connect-timeout", "30", # timeout if cannot connect within 30 seconds "--retry", "3", "-Sf", "-o", path, url], verbose=verbose, - exception=exception) + exception=exception, + help_on_error=help_on_error) def verify(path, expected, verbose): @@ -167,7 +168,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None): shutil.rmtree(os.path.join(dst, fname)) -def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs): +def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error=None, **kwargs): """Run a child program in a new process""" if verbose: print("running: " + ' '.join(args)) @@ -178,6 +179,8 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs): code = ret.wait() if code != 0: err = "failed to run: " + ' '.join(args) + if help_on_error is not None: + err += "\n" + help_on_error if verbose or exception: raise RuntimeError(err) # For most failures, we definitely do want to print this error, or the user will have no @@ -624,6 +627,14 @@ def _download_ci_llvm(self, llvm_sha, llvm_assertions): filename = "rust-dev-nightly-" + self.build + tarball_suffix tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): + help_on_error = "error: failed to download llvm from ci" + help_on_error += "\nhelp: old builds get deleted after a certain time" + help_on_error += "\nhelp: if trying to compile an old commit of rustc," + help_on_error += " disable `download-ci-llvm` in config.toml:" + help_on_error += "\n" + help_on_error += "\n[llvm]" + help_on_error += "\ndownload-ci-llvm = false" + help_on_error += "\n" get( base, "{}/{}".format(url, filename), @@ -631,6 +642,7 @@ def _download_ci_llvm(self, llvm_sha, llvm_assertions): self.checksums_sha256, verbose=self.verbose, do_verify=False, + help_on_error=help_on_error, ) unpack(tarball, tarball_suffix, self.llvm_root(), match="rust-dev", From f718b516900105ccfce2b32c915b3c3b1a136a1c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 9 Feb 2022 10:19:31 +0000 Subject: [PATCH 26/34] Update chalk tests --- .../bad-bounds-on-assoc-in-trait.rs | 1 - .../bad-bounds-on-assoc-in-trait.stderr | 6 +- .../ui/associated-type-bounds/trait-params.rs | 1 - .../ui/associated-type-bounds/union-bounds.rs | 1 - .../associated-types-stream.rs | 2 - .../hr-associated-type-bound-param-2.rs | 1 - .../hr-associated-type-bound-param-2.stderr | 12 ++-- .../hr-associated-type-bound-param-5.rs | 1 - .../hr-associated-type-bound-param-5.stderr | 8 +-- src/test/ui/associated-types/issue-50301.rs | 1 - src/test/ui/chalkify/assert.rs | 6 ++ src/test/ui/chalkify/println.rs | 3 +- src/test/ui/chalkify/trait-objects.rs | 3 +- .../const-eval/ub-nonnull.chalk.64bit.stderr | 9 +++ .../const-eval/ub-wide-ptr.chalk.64bit.stderr | 9 +++ .../ui/deriving/deriving-associated-types.rs | 1 - src/test/ui/impl-trait/example-calendar.rs | 1 - src/test/ui/impl-trait/issue-55872-2.rs | 1 - src/test/ui/impl-trait/issue-55872-2.stderr | 4 +- src/test/ui/impl-trait/issue-55872.rs | 1 - src/test/ui/impl-trait/issue-55872.stderr | 2 +- src/test/ui/impl-trait/issues/issue-65581.rs | 1 + src/test/ui/issues/issue-23122-1.rs | 6 +- src/test/ui/issues/issue-23122-2.rs | 5 +- src/test/ui/issues/issue-23122-2.stderr | 4 +- src/test/ui/issues/issue-28561.rs | 1 - src/test/ui/issues/issue-33187.rs | 16 +++-- src/test/ui/issues/issue-37051.rs | 1 - src/test/ui/issues/issue-55796.nll.stderr | 4 +- src/test/ui/issues/issue-55796.rs | 6 +- src/test/ui/issues/issue-55796.stderr | 20 +++---- .../issue-74564-if-expr-stack-overflow.rs | 1 - src/test/ui/nll/ty-outlives/issue-53789-2.rs | 59 ++++++++++--------- ....rs => default-associated-type-bound-1.rs} | 1 - ...=> default-associated-type-bound-1.stderr} | 6 +- ....rs => default-associated-type-bound-2.rs} | 0 ...=> default-associated-type-bound-2.stderr} | 6 +- ... default-generic-associated-type-bound.rs} | 0 ...ault-generic-associated-type-bound.stderr} | 6 +- .../ui/type-alias-impl-trait/issue-53598.rs | 1 - .../type-alias-impl-trait/issue-53598.stderr | 2 +- .../ui/type-alias-impl-trait/issue-57700.rs | 1 - .../type-alias-impl-trait/issue-57700.stderr | 2 +- .../ui/type-alias-impl-trait/issue-60371.rs | 2 - .../type-alias-impl-trait/issue-60371.stderr | 6 +- 45 files changed, 119 insertions(+), 112 deletions(-) create mode 100644 src/test/ui/chalkify/assert.rs create mode 100644 src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr create mode 100644 src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr rename src/test/ui/specialization/{deafult-associated-type-bound-1.rs => default-associated-type-bound-1.rs} (95%) rename src/test/ui/specialization/{deafult-associated-type-bound-1.stderr => default-associated-type-bound-1.stderr} (84%) rename src/test/ui/specialization/{deafult-associated-type-bound-2.rs => default-associated-type-bound-2.rs} (100%) rename src/test/ui/specialization/{deafult-associated-type-bound-2.stderr => default-associated-type-bound-2.stderr} (88%) rename src/test/ui/specialization/{deafult-generic-associated-type-bound.rs => default-generic-associated-type-bound.rs} (100%) rename src/test/ui/specialization/{deafult-generic-associated-type-bound.stderr => default-generic-associated-type-bound.stderr} (86%) diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index 0c4907fd00294..d180de9be3bf3 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -1,6 +1,5 @@ // NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. // This should hopefully be fixed with Chalk. -// ignore-compare-mode-chalk #![feature(associated_type_bounds)] diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index 4ecae471ec2da..c23e54594ee30 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: `<::C as Iterator>::Item` cannot be sent between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36 + --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36 | LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; | ^^^^ `<::C as Iterator>::Item` cannot be sent between threads safely @@ -11,7 +11,7 @@ LL | trait Case1 where <::C as Iterator>::Item: Send { | ++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: `<::C as Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:43 + --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43 | LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<::C as Iterator>::Item` is not an iterator @@ -23,7 +23,7 @@ LL | trait Case1 where <::C as Iterator>::Item: Iterator { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: `<::C as Iterator>::Item` cannot be shared between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93 + --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93 | LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; | ^^^^ `<::C as Iterator>::Item` cannot be shared between threads safely diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs index a9aa2747e52af..b0703a4ee22b3 100644 --- a/src/test/ui/associated-type-bounds/trait-params.rs +++ b/src/test/ui/associated-type-bounds/trait-params.rs @@ -1,5 +1,4 @@ // build-pass (FIXME(62277): could be check-pass?) -// ignore-compare-mode-chalk #![feature(associated_type_bounds)] diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs index f1aab2a6da071..97c5acf1f72ca 100644 --- a/src/test/ui/associated-type-bounds/union-bounds.rs +++ b/src/test/ui/associated-type-bounds/union-bounds.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-compare-mode-chalk #![feature(associated_type_bounds)] #![feature(untagged_unions)] diff --git a/src/test/ui/associated-types/associated-types-stream.rs b/src/test/ui/associated-types/associated-types-stream.rs index 220ee6af2fc9f..c9b302b96919f 100644 --- a/src/test/ui/associated-types/associated-types-stream.rs +++ b/src/test/ui/associated-types/associated-types-stream.rs @@ -1,8 +1,6 @@ // run-pass // Test references to the trait `Stream` in the bounds for associated // types defined on `Stream`. Issue #20551. -// ignore-compare-mode-chalk - trait Stream { type Car; diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs index 5193400882d12..f74c5a8590d1d 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk trait Z<'a, T: ?Sized> where T: Z<'a, u16>, diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index 730229b5208da..354caef1e41d8 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-2.rs:4:8 + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | T: Z<'a, u16>, | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `Z` - --> $DIR/hr-associated-type-bound-param-2.rs:7:35 + --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this @@ -14,13 +14,13 @@ LL | for<'b> >::W: Clone, | ^^^^^ required by this bound in `Z` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-2.rs:4:8 + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | T: Z<'a, u16>, | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `Z` - --> $DIR/hr-associated-type-bound-param-2.rs:7:35 + --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this @@ -29,13 +29,13 @@ LL | for<'b> >::W: Clone, | ^^^^^ required by this bound in `Z` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-2.rs:16:14 + --> $DIR/hr-associated-type-bound-param-2.rs:15:14 | LL | type W = str; | ^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `Z` - --> $DIR/hr-associated-type-bound-param-2.rs:7:35 + --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs index 920aa83528070..d7f3151a502ee 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk trait Cycle: Sized { type Next: Cycle; } diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr index 63cd89316b38c..4c04d12a71470 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:27:14 + --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `X` - --> $DIR/hr-associated-type-bound-param-5.rs:18:45 + --> $DIR/hr-associated-type-bound-param-5.rs:17:45 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -14,13 +14,13 @@ LL | for<'b> >::U: Clone, | ^^^^^ required by this bound in `X` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:32:14 + --> $DIR/hr-associated-type-bound-param-5.rs:31:14 | LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `X` - --> $DIR/hr-associated-type-bound-param-5.rs:18:45 + --> $DIR/hr-associated-type-bound-param-5.rs:17:45 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this diff --git a/src/test/ui/associated-types/issue-50301.rs b/src/test/ui/associated-types/issue-50301.rs index 4fcb41485d0e2..47ee3e7ad70e8 100644 --- a/src/test/ui/associated-types/issue-50301.rs +++ b/src/test/ui/associated-types/issue-50301.rs @@ -1,6 +1,5 @@ // Tests that HRTBs are correctly accepted -- https://github.com/rust-lang/rust/issues/50301 // check-pass -// ignore-compare-mode-chalk trait Trait where for<'a> &'a Self::IntoIter: IntoIterator, diff --git a/src/test/ui/chalkify/assert.rs b/src/test/ui/chalkify/assert.rs new file mode 100644 index 0000000000000..f4ebf91924ced --- /dev/null +++ b/src/test/ui/chalkify/assert.rs @@ -0,0 +1,6 @@ +// run-pass +// compile-flags: -Z chalk + +fn main() { + assert_eq!(1, 1); +} diff --git a/src/test/ui/chalkify/println.rs b/src/test/ui/chalkify/println.rs index cf36aef8afaf3..0f0df29019e7b 100644 --- a/src/test/ui/chalkify/println.rs +++ b/src/test/ui/chalkify/println.rs @@ -2,6 +2,5 @@ // compile-flags: -Z chalk fn main() { - // FIXME(chalk): Require `RegionOutlives`/`TypeOutlives`/`Subtype` support - //println!("hello"); + println!("hello"); } diff --git a/src/test/ui/chalkify/trait-objects.rs b/src/test/ui/chalkify/trait-objects.rs index 13d9e6a657885..d56abc42bf540 100644 --- a/src/test/ui/chalkify/trait-objects.rs +++ b/src/test/ui/chalkify/trait-objects.rs @@ -5,8 +5,7 @@ use std::fmt::Display; fn main() { let d: &dyn Display = &mut 3; - // FIXME(chalk) should be able to call d.to_string() as well, but doing so - // requires Chalk to be able to prove trait object well-formed goals. + d.to_string(); (&d).to_string(); let f: &dyn Fn(i32) -> _ = &|x| x + x; f(2); diff --git a/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr new file mode 100644 index 0000000000000..2a4b6f3b76f90 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `>::Output == _` + --> $DIR/ub-nonnull.rs:19:30 + | +LL | let out_of_bounds_ptr = &ptr[255]; + | ^^^^^^^^ cannot satisfy `>::Output == _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr new file mode 100644 index 0000000000000..39352ca848a80 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/ub-wide-ptr.rs:90:67 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/deriving/deriving-associated-types.rs b/src/test/ui/deriving/deriving-associated-types.rs index 13735ff2c5a1c..4b1cbe80c506d 100644 --- a/src/test/ui/deriving/deriving-associated-types.rs +++ b/src/test/ui/deriving/deriving-associated-types.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-compare-mode-chalk pub trait DeclaredTrait { type Type; } diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs index 45dcb74a6e05c..da45f0d133deb 100644 --- a/src/test/ui/impl-trait/example-calendar.rs +++ b/src/test/ui/impl-trait/example-calendar.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-compare-mode-chalk #![feature(fn_traits, step_trait, diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs index a519397806e07..17a6a85787442 100644 --- a/src/test/ui/impl-trait/issue-55872-2.rs +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -1,5 +1,4 @@ // edition:2018 -// ignore-compare-mode-chalk #![feature(type_alias_impl_trait)] diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index 97545ba3d1124..b76b564dfb139 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/issue-55872-2.rs:14:20 + --> $DIR/issue-55872-2.rs:13:20 | LL | fn foo() -> Self::E { | ^^^^^^^ the trait `Copy` is not implemented for `impl Future` error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:14:28 + --> $DIR/issue-55872-2.rs:13:28 | LL | fn foo() -> Self::E { | ____________________________^ diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs index bbd940254178c..183728b0f7f0a 100644 --- a/src/test/ui/impl-trait/issue-55872.rs +++ b/src/test/ui/impl-trait/issue-55872.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk #![feature(type_alias_impl_trait)] pub trait Bar { diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr index 60654ec34610f..39d870dc003bb 100644 --- a/src/test/ui/impl-trait/issue-55872.stderr +++ b/src/test/ui/impl-trait/issue-55872.stderr @@ -1,5 +1,5 @@ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872.rs:13:28 + --> $DIR/issue-55872.rs:12:28 | LL | fn foo() -> Self::E { | ____________________________^ diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs index af65b79d3e838..b947fc1d2396f 100644 --- a/src/test/ui/impl-trait/issues/issue-65581.rs +++ b/src/test/ui/impl-trait/issues/issue-65581.rs @@ -1,4 +1,5 @@ // check-pass +// ignore-compare-mode-chalk #![allow(dead_code)] diff --git a/src/test/ui/issues/issue-23122-1.rs b/src/test/ui/issues/issue-23122-1.rs index efa4e614be5b0..7fe0900ed5fde 100644 --- a/src/test/ui/issues/issue-23122-1.rs +++ b/src/test/ui/issues/issue-23122-1.rs @@ -1,10 +1,10 @@ -// ignore-compare-mode-chalk - trait Next { type Next: Next; } -struct GetNext { t: T } +struct GetNext { + t: T, +} impl Next for GetNext { type Next = as Next>::Next; diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs index 7866b931ec4b9..95e1f60d8b029 100644 --- a/src/test/ui/issues/issue-23122-2.rs +++ b/src/test/ui/issues/issue-23122-2.rs @@ -1,9 +1,10 @@ -// ignore-compare-mode-chalk trait Next { type Next: Next; } -struct GetNext { t: T } +struct GetNext { + t: T, +} impl Next for GetNext { type Next = as Next>::Next; diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index b345e90178742..7519e632d5446 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,12 +1,12 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` - --> $DIR/issue-23122-2.rs:9:17 + --> $DIR/issue-23122-2.rs:10:17 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`) note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` - --> $DIR/issue-23122-2.rs:8:15 + --> $DIR/issue-23122-2.rs:9:15 | LL | impl Next for GetNext { | ^^^^ ^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-28561.rs b/src/test/ui/issues/issue-28561.rs index 184f5cb26c546..1241fb0b1f85f 100644 --- a/src/test/ui/issues/issue-28561.rs +++ b/src/test/ui/issues/issue-28561.rs @@ -1,5 +1,4 @@ // check-pass -// ignore-compare-mode-chalk #[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] struct Array { f00: [T; 00], diff --git a/src/test/ui/issues/issue-33187.rs b/src/test/ui/issues/issue-33187.rs index f6b56610ec7d9..8db9e00588564 100644 --- a/src/test/ui/issues/issue-33187.rs +++ b/src/test/ui/issues/issue-33187.rs @@ -1,10 +1,15 @@ // run-pass -// ignore-compare-mode-chalk + struct Foo(::Data); -impl Copy for Foo where ::Data: Copy { } -impl Clone for Foo where ::Data: Clone { - fn clone(&self) -> Self { Foo(self.0.clone()) } +impl Copy for Foo where ::Data: Copy {} +impl Clone for Foo +where + ::Data: Clone, +{ + fn clone(&self) -> Self { + Foo(self.0.clone()) + } } trait Repr { @@ -15,5 +20,4 @@ impl Repr for A { type Data = u32; } -fn main() { -} +fn main() {} diff --git a/src/test/ui/issues/issue-37051.rs b/src/test/ui/issues/issue-37051.rs index e0c47197eaa03..9cae6cf5e7665 100644 --- a/src/test/ui/issues/issue-37051.rs +++ b/src/test/ui/issues/issue-37051.rs @@ -1,5 +1,4 @@ // check-pass -// ignore-compare-mode-chalk #![feature(associated_type_defaults)] diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr index c1a3084f30eae..5809a56cd4b6b 100644 --- a/src/test/ui/issues/issue-55796.nll.stderr +++ b/src/test/ui/issues/issue-55796.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-55796.rs:18:9 + --> $DIR/issue-55796.rs:16:9 | LL | pub trait Graph<'a> { | -- lifetime `'a` defined here @@ -8,7 +8,7 @@ LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/issue-55796.rs:23:9 + --> $DIR/issue-55796.rs:21:9 | LL | pub trait Graph<'a> { | -- lifetime `'a` defined here diff --git a/src/test/ui/issues/issue-55796.rs b/src/test/ui/issues/issue-55796.rs index 1086669ee7463..d802ce3b6cfbf 100644 --- a/src/test/ui/issues/issue-55796.rs +++ b/src/test/ui/issues/issue-55796.rs @@ -1,5 +1,3 @@ -// ignore-compare-mode-chalk - pub trait EdgeTrait { fn target(&self) -> N; } @@ -16,12 +14,12 @@ pub trait Graph<'a> { fn out_neighbors(&'a self, u: &Self::Node) -> Box> { Box::new(self.out_edges(u).map(|e| e.target())) -//~^ ERROR cannot infer + //~^ ERROR cannot infer } fn in_neighbors(&'a self, u: &Self::Node) -> Box> { Box::new(self.in_edges(u).map(|e| e.target())) -//~^ ERROR cannot infer + //~^ ERROR cannot infer } } diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index 304339657f0a9..569a13f45bce8 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -1,22 +1,22 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/issue-55796.rs:18:9 + --> $DIR/issue-55796.rs:16:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined here... - --> $DIR/issue-55796.rs:7:17 + --> $DIR/issue-55796.rs:5:17 | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:18:40: 18:54]>` will meet its required lifetime bounds - --> $DIR/issue-55796.rs:18:9 +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds + --> $DIR/issue-55796.rs:16:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that the types are compatible - --> $DIR/issue-55796.rs:18:9 + --> $DIR/issue-55796.rs:16:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,24 +24,24 @@ LL | Box::new(self.out_edges(u).map(|e| e.target())) found `Box>::Node>>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/issue-55796.rs:23:9 + --> $DIR/issue-55796.rs:21:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined here... - --> $DIR/issue-55796.rs:7:17 + --> $DIR/issue-55796.rs:5:17 | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:23:39: 23:53]>` will meet its required lifetime bounds - --> $DIR/issue-55796.rs:23:9 +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds + --> $DIR/issue-55796.rs:21:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that the types are compatible - --> $DIR/issue-55796.rs:23:9 + --> $DIR/issue-55796.rs:21:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs index 44ea9f12d38ff..36e9932602fb0 100644 --- a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs +++ b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs @@ -1,6 +1,5 @@ // build-pass // ignore-tidy-filelength -// ignore-compare-mode-chalk #![crate_type = "rlib"] fn banana(v: &str) -> u32 { diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs index d15e402460794..5109a0e4a683d 100644 --- a/src/test/ui/nll/ty-outlives/issue-53789-2.rs +++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs @@ -1,16 +1,14 @@ // Regression test for #53789. // // check-pass -// ignore-compare-mode-chalk +use std::cmp::Ord; use std::collections::BTreeMap; use std::ops::Range; -use std::cmp::Ord; macro_rules! valuetree { () => { - type ValueTree = - ::Value; + type ValueTree = ::Value; }; } @@ -41,7 +39,9 @@ macro_rules! product_type { macro_rules! default { ($type: ty, $val: expr) => { impl Default for $type { - fn default() -> Self { $val.into() } + fn default() -> Self { + $val.into() + } } }; } @@ -90,21 +90,17 @@ trait ValueTree { } trait Strategy { - type Value : ValueTree; + type Value: ValueTree; } #[derive(Clone)] -struct VecStrategy { +struct VecStrategy { element: T, size: Range, } -fn vec(element: T, size: Range) - -> VecStrategy { - VecStrategy { - element: element, - size: size, - } +fn vec(element: T, size: Range) -> VecStrategy { + VecStrategy { element: element, size: size } } type ValueFor = <::Value as ValueTree>::Value; @@ -124,7 +120,6 @@ type StrategyType<'a, A> = >::Strategy; struct SizeBounds(Range); default!(SizeBounds, 0..100); - impl From> for SizeBounds { fn from(high: Range) -> Self { unimplemented!() @@ -137,24 +132,26 @@ impl From for Range { } } - -fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) - -> StrategyType<'a, A> { +fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> { unimplemented!() } -impl Strategy for (K, V) where - ::Value: Ord { +impl Strategy for (K, V) +where + ::Value: Ord, +{ type Value = TupleValueTree<(K, V)>; } -impl ValueTree for TupleValueTree<(K, V)> where - ::Value: Ord { +impl ValueTree for TupleValueTree<(K, V)> +where + ::Value: Ord, +{ type Value = BTreeMapValueTree; } #[derive(Clone)] -struct VecValueTree { +struct VecValueTree { elements: Vec, } @@ -185,8 +182,8 @@ impl<'a, A, B> Arbitrary<'a> for BTreeMap where A: Arbitrary<'static> + Ord, B: Arbitrary<'static>, -StrategyFor: 'static, -StrategyFor: 'static, + StrategyFor: 'static, + StrategyFor: 'static, { valuetree!(); type Parameters = RangedParams2; @@ -208,10 +205,14 @@ mapfn! { } } -fn btree_map - (key: K, value: V, size: Range) - -> BTreeMapStrategy -where ValueFor : Ord { +fn btree_map( + key: K, + value: V, + size: Range, +) -> BTreeMapStrategy +where + ValueFor: Ord, +{ unimplemented!() } @@ -245,4 +246,4 @@ mod statics { } } -fn main() { } +fn main() {} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/default-associated-type-bound-1.rs similarity index 95% rename from src/test/ui/specialization/deafult-associated-type-bound-1.rs rename to src/test/ui/specialization/default-associated-type-bound-1.rs index 6eb2aa980d152..c043114b565c8 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.rs +++ b/src/test/ui/specialization/default-associated-type-bound-1.rs @@ -1,6 +1,5 @@ // Check that we check that default associated types satisfy the required // bounds on them. -// ignore-compare-mode-chalk #![feature(specialization)] //~^ WARNING `specialization` is incomplete diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr similarity index 84% rename from src/test/ui/specialization/deafult-associated-type-bound-1.stderr rename to src/test/ui/specialization/default-associated-type-bound-1.stderr index 9e400f8702474..6680a29f94245 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/default-associated-type-bound-1.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/deafult-associated-type-bound-1.rs:5:12 + --> $DIR/default-associated-type-bound-1.rs:4:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,13 +9,13 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/deafult-associated-type-bound-1.rs:19:22 + --> $DIR/default-associated-type-bound-1.rs:18:22 | LL | default type U = str; | ^^^ the trait `Clone` is not implemented for `str` | note: required by a bound in `X::U` - --> $DIR/deafult-associated-type-bound-1.rs:9:13 + --> $DIR/default-associated-type-bound-1.rs:8:13 | LL | type U: Clone; | ^^^^^ required by this bound in `X::U` diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/default-associated-type-bound-2.rs similarity index 100% rename from src/test/ui/specialization/deafult-associated-type-bound-2.rs rename to src/test/ui/specialization/default-associated-type-bound-2.rs diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/default-associated-type-bound-2.stderr similarity index 88% rename from src/test/ui/specialization/deafult-associated-type-bound-2.stderr rename to src/test/ui/specialization/default-associated-type-bound-2.stderr index 47ea69d40bbb7..0fd1f65b0a201 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/default-associated-type-bound-2.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/deafult-associated-type-bound-2.rs:2:12 + --> $DIR/default-associated-type-bound-2.rs:2:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,14 +9,14 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `&'static B` with `B` - --> $DIR/deafult-associated-type-bound-2.rs:16:22 + --> $DIR/default-associated-type-bound-2.rs:16:22 | LL | default type U = &'static B; | ^^^^^^^^^^ no implementation for `&'static B == B` | = help: the trait `PartialEq` is not implemented for `&'static B` note: required by a bound in `X::U` - --> $DIR/deafult-associated-type-bound-2.rs:6:13 + --> $DIR/default-associated-type-bound-2.rs:6:13 | LL | type U: PartialEq; | ^^^^^^^^^^^^ required by this bound in `X::U` diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/default-generic-associated-type-bound.rs similarity index 100% rename from src/test/ui/specialization/deafult-generic-associated-type-bound.rs rename to src/test/ui/specialization/default-generic-associated-type-bound.rs diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/default-generic-associated-type-bound.stderr similarity index 86% rename from src/test/ui/specialization/deafult-generic-associated-type-bound.stderr rename to src/test/ui/specialization/default-generic-associated-type-bound.stderr index da5fe97cf1b8b..58c6667c8c7ad 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/default-generic-associated-type-bound.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/deafult-generic-associated-type-bound.rs:3:12 + --> $DIR/default-generic-associated-type-bound.rs:3:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,14 +9,14 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `T` with `T` - --> $DIR/deafult-generic-associated-type-bound.rs:18:26 + --> $DIR/default-generic-associated-type-bound.rs:18:26 | LL | default type U<'a> = &'a T; | ^^^^^ no implementation for `T == T` | = note: required because of the requirements on the impl of `PartialEq` for `&'a T` note: required by a bound in `X::U` - --> $DIR/deafult-generic-associated-type-bound.rs:8:17 + --> $DIR/default-generic-associated-type-bound.rs:8:17 | LL | type U<'a>: PartialEq<&'a Self> where Self: 'a; | ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U` diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.rs b/src/test/ui/type-alias-impl-trait/issue-53598.rs index 37b330ba4b8fc..f936dc42f133d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53598.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53598.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk #![feature(type_alias_impl_trait)] use std::fmt::Debug; diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.stderr b/src/test/ui/type-alias-impl-trait/issue-53598.stderr index 4c8144a235930..9971c7e0e20ee 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53598.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53598.stderr @@ -1,5 +1,5 @@ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-53598.rs:20:42 + --> $DIR/issue-53598.rs:19:42 | LL | fn foo(_: T) -> Self::Item { | __________________________________________^ diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.rs b/src/test/ui/type-alias-impl-trait/issue-57700.rs index f1db4d3291b40..13a6b7c2f7ceb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57700.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57700.rs @@ -1,4 +1,3 @@ -// ignore-compare-mode-chalk #![feature(arbitrary_self_types)] #![feature(type_alias_impl_trait)] diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.stderr b/src/test/ui/type-alias-impl-trait/issue-57700.stderr index c701e3e74ef59..b2e3f46f1f582 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57700.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57700.stderr @@ -1,5 +1,5 @@ error: type parameter `impl Deref` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-57700.rs:16:58 + --> $DIR/issue-57700.rs:15:58 | LL | fn foo(self: impl Deref) -> Self::Bar { | __________________________________________________________^ diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index 9d2ba849c8667..badf35484f360 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -1,5 +1,3 @@ -// ignore-compare-mode-chalk - trait Bug { type Item: Bug; diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 62ab7eb456010..dc8a381aece94 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -1,5 +1,5 @@ error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/issue-60371.rs:10:17 + --> $DIR/issue-60371.rs:8:17 | LL | type Item = impl Bug; | ^^^^^^^^ @@ -8,7 +8,7 @@ LL | type Item = impl Bug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0277]: the trait bound `(): Bug` is not satisfied - --> $DIR/issue-60371.rs:12:40 + --> $DIR/issue-60371.rs:10:40 | LL | const FUN: fn() -> Self::Item = || (); | ^ the trait `Bug` is not implemented for `()` @@ -17,7 +17,7 @@ LL | const FUN: fn() -> Self::Item = || (); <&() as Bug> error: non-defining opaque type use in defining scope - --> $DIR/issue-60371.rs:12:37 + --> $DIR/issue-60371.rs:10:37 | LL | impl Bug for &() { | - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type From 030c50824c670da9fecd3ccdaec4d75d3dab1268 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 11 Feb 2022 18:20:47 +0000 Subject: [PATCH 27/34] Address review comment canonicalize_chalk_query -> canonicalize_query_preserving_universes --- compiler/rustc_infer/src/infer/canonical/canonicalizer.rs | 4 +++- compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 7446f24968803..bd5892dba38c7 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -53,7 +53,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1` /// in `U2`. - pub fn canonicalize_chalk_query( + /// + /// This is used for Chalk integration. + pub fn canonicalize_query_preserving_universes( &self, value: V, query_state: &mut OriginalQueryValues<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 28b0ce9a171f8..93c2f202545f6 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -95,7 +95,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { continue; } - let canonical_goal = infcx.canonicalize_chalk_query(goal, &mut orig_values); + let canonical_goal = + infcx.canonicalize_query_preserving_universes(goal, &mut orig_values); match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { From a0d603f6e89b17390f4806237bcec3386cb01eaa Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sat, 12 Feb 2022 11:47:00 -0500 Subject: [PATCH 28/34] Don't relabel to a team if there is already a team label --- triagebot.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index b484c25ea510f..276587e7f13fb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -113,6 +113,9 @@ trigger_files = [ "src/tools/rustdoc-js", "src/tools/rustdoc-themes", ] +exclude_labels = [ + "T-*", +] [autolabel."T-compiler"] trigger_files = [ @@ -122,6 +125,9 @@ trigger_files = [ # Tests "src/test/ui", ] +exclude_labels = [ + "T-*", +] [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts From 9efe61df7f609de8d90fb7f40b29ea6fe72ff205 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 12 Feb 2022 13:15:10 -0500 Subject: [PATCH 29/34] Fix signature of u8::escape_ascii --- library/core/src/num/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 864a253299f6e..40bd706da8ce0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -806,8 +806,8 @@ impl u8 { without modifying the original"] #[unstable(feature = "inherent_ascii_escape", issue = "77174")] #[inline] - pub fn escape_ascii(&self) -> ascii::EscapeDefault { - ascii::escape_default(*self) + pub fn escape_ascii(self) -> ascii::EscapeDefault { + ascii::escape_default(self) } pub(crate) fn is_utf8_char_boundary(self) -> bool { From de6e9731764af14b27b6158834454344da49c37d Mon Sep 17 00:00:00 2001 From: ltdk Date: Thu, 10 Feb 2022 21:09:05 -0500 Subject: [PATCH 30/34] Stabilise inherent_ascii_escape (FCP in #77174) --- library/alloc/src/lib.rs | 1 - library/alloc/src/slice.rs | 2 +- library/core/src/num/mod.rs | 3 +-- library/core/src/slice/ascii.rs | 17 ++++++++--------- library/core/src/slice/mod.rs | 2 +- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ab9f0b9d7378f..ce75859f963f6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -112,7 +112,6 @@ #![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] -#![feature(inherent_ascii_escape)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(layout_for_ptr)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index a5c4140e31387..f0397d08f95a8 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -108,7 +108,7 @@ pub use core::slice::ArrayChunks; pub use core::slice::ArrayChunksMut; #[unstable(feature = "array_windows", issue = "75027")] pub use core::slice::ArrayWindows; -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 40bd706da8ce0..72105888f9447 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -791,7 +791,6 @@ impl u8 { /// # Examples /// /// ``` - /// #![feature(inherent_ascii_escape)] /// /// assert_eq!("0", b'0'.escape_ascii().to_string()); /// assert_eq!("\\t", b'\t'.escape_ascii().to_string()); @@ -804,7 +803,7 @@ impl u8 { /// ``` #[must_use = "this returns the escaped byte as an iterator, \ without modifying the original"] - #[unstable(feature = "inherent_ascii_escape", issue = "77174")] + #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] #[inline] pub fn escape_ascii(self) -> ascii::EscapeDefault { ascii::escape_default(self) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 080256f493f5f..304ba7ee5544f 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -68,7 +68,6 @@ impl [u8] { /// # Examples /// /// ``` - /// #![feature(inherent_ascii_escape)] /// /// let s = b"0\t\r\n'\"\\\x9d"; /// let escaped = s.escape_ascii().to_string(); @@ -76,7 +75,7 @@ impl [u8] { /// ``` #[must_use = "this returns the escaped bytes as an iterator, \ without modifying the original"] - #[unstable(feature = "inherent_ascii_escape", issue = "77174")] + #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub fn escape_ascii(&self) -> EscapeAscii<'_> { EscapeAscii { inner: self.iter().flat_map(EscapeByte) } } @@ -93,13 +92,13 @@ impl_fn_for_zst! { /// /// This `struct` is created by the [`slice::escape_ascii`] method. See its /// documentation for more information. -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] #[derive(Clone)] pub struct EscapeAscii<'a> { inner: iter::FlatMap, ascii::EscapeDefault, EscapeByte>, } -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::Iterator for EscapeAscii<'a> { type Item = u8; #[inline] @@ -131,23 +130,23 @@ impl<'a> iter::Iterator for EscapeAscii<'a> { } } -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> { fn next_back(&mut self) -> Option { self.inner.next_back() } } -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {} -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::FusedIterator for EscapeAscii<'a> {} -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.clone().try_for_each(|b| f.write_char(b as char)) } } -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Debug for EscapeAscii<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EscapeAscii").finish_non_exhaustive() diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4e22c1d8c6d94..cd38c3a75473d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -81,7 +81,7 @@ pub use index::SliceIndex; #[unstable(feature = "slice_range", issue = "76393")] pub use index::range; -#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use ascii::EscapeAscii; /// Calculates the direction and split point of a one-sided range. From 9d8ef1160747a4d033f21803770641f2deb32b25 Mon Sep 17 00:00:00 2001 From: The8472 Date: Fri, 15 Oct 2021 23:55:23 +0200 Subject: [PATCH 31/34] make Instant::{duration_since, elapsed, sub} saturating and remove workarounds This removes all mutex/atomics based workarounds for non-monotonic clocks and makes the previously panicking methods saturating instead. Effectively this moves the monotonization from `Instant` construction to the comparisons. This has some observable effects, especially on platforms without monotonic clocks: * Incorrectly ordered Instant comparisons no longer panic. This may hide some programming errors until someone actually looks at the resulting `Duration` * `checked_duration_since` will now return `None` in more cases. Previously it only happened when one compared instants obtained in the wrong order or manually created ones. Now it also does on backslides. The upside is reduced complexity and lower overhead of `Instant::now`. --- library/std/src/sys/hermit/time.rs | 8 -- library/std/src/sys/itron/time.rs | 9 -- library/std/src/sys/sgx/time.rs | 8 -- library/std/src/sys/unix/time.rs | 19 ---- library/std/src/sys/unsupported/time.rs | 8 -- library/std/src/sys/wasi/time.rs | 8 -- library/std/src/sys/windows/time.rs | 8 -- library/std/src/time.rs | 85 ++++++----------- library/std/src/time/monotonic.rs | 116 ------------------------ library/std/src/time/tests.rs | 31 +------ 10 files changed, 30 insertions(+), 270 deletions(-) delete mode 100644 library/std/src/time/monotonic.rs diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs index c02de17c1fc3a..27173de630729 100644 --- a/library/std/src/sys/hermit/time.rs +++ b/library/std/src/sys/hermit/time.rs @@ -115,14 +115,6 @@ impl Instant { Instant { t: time } } - pub const fn zero() -> Instant { - Instant { t: Timespec::zero() } - } - - pub fn actually_monotonic() -> bool { - true - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.t.sub_timespec(&other.t).ok() } diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs index 6a992ad1d3c75..25f13ee441aca 100644 --- a/library/std/src/sys/itron/time.rs +++ b/library/std/src/sys/itron/time.rs @@ -14,15 +14,6 @@ impl Instant { } } - pub const fn zero() -> Instant { - Instant(0) - } - - pub fn actually_monotonic() -> bool { - // There are ways to change the system time - false - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.0.checked_sub(other.0).map(|ticks| { // `SYSTIM` is measured in microseconds diff --git a/library/std/src/sys/sgx/time.rs b/library/std/src/sys/sgx/time.rs index e2f6e6dba695d..db4cf2804bf13 100644 --- a/library/std/src/sys/sgx/time.rs +++ b/library/std/src/sys/sgx/time.rs @@ -25,14 +25,6 @@ impl Instant { pub fn checked_sub_duration(&self, other: &Duration) -> Option { Some(Instant(self.0.checked_sub(*other)?)) } - - pub fn actually_monotonic() -> bool { - false - } - - pub const fn zero() -> Instant { - Instant(Duration::from_secs(0)) - } } impl SystemTime { diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 824283ef6c41e..59ddd1aa92f81 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -154,14 +154,6 @@ mod inner { Instant { t: unsafe { mach_absolute_time() } } } - pub const fn zero() -> Instant { - Instant { t: 0 } - } - - pub fn actually_monotonic() -> bool { - true - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { let diff = self.t.checked_sub(other.t)?; let info = info(); @@ -296,17 +288,6 @@ mod inner { Instant { t: now(libc::CLOCK_MONOTONIC) } } - pub const fn zero() -> Instant { - Instant { t: Timespec::zero() } - } - - pub fn actually_monotonic() -> bool { - (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) - || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) - || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64")) - || cfg!(target_os = "fuchsia") - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.t.sub_timespec(&other.t).ok() } diff --git a/library/std/src/sys/unsupported/time.rs b/library/std/src/sys/unsupported/time.rs index 8aaf1777f2427..6d67b538a96bf 100644 --- a/library/std/src/sys/unsupported/time.rs +++ b/library/std/src/sys/unsupported/time.rs @@ -13,14 +13,6 @@ impl Instant { panic!("time not implemented on this platform") } - pub const fn zero() -> Instant { - Instant(Duration::from_secs(0)) - } - - pub fn actually_monotonic() -> bool { - false - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.0.checked_sub(other.0) } diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index db0ddecf0c629..088585654b948 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -25,14 +25,6 @@ impl Instant { Instant(current_time(wasi::CLOCKID_MONOTONIC)) } - pub const fn zero() -> Instant { - Instant(Duration::from_secs(0)) - } - - pub fn actually_monotonic() -> bool { - true - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { self.0.checked_sub(other.0) } diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs index 91e4f7654840d..a04908b541cdb 100644 --- a/library/std/src/sys/windows/time.rs +++ b/library/std/src/sys/windows/time.rs @@ -41,14 +41,6 @@ impl Instant { perf_counter::PerformanceCounterInstant::now().into() } - pub fn actually_monotonic() -> bool { - false - } - - pub const fn zero() -> Instant { - Instant { t: Duration::from_secs(0) } - } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { // On windows there's a threshold below which we consider two timestamps // equivalent due to measurement error. For more details + doc link, diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 2d2b96c8bcec7..0d6ace7536bf4 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -31,7 +31,6 @@ #![stable(feature = "time", since = "1.3.0")] -mod monotonic; #[cfg(test)] mod tests; @@ -125,6 +124,23 @@ pub use core::time::FromFloatSecsError; /// > structure cannot represent the new point in time. /// /// [`add`]: Instant::add +/// +/// ## Monotonicity +/// +/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior +/// if available, which is the case for all [tier 1] platforms. +/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization +/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks +/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. [`checked_duration_since`] can +/// be used to detect and handle situations where monotonicity is violated, or `Instant`s are +/// subtracted in the wrong order. +/// +/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html +/// [`duration_since`]: Instant::duration_since +/// [`elapsed`]: Instant::elapsed +/// [`sub`]: Instant::sub +/// [`checked_duration_since`]: Instant::checked_duration_since +/// #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[stable(feature = "time2", since = "1.8.0")] pub struct Instant(time::Instant); @@ -247,59 +263,12 @@ impl Instant { #[must_use] #[stable(feature = "time2", since = "1.8.0")] pub fn now() -> Instant { - let os_now = time::Instant::now(); - - // And here we come upon a sad state of affairs. The whole point of - // `Instant` is that it's monotonically increasing. We've found in the - // wild, however, that it's not actually monotonically increasing for - // one reason or another. These appear to be OS and hardware level bugs, - // and there's not really a whole lot we can do about them. Here's a - // taste of what we've found: - // - // * #48514 - OpenBSD, x86_64 - // * #49281 - linux arm64 and s390x - // * #51648 - windows, x86 - // * #56560 - windows, x86_64, AWS - // * #56612 - windows, x86, vm (?) - // * #56940 - linux, arm64 - // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar - // Firefox bug - // - // It seems that this just happens a lot in the wild. - // We're seeing panics across various platforms where consecutive calls - // to `Instant::now`, such as via the `elapsed` function, are panicking - // as they're going backwards. Placed here is a last-ditch effort to try - // to fix things up. We keep a global "latest now" instance which is - // returned instead of what the OS says if the OS goes backwards. - // - // To hopefully mitigate the impact of this, a few platforms are - // excluded as "these at least haven't gone backwards yet". - // - // While issues have been seen on arm64 platforms the Arm architecture - // requires that the counter monotonically increases and that it must - // provide a uniform view of system time (e.g. it must not be possible - // for a core to receive a message from another core with a time stamp - // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While - // there have been a few 64bit SoCs that have bugs which cause time to - // not monoticially increase, these have been fixed in the Linux kernel - // and we shouldn't penalize all Arm SoCs for those who refuse to - // update their kernels: - // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1 - // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10 - // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11 - // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12 - if time::Instant::actually_monotonic() { - return Instant(os_now); - } - - Instant(monotonic::monotonize(os_now)) + Instant(time::Instant::now()) } - /// Returns the amount of time elapsed from another instant to this one. - /// - /// # Panics + /// Returns the amount of time elapsed from another instant to this one, + /// or zero duration if that instant is later than this one. /// - /// This function will panic if `earlier` is later than `self`. /// /// # Examples /// @@ -311,16 +280,22 @@ impl Instant { /// sleep(Duration::new(1, 0)); /// let new_now = Instant::now(); /// println!("{:?}", new_now.duration_since(now)); + /// println!("{:?}", now.duration_since(new_now)); // 0ns /// ``` #[must_use] #[stable(feature = "time2", since = "1.8.0")] pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self") + self.checked_duration_since(earlier).unwrap_or_default() } /// Returns the amount of time elapsed from another instant to this one, /// or None if that instant is later than this one. /// + /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s, + /// this method can return `None`. + /// + /// [monotonicity bugs]: Instant#monotonicity + /// /// # Examples /// /// ```no_run @@ -362,12 +337,6 @@ impl Instant { /// Returns the amount of time elapsed since this instant was created. /// - /// # Panics - /// - /// This function may panic if the current time is earlier than this - /// instant, which is something that can happen if an `Instant` is - /// produced synthetically. - /// /// # Examples /// /// ```no_run diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs deleted file mode 100644 index 64f16245c2b16..0000000000000 --- a/library/std/src/time/monotonic.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::sys::time; - -#[inline] -pub(super) fn monotonize(raw: time::Instant) -> time::Instant { - inner::monotonize(raw) -} - -#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))] -pub mod inner { - use crate::sync::atomic::AtomicU64; - use crate::sync::atomic::Ordering::*; - use crate::sys::time; - use crate::time::Duration; - - pub(in crate::time) const ZERO: time::Instant = time::Instant::zero(); - - // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9 - const UNINITIALIZED: u64 = 0b11 << 30; - static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED); - - #[inline] - pub(super) fn monotonize(raw: time::Instant) -> time::Instant { - monotonize_impl(&MONO, raw) - } - - #[inline] - pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant { - let delta = raw.checked_sub_instant(&ZERO).unwrap(); - let secs = delta.as_secs(); - // occupies no more than 30 bits (10^9 seconds) - let nanos = delta.subsec_nanos() as u64; - - // This wraps around every 136 years (2^32 seconds). - // To detect backsliding we use wrapping arithmetic and declare forward steps smaller - // than 2^31 seconds as expected and everything else as a backslide which will be - // monotonized. - // This could be a problem for programs that call instants at intervals greater - // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true. - let packed = (secs << 32) | nanos; - let updated = mono.fetch_update(Relaxed, Relaxed, |old| { - (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed) - }); - match updated { - Ok(_) => raw, - Err(newer) => { - // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the - // passed in value and the 64bits loaded from the atomic - let seconds_lower = newer >> 32; - let mut seconds_upper = secs & 0xffff_ffff_0000_0000; - if secs & 0xffff_ffff > seconds_lower { - // Backslide caused the lower 32bit of the seconds part to wrap. - // This must be the case because the seconds part is larger even though - // we are in the backslide branch, i.e. the seconds count should be smaller or equal. - // - // We assume that backslides are smaller than 2^32 seconds - // which means we need to add 1 to the upper half to restore it. - // - // Example: - // most recent observed time: 0xA1_0000_0000_0000_0000u128 - // bits stored in AtomicU64: 0x0000_0000_0000_0000u64 - // backslide by 1s - // caller time is 0xA0_ffff_ffff_0000_0000u128 - // -> we can fix up the upper half time by adding 1 << 32 - seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000); - } - let secs = seconds_upper | seconds_lower; - let nanos = newer as u32; - ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() - } - } - } -} - -#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))] -pub mod inner { - use crate::sync::atomic::AtomicU128; - use crate::sync::atomic::Ordering::*; - use crate::sys::time; - use crate::time::Duration; - - const ZERO: time::Instant = time::Instant::zero(); - static MONO: AtomicU128 = AtomicU128::new(0); - - #[inline] - pub(super) fn monotonize(raw: time::Instant) -> time::Instant { - let delta = raw.checked_sub_instant(&ZERO).unwrap(); - // Split into seconds and nanos since Duration doesn't have a - // constructor that takes a u128 - let secs = delta.as_secs() as u128; - let nanos = delta.subsec_nanos() as u128; - let timestamp: u128 = secs << 64 | nanos; - let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp); - let secs = (timestamp >> 64) as u64; - let nanos = timestamp as u32; - ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() - } -} - -#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))] -pub mod inner { - use crate::cmp; - use crate::sys::time; - use crate::sys_common::mutex::StaticMutex; - - #[inline] - pub(super) fn monotonize(os_now: time::Instant) -> time::Instant { - static LOCK: StaticMutex = StaticMutex::new(); - static mut LAST_NOW: time::Instant = time::Instant::zero(); - unsafe { - let _lock = LOCK.lock(); - let now = cmp::max(LAST_NOW, os_now); - LAST_NOW = now; - now - } - } -} diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs index 7279925a6d0be..d1a69ff8697c6 100644 --- a/library/std/src/time/tests.rs +++ b/library/std/src/time/tests.rs @@ -90,10 +90,9 @@ fn instant_math_is_associative() { } #[test] -#[should_panic] -fn instant_duration_since_panic() { +fn instant_duration_since_saturates() { let a = Instant::now(); - let _ = (a - Duration::SECOND).duration_since(a); + assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO); } #[test] @@ -109,6 +108,7 @@ fn instant_checked_duration_since_nopanic() { #[test] fn instant_saturating_duration_since_nopanic() { let a = Instant::now(); + #[allow(deprecated, deprecated_in_future)] let ret = (a - Duration::SECOND).saturating_duration_since(a); assert_eq!(ret, Duration::ZERO); } @@ -192,31 +192,6 @@ fn since_epoch() { assert!(a < hundred_twenty_years); } -#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] -#[test] -fn monotonizer_wrapping_backslide() { - use super::monotonic::inner::{monotonize_impl, ZERO}; - use core::sync::atomic::AtomicU64; - - let reference = AtomicU64::new(0); - - let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) { - Some(time) => time, - None => { - // platform cannot represent u32::MAX seconds so it won't have to deal with this kind - // of overflow either - return; - } - }; - - let monotonized = monotonize_impl(&reference, time); - let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap(); - assert_eq!( - monotonized, expected, - "64bit monotonizer should handle overflows in the seconds part" - ); -} - macro_rules! bench_instant_threaded { ($bench_name:ident, $thread_count:expr) => { #[bench] From bda2693e9bcbf4246d1ada67886d9457054e3535 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 7 Jan 2022 10:50:15 +0100 Subject: [PATCH 32/34] Add caveat about the monotonicity guarantee by linking to the later section --- library/std/src/time.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 0d6ace7536bf4..e8512f0cbaa14 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -49,8 +49,8 @@ pub use core::time::FromFloatSecsError; /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with [`Duration`]. /// -/// Instants are always guaranteed to be no less than any previously measured -/// instant when created, and are often useful for tasks such as measuring +/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously +/// measured instant when created, and are often useful for tasks such as measuring /// benchmarks or timing how long an operation takes. /// /// Note, however, that instants are **not** guaranteed to be **steady**. In other @@ -83,6 +83,8 @@ pub use core::time::FromFloatSecsError; /// } /// ``` /// +/// [platform bugs]: Instant#monotonicity +/// /// # OS-specific behaviors /// /// An `Instant` is a wrapper around system-specific types and it may behave From 376d955a32e781c988af3a1cd2f7056f5da28cb5 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 7 Jan 2022 10:51:39 +0100 Subject: [PATCH 33/34] Add panic docs describing old, current and possible future behavior --- library/std/src/time.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index e8512f0cbaa14..4a65d612a6208 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -133,9 +133,12 @@ pub use core::time::FromFloatSecsError; /// if available, which is the case for all [tier 1] platforms. /// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization /// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks -/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. [`checked_duration_since`] can -/// be used to detect and handle situations where monotonicity is violated, or `Instant`s are -/// subtracted in the wrong order. +/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older rust versions this +/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations +/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order. +/// +/// This workaround obscures programming errors where earlier and later instants are accidentally +/// swapped. For this reason future rust versions may reintroduce panics. /// /// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html /// [`duration_since`]: Instant::duration_since @@ -271,6 +274,13 @@ impl Instant { /// Returns the amount of time elapsed from another instant to this one, /// or zero duration if that instant is later than this one. /// + /// # Panics + /// + /// Previous rust versions panicked when `earlier` was later than `self`. Currently this + /// method saturates. Future versions may reintroduce the panic in some circumstances. + /// See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity /// /// # Examples /// @@ -339,6 +349,14 @@ impl Instant { /// Returns the amount of time elapsed since this instant was created. /// + /// # Panics + /// + /// Previous rust versions panicked when self was earlier than the current time. Currently this + /// method returns a Duration of zero in that case. Future versions may reintroduce the panic. + /// See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity + /// /// # Examples /// /// ```no_run @@ -413,6 +431,16 @@ impl SubAssign for Instant { impl Sub for Instant { type Output = Duration; + /// Returns the amount of time elapsed from another instant to this one, + /// or zero duration if that instant is later than this one. + /// + /// # Panics + /// + /// Previous rust versions panicked when `other` was later than `self`. Currently this + /// method saturates. Future versions may reintroduce the panic in some circumstances. + /// See [Monotonicity]. + /// + /// [Monotonicity]: Instant#monotonicity fn sub(self, other: Instant) -> Duration { self.duration_since(other) } From 37a1fc542fbf8c11356d4395f28d4ab7f936945d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Feb 2022 12:17:38 -0800 Subject: [PATCH 34/34] Capitalize "Rust" Co-authored-by: Mark Rousskov --- library/std/src/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 4a65d612a6208..df8a726e64ecb 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -133,7 +133,7 @@ pub use core::time::FromFloatSecsError; /// if available, which is the case for all [tier 1] platforms. /// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization /// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks -/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older rust versions this +/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this /// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations /// where monotonicity is violated, or `Instant`s are subtracted in the wrong order. ///