diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 89b28aeda1c5e..c97c5c2077f85 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -337,7 +337,10 @@ impl AutoTraitFinder<'tcx> { &Err(SelectionError::Unimplemented) => { if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { already_visited.remove(&pred); - self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred)); + self.add_user_pred( + &mut user_computed_preds, + ty::Predicate::Trait(pred, ast::Constness::NotConst), + ); predicates.push_back(pred); } else { debug!( @@ -405,7 +408,7 @@ impl AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { match (&new_pred, old_pred) { - (&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => { + (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; let old_substs = old_trait.skip_binder().trait_ref.substs; @@ -627,7 +630,7 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match &predicate { - &ty::Predicate::Trait(p) => { + &ty::Predicate::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 5b804480119fe..84bfc86e6a94e 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -1,6 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use crate::ty::{self, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_hir::def_id::DefId; use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError}; @@ -33,7 +33,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }, ); } diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index db3173989ac60..2d02dbf823006 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -19,7 +19,9 @@ use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; use crate::ty::fold::TypeFolder; use crate::ty::SubtypePredicate; -use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{ + self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -130,7 +132,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error), + (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), _ => { // FIXME: make this work in other cases too. return false; @@ -138,7 +140,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) { - if let ty::Predicate::Trait(implication) = implication { + if let ty::Predicate::Trait(implication, _) = implication { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); // FIXME: I'm just not taking associated types at all here. @@ -530,7 +532,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { + ty::Predicate::Trait(ref trait_predicate, _) => { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { @@ -583,7 +585,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{}", message.unwrap_or_else(|| format!( "the trait bound `{}` is not satisfied{}", - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), post_message, )) ); @@ -695,7 +697,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_pred }); let unit_obligation = Obligation { - predicate: ty::Predicate::Trait(predicate), + predicate: ty::Predicate::Trait( + predicate, + ast::Constness::NotConst, + ), ..obligation.clone() }; if self.predicate_may_hold(&unit_obligation) { @@ -988,7 +993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> PredicateObligation<'tcx> { let new_trait_ref = ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.to_predicate()) + Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) } } @@ -1076,7 +1081,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let mut err = match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); @@ -1269,8 +1274,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) .value; - let obligation = - Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate()); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + cleaned_pred.without_const().to_predicate(), + ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index c09fd3079731c..9d8fa362ebbd9 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -6,7 +6,7 @@ use super::{ use crate::infer::InferCtxt; use crate::traits::object_safety::object_safety_violations; use crate::ty::TypeckTables; -use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, @@ -50,7 +50,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } else { " where" }, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), ), Applicability::MachineApplicable, ); @@ -340,8 +340,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); - let new_obligation = - Obligation::new(ObligationCause::dummy(), param_env, new_trait_ref.to_predicate()); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + new_trait_ref.without_const().to_predicate(), + ); if self.predicate_must_hold_modulo_regions(&new_obligation) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument @@ -1122,7 +1125,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // the type. The last generator has information about where the bound was introduced. At // least one generator should be present for this diagnostic to be modified. let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p) => { + ty::Predicate::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) } _ => (None, None), @@ -1545,7 +1548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required because it appears within the type `{}`", ty)); obligated_types.push(ty); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); if !self.is_recursive_obligation(obligated_types, &data.parent_code) { self.note_obligation_cause_code( err, @@ -1562,7 +1565,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { parent_trait_ref.print_only_trait_path(), parent_trait_ref.skip_binder().self_ty() )); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); self.note_obligation_cause_code( err, &parent_predicate, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9e5abc80822c7..1dbf53003585f 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -331,7 +331,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_obligation = obligation.with(data.clone()); if data.is_global() { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 2e5da2b038254..7819366f8927d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -29,7 +29,7 @@ use crate::mir::interpret::ErrorHandled; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness}; use crate::util::common::ErrorReported; use chalk_engine; use rustc_hir as hir; @@ -732,7 +732,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( param_env, cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), recursion_depth: 0, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let result = infcx.predicate_must_hold_modulo_regions(&obligation); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ce57fb8110496..15f81bb3f47ed 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -12,7 +12,7 @@ use super::elaborate_predicates; use crate::traits::{self, Obligation, ObligationCause}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -234,7 +234,7 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref)) .any(|predicate| { match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. data.skip_binder().input_types().skip(1).any(has_self_ty) } @@ -285,7 +285,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate_predicates(tcx, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred) => { + ty::Predicate::Trait(ref trait_pred, _) => { trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) } ty::Predicate::Projection(..) @@ -585,6 +585,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), } + .without_const() .to_predicate(); // U: Trait @@ -598,7 +599,7 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.to_predicate() + ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() }; let caller_bounds: Vec> = param_env @@ -620,6 +621,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), } + .without_const() .to_predicate(); Obligation::new(ObligationCause::dummy(), param_env, predicate) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 5bc211ade40ad..62672a7810480 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -16,7 +16,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -738,7 +738,12 @@ fn get_paranoid_cache_value_obligation<'a, 'tcx>( depth: usize, ) -> PredicateObligation<'tcx> { let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() } + Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.without_const().to_predicate(), + } } /// If we are projecting `::Item`, but `T: Trait` does not @@ -772,7 +777,7 @@ fn normalize_to_error<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index c0a0cbe9a3876..15870ec95d8d2 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -24,7 +24,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let Predicate::Trait(trait_ref) = key.value.predicate { + if let Predicate::Trait(trait_ref, _) = key.value.predicate { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized_def_id { if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3bfe542baabbf..ac1ca4db9d6bb 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -37,7 +37,7 @@ use crate::middle::lang_items; use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -51,7 +51,7 @@ use std::cmp; use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; -use syntax::attr; +use syntax::{ast, attr}; pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -718,7 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) @@ -945,7 +945,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // trait refs. This is important because it's only a cycle // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); + let cycle = cycle.map(|stack| { + ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst) + }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); Some(EvaluatedToOk) @@ -1060,7 +1062,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate { - ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()), + ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; debug!("coinductive_predicate({:?}) = {:?}", predicate, result); @@ -3366,7 +3368,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx.require_lang_item(lang_items::SizedTraitLangItem, None), tcx.mk_substs_trait(source, &[]), ); - nested.push(predicate_to_obligation(tr.to_predicate())); + nested.push(predicate_to_obligation(tr.without_const().to_predicate())); // If the type is `Foo + 'a`, ensure that the type // being cast to `Foo + 'a` outlives `'a`: diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index f058a4d2df24a..f3bd98b855190 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -4,7 +4,7 @@ use smallvec::SmallVec; use crate::ty::outlives::Component; use crate::ty::subst::{GenericArg, Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -13,8 +13,8 @@ use super::{Normalized, Obligation, ObligationCause, PredicateObligation, Select fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => { - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)) + ty::Predicate::Trait(ref data, constness) => { + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) } ty::Predicate::RegionOutlives(ref data) => { @@ -99,14 +99,14 @@ pub fn elaborate_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Elaborator<'tcx> { - elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) + elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) } pub fn elaborate_trait_refs<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect(); + let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); elaborate_predicates(tcx, predicates) } @@ -127,7 +127,7 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { let tcx = self.visited.tcx; match *predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -358,7 +358,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { let tcx = self.tcx; let trait_ref = item.trait_ref(); - let pred = trait_ref.to_predicate(); + let pred = trait_ref.without_const().to_predicate(); debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); @@ -370,13 +370,9 @@ impl<'tcx> TraitAliasExpander<'tcx> { // Don't recurse if this trait alias is already on the stack for the DFS search. let anon_pred = anonymize_predicate(tcx, &pred); - if item - .path - .iter() - .rev() - .skip(1) - .any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred) - { + if item.path.iter().rev().skip(1).any(|(tr, _)| { + anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred + }) { return false; } @@ -471,7 +467,7 @@ impl<'tcx, I: Iterator>> Iterator for FilterToTraits< fn next(&mut self) -> Option> { while let Some(pred) = self.base_iterator.next() { - if let ty::Predicate::Trait(data) = pred { + if let ty::Predicate::Trait(data, _) = pred { return Some(data.to_poly_trait_ref()); } } @@ -545,7 +541,12 @@ pub fn predicate_for_trait_ref<'tcx>( trait_ref: ty::TraitRef<'tcx>, recursion_depth: usize, ) -> PredicateObligation<'tcx> { - Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() } + Obligation { + cause, + param_env, + recursion_depth, + predicate: trait_ref.without_const().to_predicate(), + } } pub fn predicate_for_trait_def( diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index 869ba5315c1ae..a0cb8446c9217 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -3,7 +3,7 @@ use crate::infer::InferCtxt; use crate::middle::lang_items; use crate::traits::{self, AssocTypeBoundData}; use crate::ty::subst::SubstsRef; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Ident}; @@ -62,7 +62,7 @@ pub fn predicate_obligations<'a, 'tcx>( // (*) ok to skip binders, because wf code is prepared for it match *predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } ty::Predicate::RegionOutlives(..) => {} @@ -245,7 +245,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } } - ty::Predicate::Trait(proj) => { + ty::Predicate::Trait(proj, _) => { // An associated item obligation born out of the `trait` failed to be met. // Point at the `impl` that failed the obligation, the associated item that // needed to meet the obligation, and the definition of that associated item, @@ -350,7 +350,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.compute_trait_ref(&trait_ref, Elaborate::None); if !data.has_escaping_bound_vars() { - let predicate = trait_ref.to_predicate(); + let predicate = trait_ref.without_const().to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -378,7 +378,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; - self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + trait_ref.without_const().to_predicate(), + )); } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index b16db6ae5b18d..0dddca98c6257 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -150,6 +150,15 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } +impl TypeFoldable<'tcx> for syntax::ast::Constness { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// The `TypeFolder` trait defines the actual *folding*. There is a /// method defined for every foldable type. Each of these has a /// default implementation that does an "identity" fold. Within each diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3040ecf90ed53..0470ab20dc464 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -52,7 +52,7 @@ use std::ops::Deref; use std::ops::Range; use std::slice; use std::{mem, ptr}; -use syntax::ast::{self, Ident, Name, NodeId}; +use syntax::ast::{self, Constness, Ident, Name, NodeId}; use syntax::attr; pub use self::sty::BoundRegion::*; @@ -1068,7 +1068,11 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. - Trait(PolyTraitPredicate<'tcx>), + /// + /// A trait predicate will have `Constness::Const` if it originates + /// from a bound on a `const fn` without the `?const` opt-out (e.g., + /// `const fn foobar() {}`). + Trait(PolyTraitPredicate<'tcx>, Constness), /// `where 'a: 'b` RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), @@ -1191,8 +1195,8 @@ impl<'tcx> Predicate<'tcx> { let substs = &trait_ref.skip_binder().substs; match *self { - Predicate::Trait(ref binder) => { - Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs))) + Predicate::Trait(ref binder, constness) => { + Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } Predicate::Subtype(ref binder) => { Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) @@ -1336,15 +1340,33 @@ pub trait ToPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, + ) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, + ) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() })) + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) } } -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) } } @@ -1413,7 +1435,7 @@ impl<'tcx> Predicate<'tcx> { /// with depth 0 are bound by the predicate. pub fn walk_tys(&'a self) -> impl Iterator> + 'a { match *self { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { @@ -1439,7 +1461,7 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { - Predicate::Trait(ref t) => Some(t.to_poly_trait_ref()), + Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), Predicate::Projection(..) | Predicate::Subtype(..) | Predicate::RegionOutlives(..) @@ -1700,6 +1722,33 @@ impl<'tcx> ParamEnv<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ConstnessAnd { + pub constness: Constness, + pub value: T, +} + +// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that +// the constness of trait bounds is being propagated correctly. +pub trait WithConstness: Sized { + #[inline] + fn with_constness(self, constness: Constness) -> ConstnessAnd { + ConstnessAnd { constness, value: self } + } + + #[inline] + fn with_const(self) -> ConstnessAnd { + self.with_constness(Constness::Const) + } + + #[inline] + fn without_const(self) -> ConstnessAnd { + self.with_constness(Constness::NotConst) + } +} + +impl WithConstness for T {} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8b1b2bb586597..9091de55b7d8e 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1791,7 +1791,12 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match *self { - ty::Predicate::Trait(ref data) => p!(print(data)), + ty::Predicate::Trait(ref data, constness) => { + if let ast::Constness::Const = constness { + p!(write("const ")); + } + p!(print(data)) + } ty::Predicate::Subtype(ref predicate) => p!(print(predicate)), ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)), ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 62e895af7f355..25f9dc5b0c7bf 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -15,6 +15,7 @@ use smallvec::SmallVec; use std::fmt; use std::rc::Rc; use std::sync::Arc; +use syntax::ast; impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -234,7 +235,12 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> { impl fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Predicate::Trait(ref a) => a.fmt(f), + ty::Predicate::Trait(ref a, constness) => { + if let ast::Constness::Const = constness { + write!(f, "const ")?; + } + a.fmt(f) + } ty::Predicate::Subtype(ref pair) => pair.fmt(f), ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f), ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f), @@ -474,7 +480,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { - ty::Predicate::Trait(ref binder) => tcx.lift(binder).map(ty::Predicate::Trait), + ty::Predicate::Trait(ref binder, constness) => { + tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness)) + } ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype), ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 842361284823d..13f623aadb1a3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -12,7 +12,9 @@ use crate::mir::interpret::Scalar; use crate::mir::Promoted; use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; +use crate::ty::{ + self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, +}; use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; @@ -665,14 +667,16 @@ impl<'tcx> Binder> { pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match *self.skip_binder() { - ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), + ExistentialPredicate::Trait(tr) => { + Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() + } ExistentialPredicate::Projection(p) => { ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))) } ExistentialPredicate::AutoTrait(did) => { let trait_ref = Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); - trait_ref.to_predicate() + trait_ref.without_const().to_predicate() } } } diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 6da2d457f3c3b..c47a0f4eaca6c 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -67,9 +67,8 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { if let Some(hir_id) = item_hir_id { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl { ref of_trait, .. } = item.kind { - if of_trait.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); + if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind { + if constness == Constness::Const { this.lctx .diagnostic() .span_err(item.span, "const trait impls are not yet implemented"); @@ -366,6 +365,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unsafety, polarity, defaultness, + constness, generics: ref ast_generics, of_trait: ref trait_ref, self_ty: ref ty, @@ -422,6 +422,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unsafety, polarity, defaultness: self.lower_defaultness(defaultness, true /* [1] */), + constness, generics, of_trait: trait_ref, self_ty: lowered_ty, diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 76a0889c376a2..7163bf985ab97 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1250,10 +1250,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bounds = this.arena.alloc_from_iter(bounds.iter().filter_map( |bound| match *bound { - GenericBound::Trait(ref ty, TraitBoundModifier::None) => { + GenericBound::Trait(ref ty, TraitBoundModifier::None) + | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => { Some(this.lower_poly_trait_ref(ty, itctx.reborrow())) } - GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, + // `?const ?Bound` will cause an error during AST validation + // anyways, so treat it like `?Bound` as compilation proceeds. + GenericBound::Trait(_, TraitBoundModifier::Maybe) + | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + None + } GenericBound::Outlives(ref lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2158,10 +2164,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { - if p.trait_ref.constness.is_some() { - self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented"); - } - let bound_generic_params = self.lower_generic_params( &p.bound_generic_params, &NodeMap::default(), @@ -2300,7 +2302,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier { match f { TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, + TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, + + // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a + // placeholder for compilation to proceed. + TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { + hir::TraitBoundModifier::Maybe + } } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23701459025ae..9b71704f52d43 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -616,6 +616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness: _, + constness: _, generics: _, of_trait: Some(_), ref self_ty, @@ -649,6 +650,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness, + constness, generics: _, of_trait: None, self_ty: _, @@ -676,6 +678,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default") .emit(); } + if constness == Constness::Const { + self.err_handler() + .struct_span_err(item.span, "inherent impls cannot be `const`") + .note("only trait implementations may be annotated with `const`") + .emit(); + } } ItemKind::Fn(ref sig, ref generics, _) => { self.visit_fn_header(&sig.header); @@ -909,23 +917,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound) { - if let GenericBound::Trait(poly, maybe_bound) = bound { - match poly.trait_ref.constness { - Some(Constness::NotConst) => { - if *maybe_bound == TraitBoundModifier::Maybe { - self.err_handler() - .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); - } - - if let Some(ctx) = self.bound_context { - let msg = format!("`?const` is not permitted in {}", ctx.description()); - self.err_handler().span_err(bound.span(), &msg); - } + match bound { + GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { + if let Some(ctx) = self.bound_context { + let msg = format!("`?const` is not permitted in {}", ctx.description()); + self.err_handler().span_err(bound.span(), &msg); } + } - Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"), - None => {} + GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + self.err_handler() + .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); } + + _ => {} } visit::walk_param_bound(self, bound) diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index d346dbc8b4ee7..f8918016c1b98 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -709,6 +709,7 @@ impl<'a> TraitDef<'a> { unsafety, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, + constness: ast::Constness::NotConst, generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 9aa7623dc9f77..914dcdf196921 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -160,6 +160,7 @@ fn inject_impl_of_structural_trait( unsafety: ast::Unsafety::Normal, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, + constness: ast::Constness::NotConst, generics, of_trait: Some(trait_ref), self_ty: self_type, diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index bd3d6b589d00a..11f94ab2e6279 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -110,7 +110,7 @@ impl<'a> ExtCtxt<'a> { } pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { - ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID } + ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID } } pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef { diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 1fef871b5140e..b62a7e413e303 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -364,6 +364,7 @@ impl GenericArgs<'_> { pub enum TraitBoundModifier { None, Maybe, + MaybeConst, } /// The AST represents all type param bounds as types. @@ -2440,6 +2441,7 @@ pub enum ItemKind<'hir> { unsafety: Unsafety, polarity: ImplPolarity, defaultness: Defaultness, + constness: Constness, generics: Generics<'hir>, /// The trait being implemented, if any. diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 1a73e41db9da5..539a0eee0e312 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -570,6 +570,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { unsafety: _, defaultness: _, polarity: _, + constness: _, ref generics, ref of_trait, ref self_ty, diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index 6c7d419395317..b9598c9376146 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -631,6 +631,7 @@ impl<'a> State<'a> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -647,6 +648,10 @@ impl<'a> State<'a> { self.s.space(); } + if constness == ast::Constness::Const { + self.word_nbsp("const"); + } + if let hir::ImplPolarity::Negative = polarity { self.s.word("!"); } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 26cbda3d97895..15158c09af074 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in cx.tcx.predicates_of(def).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { + if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; let descr_pre = diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 947bbef4379f5..8f00801eb25a3 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -33,6 +33,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::{Span, DUMMY_SP}; +use syntax::ast; use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; @@ -1931,12 +1932,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { traits::ObligationCauseCode::RepeatVec(should_suggest), ), self.param_env, - ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate { - trait_ref: ty::TraitRef::new( - self.tcx().lang_items().copy_trait().unwrap(), - tcx.mk_substs_trait(ty, &[]), - ), - })), + ty::Predicate::Trait( + ty::Binder::bind(ty::TraitPredicate { + trait_ref: ty::TraitRef::new( + self.tcx().lang_items().copy_trait().unwrap(), + tcx.mk_substs_trait(ty, &[]), + ), + }), + ast::Constness::NotConst, + ), ), &traits::SelectionError::Unimplemented, false, @@ -2574,7 +2578,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) { self.prove_predicates( - Some(ty::Predicate::Trait(trait_ref.to_poly_trait_ref().to_poly_trait_predicate())), + Some(ty::Predicate::Trait( + trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), + ast::Constness::NotConst, + )), locations, category, ); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index d927553c72e8b..b047e534e4f1c 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::borrow::Cow; -use syntax::attr; +use syntax::{ast, attr}; type McfResult = Result<(), (Span, Cow<'static, str>)>; @@ -27,12 +27,19 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - bug!("closure kind predicate on function: {:#?}", predicate) } Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate), - Predicate::Trait(pred) => { + Predicate::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } match pred.skip_binder().self_ty().kind { ty::Param(ref p) => { + // Allow `T: ?const Trait` + if *constness == ast::Constness::NotConst + && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) + { + continue; + } + let generics = tcx.generics_of(current); let def = generics.type_param(p, tcx); let span = tcx.def_span(def.def_id); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 1921a6c850689..43495da192839 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_error_codes::*; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey}; -use rustc_span::source_map::{self, respan, Span, Spanned}; +use rustc_span::source_map::{self, respan, Span}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; @@ -566,9 +566,9 @@ impl<'a> Parser<'a> { let constness = if self.eat_keyword(kw::Const) { let span = self.prev_span; self.sess.gated_spans.gate(sym::const_trait_impl, span); - Some(respan(span, Constness::Const)) + Constness::Const } else { - None + Constness::NotConst }; // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. @@ -631,13 +631,13 @@ impl<'a> Parser<'a> { err_path(ty_first.span) } }; - let constness = constness.map(|c| c.node); - let trait_ref = TraitRef { path, constness, ref_id: ty_first.id }; + let trait_ref = TraitRef { path, ref_id: ty_first.id }; ItemKind::Impl { unsafety, polarity, defaultness, + constness, generics, of_trait: Some(trait_ref), self_ty: ty_second, @@ -645,18 +645,12 @@ impl<'a> Parser<'a> { } } None => { - // Reject `impl const Type {}` here - if let Some(Spanned { node: Constness::Const, span }) = constness { - self.struct_span_err(span, "`const` cannot modify an inherent impl") - .help("only a trait impl can be `const`") - .emit(); - } - // impl Type ItemKind::Impl { unsafety, polarity, defaultness, + constness, generics, of_trait: None, self_ty: ty_first, diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 065a3b14428c7..efd8acc933aa8 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -27,10 +27,12 @@ struct BoundModifiers { } impl BoundModifiers { - fn trait_bound_modifier(&self) -> TraitBoundModifier { - match self.maybe { - Some(_) => TraitBoundModifier::Maybe, - None => TraitBoundModifier::None, + fn to_trait_bound_modifier(&self) -> TraitBoundModifier { + match (self.maybe, self.maybe_const) { + (None, None) => TraitBoundModifier::None, + (Some(_), None) => TraitBoundModifier::Maybe, + (None, Some(_)) => TraitBoundModifier::MaybeConst, + (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe, } } } @@ -215,7 +217,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, TyKind> { assert_ne!(self.token, token::Question); - let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span)); + let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded @@ -557,9 +559,9 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; } - let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst); - let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span)); - Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier())) + let modifier = modifiers.to_trait_bound_modifier(); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + Ok(GenericBound::Trait(poly_trait, modifier)) } /// Optionally parses `for<$generic_params>`. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 90a422a4dcf6c..a914537d13408 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -93,7 +93,7 @@ where let ty::GenericPredicates { parent: _, predicates } = predicates; for (predicate, _span) in predicates { match predicate { - ty::Predicate::Trait(poly_predicate) => { + ty::Predicate::Trait(poly_predicate, _) => { let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder(); if self.visit_trait(trait_ref) { return true; @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // The traits' privacy in bodies is already checked as a part of trait object types. let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref); - for (trait_predicate, _) in bounds.trait_bounds { + for (trait_predicate, _, _) in bounds.trait_bounds { if self.visit_trait(*trait_predicate.skip_binder()) { return; } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 779d3f55018d5..a9d2bfabb1ba6 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -486,6 +486,7 @@ impl Sig for ast::Item { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -499,6 +500,9 @@ impl Sig for ast::Item { text.push_str("unsafe "); } text.push_str("impl"); + if constness == ast::Constness::Const { + text.push_str(" const"); + } let generics_sig = generics.make(offset + text.len(), id, scx)?; text.push_str(&generics_sig.text); diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 4b4fa4b7147fc..b77c603da9a74 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -94,7 +94,7 @@ impl<'tcx> Lower> for ty::Predicate<'tcx> { use rustc::ty::Predicate; match self { - Predicate::Trait(predicate) => predicate.lower(), + Predicate::Trait(predicate, _) => predicate.lower(), Predicate::RegionOutlives(predicate) => predicate.lower(), Predicate::TypeOutlives(predicate) => predicate.lower(), Predicate::Projection(predicate) => predicate.lower(), diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index d47e54366b550..8b62403e6ce52 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -2,7 +2,7 @@ use rustc::hir::map as hir_map; use rustc::session::CrateDisambiguator; use rustc::traits::{self}; use rustc::ty::subst::Subst; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -58,6 +58,7 @@ fn sized_constraint_for_ty(tcx: TyCtxt<'tcx>, adtdef: &ty::AdtDef, ty: Ty<'tcx>) def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]), }) + .without_const() .to_predicate(); let predicates = tcx.predicates_of(adtdef.did).predicates; if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 173bb29e964d1..9397d183493b1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3,6 +3,8 @@ //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an //! instance of `AstConv`. +// ignore-tidy-filelength + use crate::collect::PlaceholderHirTyCollector; use crate::lint; use crate::middle::lang_items::SizedTraitLangItem; @@ -17,7 +19,7 @@ use rustc::traits::astconv_object_safety_violations; use rustc::traits::error_reporting::report_object_safety_error; use rustc::traits::wf::object_region_bounds; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId}; @@ -31,7 +33,7 @@ use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use smallvec::SmallVec; -use syntax::ast; +use syntax::ast::{self, Constness}; use syntax::util::lev_distance::find_best_match_for_name; use std::collections::BTreeSet; @@ -49,6 +51,8 @@ pub trait AstConv<'tcx> { fn item_def_id(&self) -> Option; + fn default_constness_for_trait_bounds(&self) -> Constness; + /// Returns predicates in scope of the form `X: Foo`, where `X` is /// a type parameter `X` with the given id `def_id`. This is a /// subset of the full set of predicates. @@ -919,6 +923,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, trait_ref: &hir::TraitRef<'_>, span: Span, + constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, @@ -947,7 +952,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - bounds.trait_bounds.push((poly_trait_ref, span)); + bounds.trait_bounds.push((poly_trait_ref, span, constness)); let mut dup_bindings = FxHashMap::default(); for binding in &assoc_bindings { @@ -993,12 +998,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn instantiate_poly_trait_ref( &self, poly_trait_ref: &hir::PolyTraitRef<'_>, + constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, ) -> Option> { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, + constness, self_ty, bounds, false, @@ -1181,18 +1188,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut trait_bounds = Vec::new(); let mut region_bounds = Vec::new(); + let constness = self.default_constness_for_trait_bounds(); for ast_bound in ast_bounds { match *ast_bound { hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push(b) + trait_bounds.push((b, constness)) + } + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { + trait_bounds.push((b, Constness::NotConst)) } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::Outlives(ref l) => region_bounds.push(l), } } - for bound in trait_bounds { - let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds); + for (bound, constness) in trait_bounds { + let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds); } bounds.region_bounds.extend( @@ -1226,7 +1237,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut bounds = Bounds::default(); self.add_bounds(param_ty, ast_bounds, &mut bounds); - bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id()); + bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } @@ -1417,15 +1428,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - let cur_potential_assoc_types = - self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds); + let cur_potential_assoc_types = self.instantiate_poly_trait_ref( + trait_bound, + Constness::NotConst, + dummy_self, + &mut bounds, + ); potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten()); } // Expand trait aliases recursively and check that only one regular (non-auto) trait // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned()); + let expanded_traits = traits::expand_trait_aliases( + tcx, + bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)), + ); let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); if regular_traits.len() > 1 { @@ -1481,16 +1498,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let regular_traits_refs_spans = bounds .trait_bounds .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, ast::Constness::NotConst); - for (base_trait_ref, span) in regular_traits_refs_spans { for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { debug!( "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref ); match trait_ref { - ty::Predicate::Trait(pred) => { + ty::Predicate::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) .filter(|item| item.kind == ty::AssocKind::Type) @@ -2949,7 +2968,7 @@ pub struct Bounds<'tcx> { /// A list of trait bounds. So if you had `T: Debug` this would be /// `T: Debug`. Note that the self-type is explicit here. - pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>, + pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>, /// A list of projection equality bounds. So if you had `T: /// Iterator` this would include ` Bounds<'tcx> { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]), }); - (trait_ref.to_predicate(), span) + (trait_ref.without_const().to_predicate(), span) }) }); @@ -2997,11 +3016,10 @@ impl<'tcx> Bounds<'tcx> { let outlives = ty::OutlivesPredicate(param_ty, region_bound); (ty::Binder::bind(outlives).to_predicate(), span) }) - .chain( - self.trait_bounds - .iter() - .map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)), - ) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(); + (predicate, span) + })) .chain( self.projection_bounds .iter() diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 8d6b74c3015c9..367fe0c3cc199 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -5,7 +5,7 @@ use rustc::infer::{InferCtxt, InferOk}; use rustc::session::DiagnosticMessageId; use rustc::traits::{self, TraitEngine}; use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; -use rustc::ty::{self, TraitRef, Ty, TyCtxt}; +use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -124,8 +124,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let obligation = - traits::Obligation::new(cause.clone(), self.param_env, trait_ref.to_predicate()); + let obligation = traits::Obligation::new( + cause.clone(), + self.param_env, + trait_ref.without_const().to_predicate(), + ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a32fbff7bfe2d..087b720a2f4c4 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -565,7 +565,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => { if unsize_did == tr.def_id() { let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; if let ty::Tuple(..) = sty { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88e7a265ebbcf..a88dca008d751 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -234,7 +234,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate, p) { - (Predicate::Trait(a), Predicate::Trait(b)) => relator.relate(a, b).is_ok(), + (Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(), (Predicate::Projection(a), Predicate::Projection(b)) => { relator.relate(a, b).is_ok() } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 636ea5b87d659..2012a2a1526b1 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate_predicates(self.tcx, predicates.predicates.clone()) .filter_map(|predicate| match predicate { - ty::Predicate::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => { + ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { Some(trait_pred) } _ => None, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 711c285d17e88..c1cf3522b5d9c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -17,7 +17,7 @@ use rustc::traits; use rustc::ty::subst::Subst; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::GenericParamDefKind; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.to_predicate(), + poly_trait_ref.without_const().to_predicate(), ); // Now we want to know if this can be matched diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b2542cc27a551..ff2f150c63330 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -25,6 +25,7 @@ use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::GenericParamDefKind; use rustc::ty::{ self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, + WithConstness, }; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; @@ -826,7 +827,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // FIXME: do we want to commit to this behavior for param bounds? let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate { - ty::Predicate::Trait(ref trait_predicate) => { + ty::Predicate::Trait(ref trait_predicate, _) => { match trait_predicate.skip_binder().trait_ref.self_ty().kind { ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()), _ => None, @@ -1396,7 +1397,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } TraitCandidate(trait_ref) => { - let predicate = trait_ref.to_predicate(); + let predicate = trait_ref.without_const().to_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { @@ -1430,7 +1431,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - if let &ty::Predicate::Trait(ref pred) = &o.predicate { + if let &ty::Predicate::Trait(ref pred, _) = &o.predicate { possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d6c0d9c77b495..35fffd3bcd45c 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -9,7 +9,7 @@ use rustc::hir::map::Map; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::Obligation; use rustc::ty::print::with_crate_prefix; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -59,7 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.to_predicate(), + poly_trait_ref.without_const().to_predicate(), ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4affdc4a9d64e..5e1b3a76fd28f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,6 +90,7 @@ pub mod writeback; use crate::astconv::{AstConv, PathSeg}; use crate::middle::lang_items; use crate::namespace::Namespace; +use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -112,7 +113,7 @@ use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSel use rustc::ty::util::{Discr, IntTypeExt, Representability}; use rustc::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, + ToPredicate, Ty, TyCtxt, UserType, WithConstness, }; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -1423,7 +1424,7 @@ fn check_fn<'a, 'tcx>( inherited.register_predicate(traits::Obligation::new( cause, param_env, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), )); } } @@ -2612,6 +2613,16 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { None } + fn default_constness_for_trait_bounds(&self) -> ast::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + ast::Constness::NotConst + } + } + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); @@ -2623,7 +2634,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { parent: None, predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map( |&predicate| match predicate { - ty::Predicate::Trait(ref data) + ty::Predicate::Trait(ref data, _) if data.skip_binder().self_ty().is_param(index) => { // HACK(eddyb) should get the original `Span`. @@ -3695,7 +3706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Predicate::Projection(ref data) => { Some((data.to_poly_trait_ref(self.tcx), obligation)) } - ty::Predicate::Trait(ref data) => Some((data.to_poly_trait_ref(), obligation)), + ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)), ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, @@ -3998,7 +4009,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - if let ty::Predicate::Trait(predicate) = error.obligation.predicate { + if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. let mut referenced_in = final_arg_types @@ -4042,7 +4053,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::Path(qpath) = &path.kind { if let hir::QPath::Resolved(_, path) = &qpath { for error in errors { - if let ty::Predicate::Trait(predicate) = error.obligation.predicate { + if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { // If any of the type arguments in this path segment caused the // `FullfillmentError`, point at its span (#61860). for arg in path diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 5e91e98a7dfa5..e4df69993c5d2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -6,7 +6,9 @@ use rustc::middle::lang_items; use rustc::session::parse::feature_err; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{ + self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir::def_id::DefId; @@ -955,7 +957,8 @@ fn receiver_is_implemented( substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), }; - let obligation = traits::Obligation::new(cause, fcx.param_env, trait_ref.to_predicate()); + let obligation = + traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate()); if fcx.predicate_must_hold_modulo_regions(&obligation) { true diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a03b9f747372e..45d969a3d574f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -20,6 +20,7 @@ use crate::constrained_generic_params as cgp; use crate::lint; use crate::middle::resolve_lifetime as rl; use crate::middle::weak_lang_items; +use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::mir::mono::Linkage; @@ -30,7 +31,7 @@ use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; @@ -288,6 +289,22 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { Some(self.item_def_id) } + fn default_constness_for_trait_bounds(&self) -> ast::Constness { + // FIXME: refactor this into a method + let hir_id = self + .tcx + .hir() + .as_local_hir_id(self.item_def_id) + .expect("Non-local call to local provider is_const_fn"); + + let node = self.tcx.hir().get(hir_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + ast::Constness::NotConst + } + } + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id)) } @@ -411,7 +428,8 @@ fn type_param_predicates( // Implied `Self: Trait` and supertrait bounds. if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); - extend = Some((identity_trait_ref.to_predicate(), item.span)); + extend = + Some((identity_trait_ref.without_const().to_predicate(), item.span)); } generics } @@ -432,7 +450,7 @@ fn type_param_predicates( icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) .into_iter() .filter(|(predicate, _)| match predicate { - ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index), + ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index), _ => false, }), ); @@ -453,6 +471,7 @@ impl ItemCtxt<'tcx> { ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, ) -> Vec<(ty::Predicate<'tcx>, Span)> { + let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics .params .iter() @@ -461,7 +480,7 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) - .flat_map(|b| predicates_from_bound(self, ty, b)); + .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics .where_clause @@ -481,7 +500,7 @@ impl ItemCtxt<'tcx> { }; bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) - .flat_map(|(bt, b)| predicates_from_bound(self, bt, b)); + .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } @@ -857,7 +876,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi // which will, in turn, reach indirect supertraits. for &(pred, span) in superbounds { debug!("superbound: {:?}", pred); - if let ty::Predicate::Trait(bound) = pred { + if let ty::Predicate::Trait(bound, _) = pred { tcx.at(span).super_predicates_of(bound.def_id()); } } @@ -2056,7 +2075,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { let span = tcx.def_span(def_id); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(), + ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(), span, )))); } @@ -2106,6 +2125,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); + let constness = icx.default_constness_for_trait_bounds(); const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); @@ -2230,7 +2250,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.push((trait_ref.to_poly_trait_ref().to_predicate(), tcx.def_span(def_id))); + predicates.push(( + trait_ref.to_poly_trait_ref().without_const().to_predicate(), + tcx.def_span(def_id), + )); } // Collect the region predicates that were declared inline as @@ -2304,11 +2327,18 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat for bound in bound_pred.bounds.iter() { match bound { - &hir::GenericBound::Trait(ref poly_trait_ref, _) => { + &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::None => constness, + hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"), + }; + let mut bounds = Bounds::default(); let _ = AstConv::instantiate_poly_trait_ref( &icx, poly_trait_ref, + constness, ty, &mut bounds, ); @@ -2484,11 +2514,18 @@ fn predicates_from_bound<'tcx>( astconv: &dyn AstConv<'tcx>, param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, + constness: ast::Constness, ) -> Vec<(ty::Predicate<'tcx>, Span)> { match *bound { - hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => { + hir::GenericBound::Trait(ref tr, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::Maybe => return vec![], + hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::None => constness, + }; + let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds); + let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); bounds.predicates(astconv.tcx(), param_ty) } hir::GenericBound::Outlives(ref lifetime) => { @@ -2496,7 +2533,6 @@ fn predicates_from_bound<'tcx>( let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)] } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![], } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 95cd3c631ed22..b3cf5f21fab9b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -382,6 +382,7 @@ pub fn hir_trait_to_predicates<'tcx>( &item_cx, hir_trait, DUMMY_SP, + syntax::ast::Constness::NotConst, tcx.types.err, &mut bounds, true, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index f37f6921cebaf..27f8059691a14 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .filter(|p| { !orig_bounds.contains(p) || match p { - &&ty::Predicate::Trait(pred) => pred.def_id() == sized_trait, + ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait, _ => false, } }) diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 525b1b2e6ecf7..18ebd254507ea 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,7 +1,7 @@ use rustc::infer::InferOk; use rustc::traits; use rustc::ty::subst::Subst; -use rustc::ty::ToPredicate; +use rustc::ty::{ToPredicate, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_span::DUMMY_SP; @@ -64,7 +64,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { match infcx.evaluate_obligation(&traits::Obligation::new( cause, param_env, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), )) { Ok(eval_result) => eval_result.may_apply(), Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20a5a6c54984d..7a7d69c68a585 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -482,7 +482,7 @@ impl<'a> Clean> for ty::Predicate<'a> { use rustc::ty::Predicate; match *self { - Predicate::Trait(ref pred) => Some(pred.clean(cx)), + Predicate::Trait(ref pred, _) => Some(pred.clean(cx)), Predicate::Subtype(ref pred) => Some(pred.clean(cx)), Predicate::RegionOutlives(ref pred) => pred.clean(cx), Predicate::TypeOutlives(ref pred) => pred.clean(cx), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index c7b12d38c430a..2b59c60f0b77f 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -141,7 +141,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::Predicate::Trait(ref pred) = *pred { + if let ty::Predicate::Trait(ref pred, _) = *pred { if pred.skip_binder().trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 178ba69277233..218674b757f39 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -203,6 +203,7 @@ pub struct Impl<'hir> { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, pub defaultness: hir::Defaultness, + pub constness: ast::Constness, pub generics: &'hir hir::Generics<'hir>, pub trait_: &'hir Option>, pub for_: &'hir hir::Ty<'hir>, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6434dccdfc75b..79923fc3d3689 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -361,6 +361,7 @@ impl clean::GenericBound { let modifier_str = match modifier { hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::Maybe => "?", + hir::TraitBoundModifier::MaybeConst => "?const", }; if f.alternate() { write!(f, "{}{:#}", modifier_str, ty.print()) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index fdff18779e795..d3d45ccccad36 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -562,6 +562,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, self_ty, @@ -576,6 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { unsafety, polarity, defaultness, + constness, generics, trait_: of_trait, for_: self_ty, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a5a4eb1583bed..5f38ac4cc0f42 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -266,12 +266,24 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0); /// small, positive ids. pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; -/// A modifier on a bound, currently this is only used for `?Sized`, where the -/// modifier is `Maybe`. Negative bounds should also be handled here. +/// A modifier on a bound, e.g., `?Sized` or `?const Trait`. +/// +/// Negative bounds should also be handled here. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] pub enum TraitBoundModifier { + /// No modifiers None, + + /// `?Trait` Maybe, + + /// `?const Trait` + MaybeConst, + + /// `?const ?Trait` + // + // This parses but will be rejected during AST validation. + MaybeConstMaybe, } /// The AST represents all type param bounds as types. @@ -1033,7 +1045,7 @@ impl Expr { pub fn to_bound(&self) -> Option { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( - PolyTraitRef::new(Vec::new(), path.clone(), None, self.span), + PolyTraitRef::new(Vec::new(), path.clone(), self.span), TraitBoundModifier::None, )), _ => None, @@ -2158,7 +2170,8 @@ impl IsAsync { } } -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(HashStable_Generic)] pub enum Constness { Const, NotConst, @@ -2376,15 +2389,6 @@ pub enum AttrKind { pub struct TraitRef { pub path: Path, pub ref_id: NodeId, - - /// The `const` modifier, if any, that appears before this trait. - /// - /// | | `constness` | - /// |----------------|-----------------------------| - /// | `Trait` | `None` | - /// | `const Trait` | `Some(Constness::Const)` | - /// | `?const Trait` | `Some(Constness::NotConst)` | - pub constness: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2399,15 +2403,10 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new( - generic_params: Vec, - path: Path, - constness: Option, - span: Span, - ) -> Self { + pub fn new(generic_params: Vec, path: Path, span: Span) -> Self { PolyTraitRef { bound_generic_params: generic_params, - trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID }, + trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, span, } } @@ -2618,6 +2617,7 @@ pub enum ItemKind { unsafety: Unsafety, polarity: ImplPolarity, defaultness: Defaultness, + constness: Constness, generics: Generics, /// The trait being implemented, if any. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 750d054e8a0f2..4a460c5d7b24c 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -838,8 +838,7 @@ pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut } } -pub fn noop_visit_trait_ref(tr: &mut TraitRef, vis: &mut T) { - let TraitRef { path, ref_id, constness: _ } = tr; +pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { vis.visit_path(path); vis.visit_id(ref_id); } @@ -922,6 +921,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { unsafety: _, polarity: _, defaultness: _, + constness: _, generics, of_trait, self_ty, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bc67980c454c0..3927e4f903011 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1230,6 +1230,7 @@ impl<'a> State<'a> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -1240,6 +1241,7 @@ impl<'a> State<'a> { self.print_defaultness(defaultness); self.print_unsafety(unsafety); self.word_nbsp("impl"); + self.print_constness(constness); if !generics.params.is_empty() { self.print_generic_params(&generics.params); @@ -2773,6 +2775,13 @@ impl<'a> State<'a> { } } + crate fn print_constness(&mut self, s: ast::Constness) { + match s { + ast::Constness::Const => self.word_nbsp("const"), + ast::Constness::NotConst => {} + } + } + crate fn print_is_auto(&mut self, s: ast::IsAuto) { match s { ast::IsAuto::Yes => self.word_nbsp("auto"), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d03a9dfc16758..946a0d29cd399 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -312,6 +312,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { unsafety: _, polarity: _, defaultness: _, + constness: _, ref generics, ref of_trait, ref self_ty, diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 0bf337ad08dbf..e4f4d4262b64d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,8 +1,8 @@ -error: `?const` on trait bounds is not yet implemented - --> $DIR/feature-gate.rs:11:29 +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:16:1 | -LL | const fn get_assoc_const() -> i32 { ::CONST } - | ^^^^^^^^ +LL | fn main() {} + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index cf1ed30da0fcc..d600b53e44875 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -3,6 +3,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] +#![feature(rustc_attrs)] trait T { const CONST: i32; @@ -10,6 +11,6 @@ trait T { const fn get_assoc_const() -> i32 { ::CONST } //[stock]~^ ERROR `?const` on trait bounds is experimental -//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented -fn main() {} +#[rustc_error] +fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index 64388004b5b72..fbd3840cb1d2b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:11:29 + --> $DIR/feature-gate.rs:12:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ @@ -7,12 +7,6 @@ LL | const fn get_assoc_const() -> i32 { ::CONST } = note: for more information, see https://github.com/rust-lang/rust/issues/67794 = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable -error: `?const` on trait bounds is not yet implemented - --> $DIR/feature-gate.rs:11:29 - | -LL | const fn get_assoc_const() -> i32 { ::CONST } - | ^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs index e4e6bedd93746..f5561a922ddcd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs @@ -8,18 +8,14 @@ impl T for S {} fn rpit() -> impl ?const T { S } //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn apit(_: impl ?const T) {} //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn apit_assoc_bound(_: impl IntoIterator) {} //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr index f4abd4b714e8a..06cd00a956a2d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr @@ -5,46 +5,22 @@ LL | fn rpit() -> impl ?const T { S } | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:13:17 + --> $DIR/in-impl-trait.rs:12:17 | LL | fn apit(_: impl ?const T) {} | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:17:50 + --> $DIR/in-impl-trait.rs:15:50 | LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:21:48 + --> $DIR/in-impl-trait.rs:18:48 | LL | fn apit_assoc_bound(_: impl IntoIterator) {} | ^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:9:19 - | -LL | fn rpit() -> impl ?const T { S } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:13:17 - | -LL | fn apit(_: impl ?const T) {} - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:17:50 - | -LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:21:48 - | -LL | fn apit_assoc_bound(_: impl IntoIterator) {} - | ^^^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs index 4523b46bc51f6..fc9ed5b1dc22e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs @@ -4,6 +4,5 @@ trait Super {} trait T: ?const Super {} //~^ ERROR `?const` is not permitted in supertraits -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr index 8003361be7d2e..a0d8f95acd2a8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr @@ -4,11 +4,5 @@ error: `?const` is not permitted in supertraits LL | trait T: ?const Super {} | ^^^^^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-bounds.rs:5:10 - | -LL | trait T: ?const Super {} - | ^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs index 6cfca71548674..b3d1f48ace147 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs @@ -9,14 +9,11 @@ impl T for S {} // An inherent impl for the trait object `?const T`. impl ?const T {} //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn trait_object() -> &'static dyn ?const T { &S } //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn trait_object_in_apit(_: impl IntoIterator>) {} //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr index c059f16902250..331fe0423fa94 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr @@ -5,34 +5,16 @@ LL | impl ?const T {} | ^^^^^^^^ error: `?const` is not permitted in trait objects - --> $DIR/in-trait-object.rs:14:35 + --> $DIR/in-trait-object.rs:13:35 | LL | fn trait_object() -> &'static dyn ?const T { &S } | ^^^^^^^^ error: `?const` is not permitted in trait objects - --> $DIR/in-trait-object.rs:18:61 + --> $DIR/in-trait-object.rs:16:61 | LL | fn trait_object_in_apit(_: impl IntoIterator>) {} | ^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:10:6 - | -LL | impl ?const T {} - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:14:35 - | -LL | fn trait_object() -> &'static dyn ?const T { &S } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:18:61 - | -LL | fn trait_object_in_apit(_: impl IntoIterator>) {} - | ^^^^^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs index 425784f4e4326..c2c8689e2942b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs @@ -3,6 +3,5 @@ struct S(std::marker::PhantomData); //~^ ERROR `?const` and `?` are mutually exclusive -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr index 44f6d464ae6a8..e8e9d6c1e7621 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr @@ -4,11 +4,5 @@ error: `?const` and `?` are mutually exclusive LL | struct S(std::marker::PhantomData); | ^^^^^^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/with-maybe-sized.rs:4:13 - | -LL | struct S(std::marker::PhantomData); - | ^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs index 9cffe75addd63..7f064c0c53ade 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z parse-only - #![feature(const_trait_impl)] #![feature(const_trait_bound_opt_out)] #![allow(incomplete_features)] @@ -8,7 +6,12 @@ struct S; trait T {} +impl const S {} +//~^ ERROR inherent impls cannot be `const` +//~| ERROR const trait impls are not yet implemented + impl const T {} -//~^ ERROR `const` cannot modify an inherent impl +//~^ ERROR inherent impls cannot be `const` +//~| ERROR const trait impls are not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr index 1d24557655951..508c6f4c747e1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -1,10 +1,30 @@ -error: `const` cannot modify an inherent impl - --> $DIR/inherent-impl.rs:11:6 +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:9:1 + | +LL | impl const S {} + | ^^^^^^^^^^^^^^^ + | + = note: only trait implementations may be annotated with `const` + +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:13:1 | LL | impl const T {} - | ^^^^^ + | ^^^^^^^^^^^^^^^ + | + = note: only trait implementations may be annotated with `const` + +error: const trait impls are not yet implemented + --> $DIR/inherent-impl.rs:9:1 + | +LL | impl const S {} + | ^^^^^^^^^^^^^^^ + +error: const trait impls are not yet implemented + --> $DIR/inherent-impl.rs:13:1 | - = help: only a trait impl can be `const` +LL | impl const T {} + | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 4 previous errors