diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 6f1bbe60569fd..c0b14352b7d1a 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -100,11 +100,17 @@ LLVM. However, the approximation is usually reliable. The following table shows known good combinations of toolchain versions. -| | Clang 7 | Clang 8 | -|-----------|-----------|-----------| -| Rust 1.34 | ✗ | ✓ | -| Rust 1.35 | ✗ | ✓ | -| Rust 1.36 | ✗ | ✓ | -| Rust 1.37 | ✗ | ✓ | +| | Clang 7 | Clang 8 | Clang 9 | +|-----------|-----------|-----------|-----------| +| Rust 1.34 | ✗ | ✓ | ✗ | +| Rust 1.35 | ✗ | ✓ | ✗ | +| Rust 1.36 | ✗ | ✓ | ✗ | +| Rust 1.37 | ✗ | ✓ | ✗ | +| Rust 1.38 | ✗ | ✗ | ✓ | +| Rust 1.39 | ✗ | ✗ | ✓ | +| Rust 1.40 | ✗ | ✗ | ✓ | +| Rust 1.41 | ✗ | ✗ | ✓ | +| Rust 1.42 | ✗ | ✗ | ✓ | +| Rust 1.43 | ✗ | ✗ | ✓ | Note that the compatibility policy for this feature might change in the future. diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index de93baff79beb..c7a7cf89b4f1b 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt}; use std::fmt::Debug; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { @@ -671,6 +671,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { }); } + fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) { + span_bug!( + self.cause.span(self.infcx.tcx), + "lazy_normalization_consts: unreachable `const_equate`" + ); + } + fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index d4af470499670..3467457b44997 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -39,7 +39,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -126,7 +126,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> where - R: TypeRelation<'tcx>, + R: ConstEquateRelation<'tcx>, { debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); if a == b { @@ -164,7 +164,22 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { return self.unify_const_variable(!a_is_expected, vid, a); } - + (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { + // FIXME(#59490): Need to remove the leak check to accomodate + // escaping bound variables here. + if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { + relation.const_equate_obligation(a, b); + } + return Ok(b); + } + (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => { + // FIXME(#59490): Need to remove the leak check to accomodate + // escaping bound variables here. + if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { + relation.const_equate_obligation(a, b); + } + return Ok(a); + } _ => {} } @@ -375,6 +390,20 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf); Ok(Generalization { ty, needs_wf }) } + + pub fn add_const_equate_obligation( + &mut self, + a_is_expected: bool, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) { + let predicate = if a_is_expected { + ty::Predicate::ConstEquate(a, b) + } else { + ty::Predicate::ConstEquate(b, a) + }; + self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate)); + } } struct Generalizer<'cx, 'tcx> { @@ -637,11 +666,19 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } + ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c), _ => relate::super_relate_consts(self, c, c), } } } +pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> { + /// Register an obligation that both constants must be equal to each other. + /// + /// If they aren't equal then the relation doesn't hold. + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); +} + pub trait RelateResultCompare<'tcx, T> { fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index d054070e292fa..e3cafb82719dd 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -1,4 +1,4 @@ -use super::combine::{CombineFields, RelationDir}; +use super::combine::{CombineFields, ConstEquateRelation, RelationDir}; use super::Subtype; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -140,3 +140,9 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { } } } + +impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> { + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + self.fields.add_const_equate_obligation(self.a_is_expected, a, b); + } +} diff --git a/src/librustc_infer/infer/glb.rs b/src/librustc_infer/infer/glb.rs index f95d74a9340c9..ec219a95b9441 100644 --- a/src/librustc_infer/infer/glb.rs +++ b/src/librustc_infer/infer/glb.rs @@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir}; use super::InferCtxt; use super::Subtype; +use crate::infer::combine::ConstEquateRelation; use crate::traits::ObligationCause; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -116,3 +117,9 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, Ok(()) } } + +impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> { + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + self.fields.add_const_equate_obligation(self.a_is_expected, a, b); + } +} diff --git a/src/librustc_infer/infer/lub.rs b/src/librustc_infer/infer/lub.rs index 492f2b229d36d..a0453db2cb499 100644 --- a/src/librustc_infer/infer/lub.rs +++ b/src/librustc_infer/infer/lub.rs @@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir}; use super::InferCtxt; use super::Subtype; +use crate::infer::combine::ConstEquateRelation; use crate::traits::ObligationCause; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -100,6 +101,12 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { } } +impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> { + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + self.fields.add_const_equate_obligation(self.a_is_expected, a, b); + } +} + impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> { fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> { self.fields.infcx diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 67632a97df792..9c81a1153958b 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1490,6 +1490,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.report_and_explain_type_error(trace, &err) } + pub fn report_mismatched_consts( + &self, + cause: &ObligationCause<'tcx>, + expected: &'tcx ty::Const<'tcx>, + actual: &'tcx ty::Const<'tcx>, + err: TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx> { + let trace = TypeTrace::consts(cause, true, expected, actual); + self.report_and_explain_type_error(trace, &err) + } + pub fn replace_bound_vars_with_fresh_vars( &self, span: Span, @@ -1777,6 +1788,15 @@ impl<'tcx> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } } + pub fn consts( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) } + } + pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { TypeTrace { cause: ObligationCause::dummy(), diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 7aea26987a29f..8de8925100608 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -21,6 +21,7 @@ //! thing we relate in chalk are basically domain goals and their //! constituents) +use crate::infer::combine::ConstEquateRelation; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use rustc_data_structures::fx::FxHashMap; @@ -77,6 +78,8 @@ pub trait TypeRelatingDelegate<'tcx> { /// delegate. fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); + fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); + /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -715,6 +718,15 @@ where } } +impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D> +where + D: TypeRelatingDelegate<'tcx>, +{ + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + self.delegate.const_equate(a, b); + } +} + /// When we encounter a binder like `for<..> fn(..)`, we actually have /// to walk the `fn` value to find all the values bound by the `for` /// (these are not explicitly present in the ty representation right @@ -976,6 +988,7 @@ where } } } + ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a), _ => relate::super_relate_consts(self, a, a), } } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index ed3d860586968..289457e2bd0c2 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, ty::Predicate::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 0abcc15d6fcd8..1ec67ef2efa9d 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -1,6 +1,7 @@ use super::combine::{CombineFields, RelationDir}; use super::SubregionOrigin; +use crate::infer::combine::ConstEquateRelation; use crate::traits::Obligation; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; @@ -169,3 +170,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { self.fields.higher_ranked_sub(a, b, self.a_is_expected) } } + +impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> { + fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + self.fields.add_const_equate_obligation(self.a_is_expected, a, b); + } +} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index a8585fd293518..8d95904b355da 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -10,7 +10,7 @@ pub mod util; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Const, Ty}; use rustc_span::Span; pub use self::FulfillmentErrorCode::*; @@ -81,6 +81,7 @@ pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>), CodeAmbiguity, } diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs index 595a8cd768390..c48e58c04824e 100644 --- a/src/librustc_infer/traits/structural_impls.rs +++ b/src/librustc_infer/traits/structural_impls.rs @@ -41,6 +41,9 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { super::CodeSubtypeError(ref a, ref b) => { write!(f, "CodeSubtypeError({:?}, {:?})", a, b) } + super::CodeConstEquateError(ref a, ref b) => { + write!(f, "CodeConstEquateError({:?}, {:?})", a, b) + } super::CodeAmbiguity => write!(f, "Ambiguity"), } } diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index b34685006e223..ee903b676bae9 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>( ty::Predicate::ConstEvaluatable(def_id, substs) => { ty::Predicate::ConstEvaluatable(def_id, substs) } + + ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2), } } @@ -187,6 +189,10 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-evaluatable // predicates. } + ty::Predicate::ConstEquate(..) => { + // Currently, we do not elaborate const-equate + // predicates. + } ty::Predicate::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 327dbecba26ce..bca91fb7b5d16 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1221,7 +1221,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { ObjectSafe(..) | ClosureKind(..) | Subtype(..) | - ConstEvaluatable(..) => continue, + ConstEvaluatable(..) | + ConstEquate(..) => continue, }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 7feb080d4b8d4..c005455a3aab6 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1339,7 +1339,7 @@ impl<'tcx> TyCtxt<'tcx> { /// What mode(s) of borrowck should we run? AST? MIR? both? /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { + pub fn borrowck_mode(self) -> BorrowckMode { // Here are the main constraints we need to deal with: // // 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is @@ -1369,6 +1369,13 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.opts.borrowck_mode } + /// If `true`, we should use lazy normalization for constants, otherwise + /// we still evaluate them eagerly. + #[inline] + pub fn lazy_normalization(self) -> bool { + self.features().const_generics + } + #[inline] pub fn local_crate_exports_generics(self) -> bool { debug_assert!(self.sess.opts.share_generics()); @@ -2069,24 +2076,25 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } - /// Given a closure signature `sig`, returns an equivalent `fn` - /// type with the same signature. Detuples and so forth -- so - /// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get - /// a `fn(u32, i32)`. - /// `unsafety` determines the unsafety of the `fn` type. If you pass + /// Given a closure signature, returns an equivalent fn signature. Detuples + /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then + /// you would get a `fn(u32, i32)`. + /// `unsafety` determines the unsafety of the fn signature. If you pass /// `hir::Unsafety::Unsafe` in the previous example, then you would get /// an `unsafe fn (u32, i32)`. /// It cannot convert a closure that requires unsafe. - pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> { - let converted_sig = sig.map_bound(|s| { + pub fn signature_unclosure( + self, + sig: PolyFnSig<'tcx>, + unsafety: hir::Unsafety, + ) -> PolyFnSig<'tcx> { + sig.map_bound(|s| { let params_iter = match s.inputs()[0].kind { ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()), _ => bug!(), }; self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust) - }); - - self.mk_fn_ptr(converted_sig) + }) } #[allow(rustc::usage_of_ty_tykind)] diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 6d6e1699feb22..36bc44f5e5032 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1054,6 +1054,9 @@ pub enum Predicate<'tcx> { /// Constant initializer must evaluate successfully. ConstEvaluatable(DefId, SubstsRef<'tcx>), + + /// Constants must be equal. The first component is the const that is expected. + ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1172,6 +1175,9 @@ impl<'tcx> Predicate<'tcx> { Predicate::ConstEvaluatable(def_id, const_substs) => { Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)) } + Predicate::ConstEquate(c1, c2) => { + Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) + } } } } @@ -1349,7 +1355,8 @@ impl<'tcx> Predicate<'tcx> { | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | Predicate::TypeOutlives(..) - | Predicate::ConstEvaluatable(..) => None, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => None, } } @@ -1363,7 +1370,8 @@ impl<'tcx> Predicate<'tcx> { | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) => None, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => None, } } } diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index afd670b85775b..3e6a12df6887d 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -83,6 +83,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo } } + ty::Array(element, _) => { + // Don't look into the len const as it doesn't affect regions + compute_components(tcx, element, out); + } + ty::Closure(_, ref substs) => { for upvar_ty in substs.as_closure().upvar_tys() { compute_components(tcx, upvar_ty, out); @@ -158,7 +163,6 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo ty::Opaque(..) | // OutlivesNominalType (ish) ty::Foreign(..) | // OutlivesNominalType ty::Str | // OutlivesScalar (ish) - ty::Array(..) | // ... ty::Slice(..) | // ... ty::RawPtr(..) | // ... ty::Ref(..) | // OutlivesReference diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 64909cd0c467a..2502a4a13a8f0 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2058,6 +2058,13 @@ define_print_and_forward_display! { print_value_path(def_id, substs), write("` can be evaluated")) } + ty::Predicate::ConstEquate(c1, c2) => { + p!(write("the constant `"), + print(c1), + write("` equals `"), + print(c2), + write("`")) + } } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index d68bc7221f92d..594ffbcd83613 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -431,6 +431,9 @@ pub fn super_relate_tys>( let t = relation.relate(&a_t, &b_t)?; match relation.relate(&sz_a, &sz_b) { Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))), + // FIXME(#72219) Implement improved diagnostics for mismatched array + // length? + Err(err) if relation.tcx().lazy_normalization() => Err(err), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index 680b718792199..cdb7e34546af8 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -240,6 +240,7 @@ impl fmt::Debug for ty::Predicate<'tcx> { ty::Predicate::ConstEvaluatable(def_id, substs) => { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } + ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), } } } @@ -492,6 +493,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::ConstEvaluatable(def_id, substs) => { tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs)) } + ty::Predicate::ConstEquate(c1, c2) => { + tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2)) + } } } } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index bad176c603f35..526914721bebe 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -2088,7 +2088,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), }; - let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety); + let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); if let Err(terr) = self.eq_types( ty_fn_ptr_from, diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index 96ae534c3963f..7ff12820db815 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Const, Ty}; use rustc_trait_selection::traits::query::Fallible; use crate::borrow_check::constraints::OutlivesConstraint; @@ -99,6 +99,10 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { } } + // We don't have to worry about the equality of consts during borrow checking + // as consts always have a static lifetime. + fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} + fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index d025468d28bf3..e3982c654d5fa 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -277,7 +277,18 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { - if let DropFlagMode::Shallow = mode { DropStyle::Static } else { DropStyle::Open } + match mode { + DropFlagMode::Shallow => { + // Drops for the contained fields are "shallow" and "static" - they will simply call + // the field's own drop glue. + DropStyle::Static + } + DropFlagMode::Deep => { + // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder + // dropping each field contained in the value. + DropStyle::Open + } + } } fn get_drop_flag(&mut self, _path: Self::Path) -> Option> { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c9982aeaa0839..a2e2c1bf9eda3 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -28,7 +28,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | Predicate::TypeOutlives(_) | Predicate::WellFormed(_) | Predicate::Projection(_) - | Predicate::ConstEvaluatable(..) => continue, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => continue, Predicate::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index af7c88b178d32..ed999c6871bb6 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -12,10 +12,15 @@ use std::fmt; use std::convert::TryInto; +/// The value of an inserted drop flag. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { - Present, // i.e., initialized - Absent, // i.e., deinitialized or "moved" + /// The tracked value is initialized and needs to be dropped when leaving its scope. + Present, + + /// The tracked value is uninitialized or was moved out of and does not need to be dropped when + /// leaving its scope. + Absent, } impl DropFlagState { @@ -27,23 +32,42 @@ impl DropFlagState { } } +/// Describes how/if a value should be dropped. #[derive(Debug)] pub enum DropStyle { + /// The value is already dead at the drop location, no drop will be executed. Dead, + + /// The value is known to always be initialized at the drop location, drop will always be + /// executed. Static, + + /// Whether the value needs to be dropped depends on its drop flag. Conditional, + + /// An "open" drop is one where only the fields of a value are dropped. + /// + /// For example, this happens when moving out of a struct field: The rest of the struct will be + /// dropped in such an "open" drop. It is also used to generate drop glue for the individual + /// components of a value, for example for dropping array elements. Open, } +/// Which drop flags to affect/check with an operation. #[derive(Debug)] pub enum DropFlagMode { + /// Only affect the top-level drop flag, not that of any contained fields. Shallow, + /// Affect all nested drop flags in addition to the top-level one. Deep, } +/// Describes if unwinding is necessary and where to unwind to if a panic occurs. #[derive(Copy, Clone, Debug)] pub enum Unwind { + /// Unwind to this block. To(BasicBlock), + /// Already in an unwind path, any panic will cause an abort. InCleanup, } @@ -74,20 +98,58 @@ impl Unwind { } pub trait DropElaborator<'a, 'tcx>: fmt::Debug { + /// The type representing paths that can be moved out of. + /// + /// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to + /// represent such move paths. Sometimes tracking individual move paths is not necessary, in + /// which case this may be set to (for example) `()`. type Path: Copy + fmt::Debug; + // Accessors + fn patch(&mut self) -> &mut MirPatch<'tcx>; fn body(&self) -> &'a Body<'tcx>; fn tcx(&self) -> TyCtxt<'tcx>; fn param_env(&self) -> ty::ParamEnv<'tcx>; + // Drop logic + + /// Returns how `path` should be dropped, given `mode`. fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; + + /// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag). fn get_drop_flag(&mut self, path: Self::Path) -> Option>; + + /// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`. + /// + /// If `mode` is deep, drop flags of all child paths should also be cleared by inserting + /// additional statements. fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode); + // Subpaths + + /// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath). + /// + /// If this returns `None`, `field` will not get a dedicated drop flag. fn field_subpath(&self, path: Self::Path, field: Field) -> Option; + + /// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath). + /// + /// If this returns `None`, `*path` will not get a dedicated drop flag. + /// + /// This is only relevant for `Box`, where the contained `T` can be moved out of the box. fn deref_subpath(&self, path: Self::Path) -> Option; + + /// Returns the subpath of downcasting `path` to one of its variants. + /// + /// If this returns `None`, the downcast of `path` will not get a dedicated drop flag. fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option; + + /// Returns the subpath of indexing a fixed-size array `path`. + /// + /// If this returns `None`, elements of `path` will not get a dedicated drop flag. + /// + /// This is only relevant for array patterns, which can move out of individual array elements. fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option; } @@ -106,6 +168,14 @@ where unwind: Unwind, } +/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it. +/// +/// The passed `elaborator` is used to determine what should happen at the drop terminator. It +/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag, +/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped +/// value. +/// +/// When this returns, the MIR patch in the `elaborator` contains the necessary changes. pub fn elaborate_drop<'b, 'tcx, D>( elaborator: &mut D, source_info: SourceInfo, @@ -346,9 +416,7 @@ where let interior = self.tcx().mk_place_deref(self.place); let interior_path = self.elaborator.deref_subpath(self.path); - let succ = self.succ; // FIXME(#43234) - let unwind = self.unwind; - let succ = self.box_free_block(adt, substs, succ, unwind); + let succ = self.box_free_block(adt, substs, self.succ, self.unwind); let unwind_succ = self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup)); @@ -829,6 +897,8 @@ where self.drop_flag_test_block(drop_block, succ, unwind) } + /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will + /// also be cleared. fn drop_flag_reset_block( &mut self, mode: DropFlagMode, @@ -850,13 +920,15 @@ where fn elaborated_drop_block(&mut self) -> BasicBlock { debug!("elaborated_drop_block({:?})", self); - let unwind = self.unwind; // FIXME(#43234) - let succ = self.succ; - let blk = self.drop_block(succ, unwind); + let blk = self.drop_block(self.succ, self.unwind); self.elaborate_drop(blk); blk } + /// Creates a block that frees the backing memory of a `Box` if its drop is required (either + /// statically or by checking its drop flag). + /// + /// The contained value will not be dropped. fn box_free_block( &mut self, adt: &'tcx ty::AdtDef, @@ -868,6 +940,8 @@ where self.drop_flag_test_block(block, target, unwind) } + /// Creates a block that frees the backing memory of a `Box` (without dropping the contained + /// value). fn unelaborated_free_block( &mut self, adt: &'tcx ty::AdtDef, @@ -914,6 +988,11 @@ where self.new_block(unwind, block) } + /// Returns the block to jump to in order to test the drop flag and execute the drop. + /// + /// Depending on the required `DropStyle`, this might be a generated block with an `if` + /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case + /// the drop can be statically determined. fn drop_flag_test_block( &mut self, on_set: BasicBlock, diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 4f8075b0171d3..396965fcfb8b7 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,7 +1277,8 @@ crate fn required_region_bounds( | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, ty::Predicate::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 0d53df3bf4b46..139b860072224 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -615,6 +615,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation ) } + + ty::Predicate::ConstEquate(..) => { + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-equate requirement gave wrong error: `{:?}`", + obligation + ) + } } } @@ -1092,6 +1103,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) .emit(); } + FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => { + self.report_mismatched_consts( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone(), + ) + .emit(); + } } } diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 1e056c96acd38..98f6ac0e54728 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -2,9 +2,11 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; +use rustc_errors::ErrorReported; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _}; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Const, ToPolyTraitRef, Ty, TypeFoldable}; use std::marker::PhantomData; use super::project; @@ -520,6 +522,68 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), } } + + ty::Predicate::ConstEquate(c1, c2) => { + debug!("equating consts: c1={:?} c2={:?}", c1, c2); + + let stalled_on = &mut pending_obligation.stalled_on; + + let mut evaluate = |c: &'tcx Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { + match self.selcx.infcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + promoted, + Some(obligation.cause.span), + ) { + Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)), + Err(ErrorHandled::TooGeneric) => { + stalled_on.append( + &mut substs + .types() + .filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)) + .collect(), + ); + Err(ErrorHandled::TooGeneric) + } + Err(err) => Err(err), + } + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .selcx + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => { + ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError( + ExpectedFound::new(true, c1, c2), + err, + )) + } + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(ErrorHandled::Reported(ErrorReported))), + ), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( + obligation.cause.span(self.selcx.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ), + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + ProcessResult::Unchanged + } + } + } } } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 96b2b904e6543..1bfcacd6ccdc1 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -16,8 +16,9 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{Applicability, FatalError}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; -use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness}; +use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -281,7 +282,8 @@ fn predicates_reference_self( | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, } }) .collect() @@ -313,7 +315,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => false, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => false, }) } @@ -724,51 +727,65 @@ fn contains_illegal_self_type_reference<'tcx>( // object type, and we cannot resolve `Self as SomeOtherTrait` // without knowing what `Self` is. - let mut supertraits: Option>> = None; - let self_ty = tcx.types.self_param; - - let mut walker = ty.walk(); - while let Some(arg) = walker.next() { - if arg == self_ty.into() { - return true; - } - - // Special-case projections (everything else is walked normally). - if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Projection(ref data) = ty.kind { - // This is a projected type `::X`. + struct IllegalSelfTypeVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + trait_def_id: DefId, + supertraits: Option>>, + } - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id)); - supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); - } + impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Param(_) => t == self.self_ty, + ty::Projection(ref data) => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + let trait_ref = + ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect()); + } - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx)); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - // Do not walk contained types, do not report error, do collect $200. - walker.skip_current_subtree(); + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx)); + let is_supertrait_of_current_trait = + self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error + } } - - // DO walk contained types, POSSIBLY reporting an error. + _ => t.super_visit_with(self), // walk contained types, if any } } - // Walk contained types, if any. + fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool { + // FIXME(#72219) Look into the unevaluated constants for object safety violations. + // Do not walk substitutions of unevaluated consts, as they contain `Self`, even + // though the const expression doesn't necessary use it. Currently type variables + // inside array length expressions are forbidden, so they can't break the above + // rules. + false + } } - false + ty.visit_with(&mut IllegalSelfTypeVisitor { + tcx, + self_ty: tcx.types.self_param, + trait_def_id, + supertraits: None, + }) } pub fn provide(providers: &mut ty::query::Providers<'_>) { diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 0779882b6dd58..c4cb72fa08c08 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -388,8 +388,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - let constant = constant.super_fold_with(self); - constant.eval(self.selcx.tcx(), self.param_env) + if self.selcx.tcx().lazy_normalization() { + constant + } else { + let constant = constant.super_fold_with(self); + constant.eval(self.selcx.tcx(), self.param_env) + } } } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index f0ff30232b96d..70c6cbef102c5 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -38,11 +38,13 @@ use crate::traits::project::ProjectionCacheKeyExt; use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; use rustc_index::bit_set::GrowableBitSet; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; @@ -503,9 +505,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None, ) { Ok(_) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), Err(_) => Ok(EvaluatedToErr), } } + + ty::Predicate::ConstEquate(c1, c2) => { + debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); + + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { + self.infcx + .const_eval_resolve( + obligation.param_env, + def_id, + substs, + promoted, + Some(obligation.cause.span), + ) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( + obligation.cause.span(self.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ), + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + Ok(EvaluatedToAmbig) + } + } + } } } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index ba7ec96775c04..4d3bbfa77c37d 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -102,6 +102,10 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(ty); } } + ty::Predicate::ConstEquate(c1, c2) => { + wf.compute(c1.ty); + wf.compute(c2.ty); + } } wf.normalize() diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index aacbd311d1dec..184b9a9dc1040 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -126,9 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { - bug!("unexpected predicate {}", predicate) - } + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => bug!("unexpected predicate {}", predicate), } } ChalkEnvironmentClause::TypeFromEnv(ty) => Some( @@ -192,9 +191,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | Predicate::Subtype(..) - | Predicate::ConstEvaluatable(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) - } + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), } } } @@ -459,7 +457,8 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 6db2e557fea69..eaaab87ab7474 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -100,7 +100,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ConstEvaluatable(..) => vec![], + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => vec![], ty::Predicate::WellFormed(subty) => { wf_types.push(subty); diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index ad6c753edff00..ed30ed5313e5c 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => true, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => true, } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4ac3f2625ab86..54562cf38addd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -793,7 +793,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // `unsafe fn(arg0,arg1,...) -> _` let closure_sig = substs_a.as_closure().sig(); let unsafety = fn_ty.unsafety(); - let pointer_ty = self.tcx.coerce_closure_fn_ty(closure_sig, unsafety); + let pointer_ty = + self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety)); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); self.unify_and( pointer_ty, @@ -909,23 +910,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); // Special-case that coercion alone cannot handle: - // Two function item types of differing IDs or InternalSubsts. - if let (&ty::FnDef(..), &ty::FnDef(..)) = (&prev_ty.kind, &new_ty.kind) { - // Don't reify if the function types have a LUB, i.e., they - // are the same function and their parameters have a LUB. - let lub_ty = self - .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) - .map(|ok| self.register_infer_ok_obligations(ok)); - - if lub_ty.is_ok() { - // We have a LUB of prev_ty and new_ty, just return it. - return lub_ty; + // Function items or non-capturing closures of differing IDs or InternalSubsts. + let (a_sig, b_sig) = { + let is_capturing_closure = |ty| { + if let &ty::Closure(_, substs) = ty { + substs.as_closure().upvar_tys().next().is_some() + } else { + false + } + }; + if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) { + (None, None) + } else { + match (&prev_ty.kind, &new_ty.kind) { + (&ty::FnDef(..), &ty::FnDef(..)) => { + // Don't reify if the function types have a LUB, i.e., they + // are the same function and their parameters have a LUB. + match self + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) + { + // We have a LUB of prev_ty and new_ty, just return it. + Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), + Err(_) => { + (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))) + } + } + } + (&ty::Closure(_, substs), &ty::FnDef(..)) => { + let b_sig = new_ty.fn_sig(self.tcx); + let a_sig = self + .tcx + .signature_unclosure(substs.as_closure().sig(), b_sig.unsafety()); + (Some(a_sig), Some(b_sig)) + } + (&ty::FnDef(..), &ty::Closure(_, substs)) => { + let a_sig = prev_ty.fn_sig(self.tcx); + let b_sig = self + .tcx + .signature_unclosure(substs.as_closure().sig(), a_sig.unsafety()); + (Some(a_sig), Some(b_sig)) + } + (&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => ( + Some(self.tcx.signature_unclosure( + substs_a.as_closure().sig(), + hir::Unsafety::Normal, + )), + Some(self.tcx.signature_unclosure( + substs_b.as_closure().sig(), + hir::Unsafety::Normal, + )), + ), + _ => (None, None), + } } - + }; + if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { // The signature must match. - let a_sig = prev_ty.fn_sig(self.tcx); let a_sig = self.normalize_associated_types_in(new.span, &a_sig); - let b_sig = new_ty.fn_sig(self.tcx); let b_sig = self.normalize_associated_types_in(new.span, &b_sig); let sig = self .at(cause, self.param_env) @@ -935,17 +976,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(sig); - for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { - // The only adjustment that can produce an fn item is - // `NeverToAny`, so this should always be valid. + let prev_adjustment = match prev_ty.kind { + ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), + ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + _ => unreachable!(), + }; + let next_adjustment = match new_ty.kind { + ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), + ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + _ => unreachable!(), + }; + for expr in exprs.iter().map(|e| e.as_coercion_site()) { self.apply_adjustments( expr, - vec![Adjustment { - kind: Adjust::Pointer(PointerCast::ReifyFnPointer), - target: fn_ptr, - }], + vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }], ); } + self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]); return Ok(fn_ptr); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7f1d77e5b97d8..e21db9035e25d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -810,7 +810,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6bf836015d226..d72c74e4188ee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1648,6 +1648,16 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, r.super_visit_with(self) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(..) = c.val { + // FIXME(#72219) We currenctly don't detect lifetimes within substs + // which would violate this check. Even though the particular substitution is not used + // within the const, this should still be fixed. + return false; + } + c.super_visit_with(self) + } } let prohibit_opaque = match item.kind { @@ -3858,6 +3868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::ConstEquate(..) => None, // N.B., this predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where // `ClosureType` represents some `Closure`. It can't diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 854bd03b26486..7cfb89f3ff048 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1164,7 +1164,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id(parent_id).to_def_id()) } - // FIXME(#43408) enable this always when we get lazy normalization. + // FIXME(#43408) always enable this once `lazy_normalization` is + // stable enough and does not need a feature gate anymore. Node::AnonConst(_) => { let parent_id = tcx.hir().get_parent_item(hir_id); let parent_def_id = tcx.hir().local_def_id(parent_id); @@ -1172,7 +1173,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // HACK(eddyb) this provides the correct generics when // `feature(const_generics)` is enabled, so that const expressions // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - if tcx.features().const_generics { + if tcx.lazy_normalization() { Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index 8b12535b3a2cf..919bcc9943d48 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -413,6 +413,7 @@ fn trait_predicate_kind<'tcx>( | ty::Predicate::Subtype(_) | ty::Predicate::ObjectSafe(_) | ty::Predicate::ClosureKind(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 168f20771476c..66daf0e7f7d9d 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -58,7 +58,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => (), + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6c001bc548410..c130ed3f46dbb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -493,7 +493,8 @@ impl<'a> Clean> for ty::Predicate<'a> { Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) => panic!("not user writable"), + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.rs b/src/test/ui/closures/closure_cap_coerce_many_fail.rs new file mode 100644 index 0000000000000..9133a29210308 --- /dev/null +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.rs @@ -0,0 +1,39 @@ +fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We shouldn't coerce capturing closure to a function + let cap = 0; + let _ = match "+" { + "+" => add, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + + // We shouldn't coerce capturing closure to a non-capturing closure + let _ = match "+" { + "+" => |a, b| (a + b) as i32, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + + // We shouldn't coerce non-capturing closure to a capturing closure + let _ = match "+" { + "+" => |a, b| (a + b + cap) as i32, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types + + // We shouldn't coerce capturing closure to a capturing closure + let _ = match "+" { + "+" => |a, b| (a + b + cap) as i32, + "-" => |a, b| (a - b + cap) as i32, + _ => unimplemented!(), + }; + //~^^^ ERROR `match` arms have incompatible types +} diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr new file mode 100644 index 0000000000000..63eb0bd8fabad --- /dev/null +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr @@ -0,0 +1,73 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:9:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => add, + | | --- this is found to be of type `fn(i32, i32) -> i32 {add}` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `fn(i32, i32) -> i32 {add}` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]` + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:18:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b) as i32, + | | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:27:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b + cap) as i32, + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` +LL | | "-" => |a, b| (a - b) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error[E0308]: `match` arms have incompatible types + --> $DIR/closure_cap_coerce_many_fail.rs:35:16 + | +LL | let _ = match "+" { + | _____________- +LL | | "+" => |a, b| (a + b + cap) as i32, + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` +LL | | "-" => |a, b| (a - b + cap) as i32, + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure +LL | | _ => unimplemented!(), +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs b/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs new file mode 100644 index 0000000000000..ce461810ec990 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs @@ -0,0 +1,166 @@ +// check-pass +// Ensure non-capturing Closure passes CoerceMany. +fn foo(x: usize) -> usize { + 0 +} + +fn bar(x: usize) -> usize { + 1 +} + +fn main() { + // One FnDef and one non-capturing Closure + let _ = match 0 { + 0 => foo, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 2 => |a| 2, + 0 => foo, + _ => unimplemented!(), + }; + + let _ = [foo, |a| 2]; + let _ = [|a| 2, foo]; + + + + // Two FnDefs and one non-capturing Closure + let _ = match 0 { + 0 => foo, + 1 => bar, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 0 => foo, + 2 => |a| 2, + 1 => bar, + _ => unimplemented!(), + }; + + let _ = match 0 { + 2 => |a| 2, + 0 => foo, + 1 => bar, + _ => unimplemented!(), + }; + + let _ = [foo, bar, |a| 2]; + let _ = [foo, |a| 2, bar]; + let _ = [|a| 2, foo, bar]; + + + + // One FnDef and two non-capturing Closures + let _ = match 0 { + 0 => foo, + 1 => |a| 1, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 1 => |a| 1, + 0 => foo, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = match 0 { + 1 => |a| 1, + 2 => |a| 2, + 0 => foo, + _ => unimplemented!(), + }; + + let _ = [foo, |a| 1, |a| 2]; + let _ = [|a| 1, foo, |a| 2]; + let _ = [|a| 1, |a| 2, foo]; + + + + // Three non-capturing Closures + let _ = match 0 { + 0 => |a: usize| 0, + 1 => |a| 1, + 2 => |a| 2, + _ => unimplemented!(), + }; + + let _ = [|a: usize| 0, |a| 1, |a| 2]; + + + + // Three non-capturing Closures variable + let clo0 = |a: usize| 0; + let clo1 = |a| 1; + let clo2 = |a| 2; + let _ = match 0 { + 0 => clo0, + 1 => clo1, + 2 => clo2, + _ => unimplemented!(), + }; + + let clo0 = |a: usize| 0; + let clo1 = |a| 1; + let clo2 = |a| 2; + let _ = [clo0, clo1, clo2]; + + + + // --- Function pointer related part + + // Closure is not in a variable + type FnPointer = fn(usize) -> usize; + + let _ = match 0 { + 0 => foo as FnPointer, + 2 => |a| 2, + _ => unimplemented!(), + }; + let _ = match 0 { + 2 => |a| 2, + 0 => foo as FnPointer, + _ => unimplemented!(), + }; + let _ = [foo as FnPointer, |a| 2]; + let _ = [|a| 2, foo as FnPointer]; + let _ = [foo, bar, |x| x]; + let _ = [foo as FnPointer, bar, |x| x]; + let _ = [foo, bar as FnPointer, |x| x]; + let _ = [foo, bar, (|x| x) as FnPointer]; + let _ = [foo as FnPointer, bar as FnPointer, |x| x]; + + // Closure is in a variable + let x = |a| 2; + let _ = match 0 { + 0 => foo as FnPointer, + 2 => x, + _ => unimplemented!(), + }; + let x = |a| 2; + let _ = match 0 { + 2 => x, + 0 => foo as FnPointer, + _ => unimplemented!(), + }; + let x = |a| 2; + let _ = [foo as FnPointer, x]; + let _ = [x, foo as FnPointer]; + + let x = |a| 2; + let _ = [foo, bar, x]; + let x: FnPointer = |a| 2; + let _ = [foo, bar, x]; + let x = |a| 2; + let _ = [foo, bar as FnPointer, x]; + let x = |a| 2; + let _ = [foo as FnPointer, bar, x]; + let x = |a| 2; + let _ = [foo as FnPointer, bar as FnPointer, x]; +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs b/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs new file mode 100644 index 0000000000000..3c5fe8a550276 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs @@ -0,0 +1,59 @@ +// run-pass +// Ensure non-capturing Closure passing CoerceMany work correctly. +fn foo(_: usize) -> usize { + 0 +} + +fn bar(_: usize) -> usize { + 1 +} + +fn add(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + // Coerce result check + + type FnPointer = fn(usize) -> usize; + + let c = |x| x; + let c_pointer: FnPointer = c; + assert_eq!(c_pointer(42), 42); + + let f = match 0 { + 0 => foo, + 1 => |_| 1, + _ => unimplemented!(), + }; + assert_eq!(f(42), 0); + + let f = match 2 { + 2 => |_| 2, + 0 => foo, + _ => unimplemented!(), + }; + assert_eq!(f(42), 2); + + let f = match 1 { + 0 => foo, + 1 => bar, + 2 => |_| 2, + _ => unimplemented!(), + }; + assert_eq!(f(42), 1); + + let clo0 = |_: usize| 0; + let clo1 = |_| 1; + let clo2 = |_| 2; + let f = match 0 { + 0 => clo0, + 1 => clo1, + 2 => clo2, + _ => unimplemented!(), + }; + assert_eq!(f(42), 0); + + let funcs = [add, |a, b| (a - b) as i32]; + assert_eq!([funcs[0](5, 5), funcs[1](5, 5)], [10, 0]); +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs new file mode 100644 index 0000000000000..76a0f2914103d --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs @@ -0,0 +1,22 @@ +// Ensure we get unsafe function after coercion +unsafe fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We can coerce non-capturing closure to unsafe function + let foo = match "+" { + "+" => add, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + let result: i32 = foo(5, 5); //~ ERROR call to unsafe function + + + // We can coerce unsafe function to non-capturing closure + let foo = match "+" { + "-" => |a, b| (a - b) as i32, + "+" => add, + _ => unimplemented!(), + }; + let result: i32 = foo(5, 5); //~ ERROR call to unsafe function +} diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr new file mode 100644 index 0000000000000..190b4792ebcbc --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:12:23 + | +LL | let result: i32 = foo(5, 5); + | ^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:21:23 + | +LL | let result: i32 = foo(5, 5); + | ^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs new file mode 100644 index 0000000000000..a6d6125a1b9f9 --- /dev/null +++ b/src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs @@ -0,0 +1,23 @@ +// run-pass +// Ensure we get correct unsafe function after coercion +unsafe fn add(a: i32, b: i32) -> i32 { + a + b +} +fn main() { + // We can coerce non-capturing closure to unsafe function + let foo = match "+" { + "+" => add, + "-" => |a, b| (a - b) as i32, + _ => unimplemented!(), + }; + assert_eq!(unsafe { foo(5, 5) }, 10); + + + // We can coerce unsafe function to non-capturing closure + let foo = match "-" { + "-" => |a, b| (a - b) as i32, + "+" => add, + _ => unimplemented!(), + }; + assert_eq!(unsafe { foo(5, 5) }, 0); +} diff --git a/src/test/ui/closures/issue-46742.rs b/src/test/ui/closures/issue-46742.rs new file mode 100644 index 0000000000000..cd8dc486906bb --- /dev/null +++ b/src/test/ui/closures/issue-46742.rs @@ -0,0 +1,9 @@ +// check-pass +fn main() { + let _: i32 = (match "" { + "+" => ::std::ops::Add::add, + "-" => ::std::ops::Sub::sub, + "<" => |a,b| (a < b) as i32, + _ => unimplemented!(), + })(5, 5); +} diff --git a/src/test/ui/closures/issue-48109.rs b/src/test/ui/closures/issue-48109.rs new file mode 100644 index 0000000000000..ce1f2a0364764 --- /dev/null +++ b/src/test/ui/closures/issue-48109.rs @@ -0,0 +1,14 @@ +// check-pass +fn useful(i: usize) -> usize { + i +} + +fn useful2(i: usize) -> usize { + i +} + +fn main() { + for f in &[useful, useful2, |x| x] { + println!("{}", f(6)); + } +} diff --git a/src/test/ui/const-generics/different_byref.stderr b/src/test/ui/const-generics/different_byref.stderr index 001d9852a69f8..7eb826b8a36b1 100644 --- a/src/test/ui/const-generics/different_byref.stderr +++ b/src/test/ui/const-generics/different_byref.stderr @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | x = Const::<{ [4] }> {}; | ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize` | - = note: expected struct `Const<[3usize]>` - found struct `Const<[4usize]>` + = note: expected type `[3usize]` + found type `[4usize]` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 3e07393b9aa89..de41d2984a655 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -11,12 +11,10 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:16:31 | LL | let _: Checked = Checked::; - | ---------------- ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}` | - = note: expected struct `Checked<{not_one as fn(usize) -> bool}>` - found struct `Checked<{not_two as fn(usize) -> bool}>` + = note: expected type `{not_one as fn(usize) -> bool}` + found type `{not_two as fn(usize) -> bool}` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:20:24 @@ -37,12 +35,10 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 | LL | let _: Checked<{generic::}> = Checked::<{generic::}>; - | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` | - = note: expected struct `Checked<{generic:: as fn(usize) -> bool}>` - found struct `Checked<{generic:: as fn(usize) -> bool}>` + = note: expected type `{generic:: as fn(usize) -> bool}` + found type `{generic:: as fn(usize) -> bool}` error: aborting due to 4 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs new file mode 100644 index 0000000000000..5c987e63a9e07 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +trait Foo {} + +impl Foo for [(); N] + where + Self:FooImpl<{N==0}> +{} + +trait FooImpl{} + +impl FooImpl for [(); 0] {} + +impl FooImpl for [();N] {} + +fn foo(_: impl Foo) {} + +fn main() { + foo([]); + foo([()]); +} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr new file mode 100644 index 0000000000000..cf0c0e24a7604 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.stderr @@ -0,0 +1,11 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-61935.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 264e693a00828..4e05aadd3930f 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -16,8 +16,7 @@ struct ArrayHolder([u32; X]); impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR: mismatched types - //~| ERROR constant expression depends on a generic parameter + //~^ ERROR constant expression depends on a generic parameter } } diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr index 5d45e302888d4..f09af76325e96 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.stderr @@ -1,12 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-62504.rs:18:21 - | -LL | ArrayHolder([0; Self::SIZE]) - | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` - | - = note: expected array `[u32; X]` - found array `[u32; _]` - error: constant expression depends on a generic parameter --> $DIR/issue-62504.rs:18:25 | @@ -15,6 +6,5 @@ LL | ArrayHolder([0; Self::SIZE]) | = note: this may fail depending on what value the parameter takes -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 73ba4fa6aae88..76bde1815be18 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,5 +1,6 @@ #![allow(incomplete_features, dead_code, unconditional_recursion)] #![feature(const_generics)] +#![feature(lazy_normalization_consts)] fn fact() { fact::<{ N - 1 }>(); diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr index 2bd013e8b41f2..416b675b56d28 100644 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-66205.rs:5:12 + --> $DIR/issue-66205.rs:6:12 | LL | fact::<{ N - 1 }>(); | ^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-67185-1.rs b/src/test/ui/const-generics/issues/issue-67185-1.rs new file mode 100644 index 0000000000000..b08057851a1ba --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-1.rs @@ -0,0 +1,32 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +trait Baz { + type Quaks; +} +impl Baz for u8 { + type Quaks = [u16; 3]; +} + +trait Bar {} +impl Bar for [u16; 3] {} +impl Bar for [[u16; 3]; 2] {} + +trait Foo + where + [::Quaks; 2]: Bar, + ::Quaks: Bar, +{ +} + +struct FooImpl; + +impl Foo for FooImpl {} + +fn f(_: impl Foo) {} + +fn main() { + f(FooImpl) +} diff --git a/src/test/ui/const-generics/issues/issue-67185-1.stderr b/src/test/ui/const-generics/issues/issue-67185-1.stderr new file mode 100644 index 0000000000000..9cc797d6d8a01 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-1.stderr @@ -0,0 +1,11 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-67185-1.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs new file mode 100644 index 0000000000000..111b718dd5efd --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -0,0 +1,35 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +trait Baz { + type Quaks; +} +impl Baz for u8 { + type Quaks = [u16; 3]; +} + +trait Bar {} +impl Bar for [u16; 4] {} +impl Bar for [[u16; 3]; 3] {} + +trait Foo //~ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] + //~^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + where + [::Quaks; 2]: Bar, + ::Quaks: Bar, +{ +} + +struct FooImpl; + +impl Foo for FooImpl {} +//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] +//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + +fn f(_: impl Foo) {} +//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] +//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + +fn main() { + f(FooImpl) +} diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.stderr new file mode 100644 index 0000000000000..7d947a907a0ee --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.stderr @@ -0,0 +1,112 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-67185-2.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:15:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:15:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:25:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:25:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:29:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:29:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs deleted file mode 100644 index 2befbe56d85c7..0000000000000 --- a/src/test/ui/const-generics/issues/issue-69654.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] - -trait Bar {} -impl Bar for [u8; O] {} -//~^ ERROR expected value, found type parameter `O` - -struct Foo {} -impl Foo -where - [u8; O]: Bar<[(); O]>, -{ - fn foo() {} -} - -fn main() { - Foo::foo(); -} diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr deleted file mode 100644 index 9d52603f462be..0000000000000 --- a/src/test/ui/const-generics/issues/issue-69654.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0423]: expected value, found type parameter `O` - --> $DIR/issue-69654.rs:5:25 - | -LL | impl Bar for [u8; O] {} - | ^ help: a tuple variant with a similar name exists: `Ok` - | - ::: $SRC_DIR/libcore/result.rs:LL:COL - | -LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), - | --------------------------------------------------- similarly named tuple variant `Ok` defined here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs new file mode 100644 index 0000000000000..36513f94a9e97 --- /dev/null +++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] +trait Foo {} + +impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} + +trait FooImpl {} + +impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {} + +impl FooImpl<{ 0u8 != 0u8 }> for [(); N] {} + +fn foo(_: T) {} + +fn main() { + foo([]); + foo([()]); +} diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71986.rs b/src/test/ui/const-generics/lazy-normalization/issue-71986.rs new file mode 100644 index 0000000000000..048ed18c927bf --- /dev/null +++ b/src/test/ui/const-generics/lazy-normalization/issue-71986.rs @@ -0,0 +1,8 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +pub trait Foo {} +pub fn bar>() {} + +fn main() {} diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index 6644c72236b86..7a665397c1207 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -11,12 +11,10 @@ error[E0308]: mismatched types --> $DIR/raw-ptr-const-param.rs:7:40 | LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; - | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` | - = note: expected struct `Const<{0xf as *const u32}>` - found struct `Const<{0xa as *const u32}>` + = note: expected type `{0xf as *const u32}` + found type `{0xa as *const u32}` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.stderr index 2131738554f87..53328c2e89bf4 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.stderr +++ b/src/test/ui/const-generics/types-mismatch-const-args.stderr @@ -11,12 +11,10 @@ error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:13:41 | LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; - | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32` | - = note: expected struct `A<'_, _, 2u32, _>` - found struct `A<'_, _, 4u32, _>` + = note: expected type `2u32` + found type `4u32` error[E0308]: mismatched types --> $DIR/types-mismatch-const-args.rs:15:41 @@ -26,8 +24,8 @@ LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data | | | expected due to this | - = note: expected struct `A<'a, u16, _, _>` - found struct `A<'b, u32, _, _>` + = note: expected struct `A<'a, u16, {2u32}, {3u32}>` + found struct `A<'b, u32, {2u32}, {3u32}>` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/issues/issue-24036.rs b/src/test/ui/issues/issue-24036.rs index bd82f95c9ef66..7df036c8e3a45 100644 --- a/src/test/ui/issues/issue-24036.rs +++ b/src/test/ui/issues/issue-24036.rs @@ -10,7 +10,7 @@ fn closure_from_match() { 2 => |c| c - 1, _ => |c| c - 1 }; - //~^^^ ERROR `match` arms have incompatible types + //~^^^^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 036c05fc848cf..e6b8367f74fb5 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -11,24 +11,13 @@ LL | x = |c| c + 1; = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object -error[E0308]: `match` arms have incompatible types - --> $DIR/issue-24036.rs:10:14 +error[E0282]: type annotations needed + --> $DIR/issue-24036.rs:9:15 | -LL | let x = match 1usize { - | _____________- -LL | | 1 => |c| c + 1, - | | --------- this is found to be of type `[closure@$DIR/issue-24036.rs:9:14: 9:23]` -LL | | 2 => |c| c - 1, - | | ^^^^^^^^^ expected closure, found a different closure -LL | | _ => |c| c - 1 -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected type `[closure@$DIR/issue-24036.rs:9:14: 9:23]` - found closure `[closure@$DIR/issue-24036.rs:10:14: 10:23]` - = note: no two closures, even if identical, have the same type - = help: consider boxing your closure and/or using it as a trait object +LL | 1 => |c| c + 1, + | ^ consider giving this closure parameter a type error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr index b0ffc4a5ef61d..88f8dbe1a7d72 100644 --- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -25,7 +25,7 @@ error: non-defining opaque type use in defining scope LL | fn concrete_const() -> OneConst<{123}> { | ^^^^^^^^^^^^^^^ | -note: used non-generic constant `123usize` for generic parameter +note: used non-generic constant `{123}` for generic parameter --> $DIR/generic_nondefining_use.rs:10:21 | LL | type OneConst = impl Debug; diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index d0ae8300bd6af..3379d82eda829 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -18,6 +18,7 @@ use std::thread; use std::time::Duration; const REMOTE_ADDR_ENV: &str = "TEST_DEVICE_ADDR"; +const DEFAULT_ADDR: &str = "127.0.0.1:12345"; macro_rules! t { ($e:expr) => { @@ -30,8 +31,12 @@ macro_rules! t { fn main() { let mut args = env::args().skip(1); + let next = args.next(); + if next.is_none() { + return help(); + } - match &args.next().unwrap()[..] { + match &next.unwrap()[..] { "spawn-emulator" => spawn_emulator( &args.next().unwrap(), Path::new(&args.next().unwrap()), @@ -40,12 +45,16 @@ fn main() { ), "push" => push(Path::new(&args.next().unwrap())), "run" => run(args.next().unwrap(), args.collect()), - cmd => panic!("unknown command: {}", cmd), + "help" | "-h" | "--help" => help(), + cmd => { + println!("unknown command: {}", cmd); + help(); + } } } fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option) { - let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string()); + let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string()); if env::var(REMOTE_ADDR_ENV).is_ok() { println!("Connecting to remote device {} ...", device_address); @@ -172,7 +181,7 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path } fn push(path: &Path) { - let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string()); + let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string()); let client = t!(TcpStream::connect(device_address)); let mut client = BufWriter::new(client); t!(client.write_all(b"push")); @@ -189,7 +198,7 @@ fn push(path: &Path) { } fn run(files: String, args: Vec) { - let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string()); + let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string()); let client = t!(TcpStream::connect(device_address)); let mut client = BufWriter::new(client); t!(client.write_all(b"run ")); @@ -284,3 +293,40 @@ fn send(path: &Path, dst: &mut dyn Write) { t!(dst.write_all(&[(amt >> 24) as u8, (amt >> 16) as u8, (amt >> 8) as u8, (amt >> 0) as u8,])); t!(io::copy(&mut file, dst)); } + +fn help() { + println!( + " +Usage: {0} [] + +Sub-commands: + spawn-emulator [rootfs] See below + push Copy to emulator + run [args...] Run program on emulator + help Display help message + +Spawning an emulator: + +For Android s, adb will push the , set up TCP forwarding and run +the . Otherwise qemu emulates the target using a rootfs image created in + and generated from plus the executable. +If {1} is set in the environment, this step is skipped. + +Pushing a path to a running emulator: + +A running emulator or adb device is connected to at the IP address and port in +the {1} environment variable or {2} if this isn't +specified. The file at is sent to this target. + +Executing commands on a running emulator: + +First the target emulator/adb session is connected to as for pushing files. Next +the colon separated list of is pushed to the target. Finally, the first +file in is executed in the emulator, preserving the current environment. +That command's status code is returned. +", + env::args().next().unwrap(), + REMOTE_ADDR_ENV, + DEFAULT_ADDR + ); +}