diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index f787b8a6fd94a..e0ebe30752afa 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -415,7 +415,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - sym::simd_fma => { + // FIXME: simd_relaxed_fma doesn't relax to non-fused multiply-add + sym::simd_fma | sym::simd_relaxed_fma => { intrinsic_args!(fx, args => (a, b, c); intrinsic); if !a.layout().ty.is_simd() { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 604678a9af4c7..79d1a06dd467f 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -772,6 +772,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( sym::simd_flog => "log", sym::simd_floor => "floor", sym::simd_fma => "fma", + sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary sym::simd_fpowi => "__builtin_powi", sym::simd_fpow => "pow", sym::simd_fsin => "sin", diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index da7f94e8cf71d..d8b055137b359 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1534,6 +1534,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), + sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)), sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)), sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), @@ -1572,6 +1573,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( | sym::simd_fpowi | sym::simd_fsin | sym::simd_fsqrt + | sym::simd_relaxed_fma | sym::simd_round | sym::simd_trunc ) { diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index 93d90cd16b24a..d9c5c3e5af96d 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -97,7 +97,7 @@ fn minimum_deployment_target(target: &Target) -> OSVersion { } /// Name of the environment variable used to fetch the deployment target on the given OS. -fn deployment_target_env_var(os: &str) -> &'static str { +pub fn deployment_target_env_var(os: &str) -> &'static str { match os { "macos" => "MACOSX_DEPLOYMENT_TARGET", "ios" => "IPHONEOS_DEPLOYMENT_TARGET", diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 34a2464972a6e..78d69a66edc8b 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -415,6 +415,10 @@ impl ObligationForest { .collect() } + pub fn has_pending_obligations(&self) -> bool { + self.nodes.iter().any(|node| node.state.get() == NodeState::Pending) + } + fn insert_into_error_cache(&mut self, index: usize) { let node = &self.nodes[index]; self.error_cache diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 85eaae8a10466..5b472bb9b8103 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -867,8 +867,9 @@ fn print_crate_info( DeploymentTarget => { if sess.target.is_like_osx { println_info!( - "deployment_target={}", - apple::pretty_version(apple::deployment_target(sess)) + "{}={}", + apple::deployment_target_env_var(&sess.target.os), + apple::pretty_version(apple::deployment_target(sess)), ) } else { #[allow(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index cb658111392c3..070d63b48b7bd 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -113,8 +113,6 @@ hir_analysis_const_param_ty_impl_on_unsized = the trait `ConstParamTy` may not be implemented for this type .label = type is not `Sized` -hir_analysis_const_specialize = cannot specialize on const impl with non-const impl - hir_analysis_copy_impl_on_non_adt = the trait `Copy` cannot be implemented for this type .label = type is not a structure or enumeration diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 3e33120901f69..7434bbf180b97 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -641,7 +641,9 @@ pub fn check_intrinsic_type( | sym::simd_round | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)), - sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)), + sym::simd_fma | sym::simd_relaxed_fma => { + (1, 0, vec![param(0), param(0), param(0)], param(0)) + } sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)), sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)), sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index ed3ae1e12b925..2b33da3c49a07 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -117,13 +117,12 @@ where } f(&mut wfcx)?; - let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; - let errors = wfcx.select_all_or_error(); if !errors.is_empty() { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } + let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; debug!(?assumed_wf_types); let infcx_compat = infcx.fork(); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 51115b11e86b8..4142dcff226bf 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1079,13 +1079,6 @@ pub(crate) struct EmptySpecialization { pub base_impl_span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_const_specialize)] -pub(crate) struct ConstSpecialize { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_static_specialize)] pub(crate) struct StaticSpecialize { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 246643d807470..ee55e1bc21a60 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -66,7 +66,6 @@ //! on traits with methods can. use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -134,7 +133,6 @@ fn check_always_applicable( unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) }; - res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span)); res = res.and(check_static_lifetimes(tcx, &parent_args, span)); res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span)); res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); @@ -157,30 +155,6 @@ fn check_has_items( Ok(()) } -/// Check that the specializing impl `impl1` is at least as const as the base -/// impl `impl2` -fn check_constness( - tcx: TyCtxt<'_>, - impl1_def_id: LocalDefId, - impl2_node: Node, - span: Span, -) -> Result<(), ErrorGuaranteed> { - if impl2_node.is_from_trait() { - // This isn't a specialization - return Ok(()); - } - - let impl1_constness = tcx.constness(impl1_def_id.to_def_id()); - let impl2_constness = tcx.constness(impl2_node.def_id()); - - if let hir::Constness::Const = impl2_constness { - if let hir::Constness::NotConst = impl1_constness { - return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span })); - } - } - Ok(()) -} - /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two /// generic parameters `(S1, S2)` that equate their trait references. /// The returned types are expressed in terms of the generics of `impl1`. diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index ba1516655b0bc..51282b900ed14 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -84,6 +84,8 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { self.collect_remaining_errors(infcx) } + fn has_pending_obligations(&self) -> bool; + fn pending_obligations(&self) -> PredicateObligations<'tcx>; /// Among all pending obligations, collect those are stalled on a inference variable which has diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e94c0a5ea6e7f..5fa8ce835edad 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1844,6 +1844,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_relaxed_fma, simd_rem, simd_round, simd_saturating_add, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 0f90c45d0320c..2b2623a050ec9 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -199,6 +199,10 @@ where errors } + fn has_pending_obligations(&self) -> bool { + !self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty() + } + fn pending_obligations(&self) -> PredicateObligations<'tcx> { self.obligations.clone_pending() } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 03e483f555d8e..7529ee128f5e4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -213,6 +213,10 @@ where } } + fn has_pending_obligations(&self) -> bool { + self.predicates.has_pending_obligations() + } + fn pending_obligations(&self) -> PredicateObligations<'tcx> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index e99c5eacbd8e0..ad62b456ad461 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -7,6 +7,7 @@ use rustc_infer::traits::{ FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, }; use rustc_macros::extension; +use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, @@ -63,10 +64,18 @@ impl<'tcx> At<'_, 'tcx> { if self.infcx.next_trait_solver() { crate::solve::deeply_normalize(self, value) } else { + if fulfill_cx.has_pending_obligations() { + let pending_obligations = fulfill_cx.pending_obligations(); + span_bug!( + pending_obligations[0].cause.span, + "deeply_normalize should not be called with pending obligations: \ + {pending_obligations:#?}" + ); + } let value = self .normalize(value) .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); - let errors = fulfill_cx.select_where_possible(self.infcx); + let errors = fulfill_cx.select_all_or_error(self.infcx); let value = self.infcx.resolve_vars_if_possible(value); if errors.is_empty() { Ok(value) } else { Err(errors) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index c6e41e57f0cec..fe47e837dfb53 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -59,12 +59,16 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { - let normalize_op = |ty| { - let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty); + let normalize_op = |ty| -> Result<_, NoSolution> { + // We must normalize the type so we can compute the right outlives components. + // for example, if we have some constrained param type like `T: Trait`, + // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`. + let ty = ocx + .deeply_normalize(&ObligationCause::dummy(), param_env, ty) + .map_err(|_| NoSolution)?; if !ocx.select_all_or_error().is_empty() { return Err(NoSolution); } - let ty = ocx.infcx.resolve_vars_if_possible(ty); let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty); Ok(ty) }; diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index a9cd705465e3a..1430cfae51f73 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::traits::Obligation; use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -224,21 +225,30 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool tcx.features().specialization() || tcx.features().min_specialization() } -/// Is `impl1` a specialization of `impl2`? +/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`? /// -/// Specialization is determined by the sets of types to which the impls apply; -/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies -/// to. +/// For every type that could apply to `specializing_impl_def_id`, we prove that +/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and +/// its where-clauses hold). +/// +/// For the purposes of const traits, we also check that the specializing +/// impl is not more restrictive than the parent impl. That is, if the +/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const` +/// bounds), then `specializing_impl_def_id` must also be const for the same +/// set of types. #[instrument(skip(tcx), level = "debug")] -pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { +pub(super) fn specializes( + tcx: TyCtxt<'_>, + (specializing_impl_def_id, parent_impl_def_id): (DefId, DefId), +) -> bool { // We check that the specializing impl comes from a crate that has specialization enabled, // or if the specializing impl is marked with `allow_internal_unstable`. // // We don't really care if the specialized impl (the parent) is in a crate that has // specialization enabled, since it's not being specialized, and it's already been checked // for coherence. - if !tcx.specialization_enabled_in(impl1_def_id.krate) { - let span = tcx.def_span(impl1_def_id); + if !tcx.specialization_enabled_in(specializing_impl_def_id.krate) { + let span = tcx.def_span(specializing_impl_def_id); if !span.allows_unstable(sym::specialization) && !span.allows_unstable(sym::min_specialization) { @@ -246,7 +256,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, } } - let impl1_trait_header = tcx.impl_trait_header(impl1_def_id).unwrap(); + let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id).unwrap(); // We determine whether there's a subset relationship by: // @@ -261,27 +271,123 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // See RFC 1210 for more details and justification. // Currently we do not allow e.g., a negative impl to specialize a positive one - if impl1_trait_header.polarity != tcx.impl_polarity(impl2_def_id) { + if specializing_impl_trait_header.polarity != tcx.impl_polarity(parent_impl_def_id) { return false; } - // create a parameter environment corresponding to an identity instantiation of impl1, - // i.e. the most generic instantiation of impl1. - let param_env = tcx.param_env(impl1_def_id); + // create a parameter environment corresponding to an identity instantiation of the specializing impl, + // i.e. the most generic instantiation of the specializing impl. + let param_env = tcx.param_env(specializing_impl_def_id); - // Create an infcx, taking the predicates of impl1 as assumptions: + // Create an infcx, taking the predicates of the specializing impl as assumptions: let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); - // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication( - &infcx, + let specializing_impl_trait_ref = + specializing_impl_trait_header.trait_ref.instantiate_identity(); + let cause = &ObligationCause::dummy(); + debug!( + "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", + param_env, specializing_impl_trait_ref, parent_impl_def_id + ); + + // Attempt to prove that the parent impl applies, given all of the above. + + let ocx = ObligationCtxt::new(&infcx); + let specializing_impl_trait_ref = ocx.normalize(cause, param_env, specializing_impl_trait_ref); + + if !ocx.select_all_or_error().is_empty() { + infcx.dcx().span_delayed_bug( + infcx.tcx.def_span(specializing_impl_def_id), + format!("failed to fully normalize {specializing_impl_trait_ref}"), + ); + return false; + } + + let parent_args = infcx.fresh_args_for_item(DUMMY_SP, parent_impl_def_id); + let parent_impl_trait_ref = ocx.normalize( + cause, param_env, - impl1_trait_header.trait_ref.instantiate_identity(), - impl1_def_id, - impl2_def_id, - &ObligationCause::dummy(), - ) - .is_ok() + infcx + .tcx + .impl_trait_ref(parent_impl_def_id) + .expect("expected source impl to be a trait impl") + .instantiate(infcx.tcx, parent_args), + ); + + // do the impls unify? If not, no specialization. + let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref) + else { + return false; + }; + + // Now check that the source trait ref satisfies all the where clauses of the target impl. + // This is not just for correctness; we also need this to constrain any params that may + // only be referenced via projection predicates. + let predicates = ocx.normalize( + cause, + param_env, + infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args), + ); + let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates); + ocx.register_obligations(obligations); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + // no dice! + debug!( + "fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + specializing_impl_trait_ref, + parent_impl_trait_ref, + errors, + param_env.caller_bounds() + ); + return false; + } + + // If the parent impl is const, then the specializing impl must be const, + // and it must not be *more restrictive* than the parent impl (that is, + // it cannot be const in fewer cases than the parent impl). + if tcx.is_conditionally_const(parent_impl_def_id) { + if !tcx.is_conditionally_const(specializing_impl_def_id) { + return false; + } + + let const_conditions = ocx.normalize( + cause, + param_env, + infcx.tcx.const_conditions(parent_impl_def_id).instantiate(infcx.tcx, parent_args), + ); + ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, _)| { + Obligation::new( + infcx.tcx, + cause.clone(), + param_env, + trait_ref.to_host_effect_clause(infcx.tcx, ty::BoundConstness::Maybe), + ) + })); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + // no dice! + debug!( + "fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + specializing_impl_trait_ref, + parent_impl_trait_ref, + errors, + param_env.caller_bounds() + ); + return false; + } + } + + debug!( + "fulfill_implication: an impl for {:?} specializes {:?}", + specializing_impl_trait_ref, parent_impl_trait_ref + ); + + true } /// Query provider for `specialization_graph_of`. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 5ddca9c4dce88..0d24b0558c594 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -612,6 +612,20 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_fma(x: T, y: T, z: T) -> T; + /// Computes `(x*y) + z` for each element, non-deterministically executing either + /// a fused multiply-add or two operations with rounding of the intermediate result. + /// + /// The operation is fused if the code generator determines that target instruction + /// set has support for a fused operation, and that the fused operation is more efficient + /// than the equivalent, separate pair of mul and add instructions. It is unspecified + /// whether or not a fused operation is selected, and that may depend on optimization + /// level and context, for example. + /// + /// `T` must be a vector of floats. + #[cfg(not(bootstrap))] + #[rustc_nounwind] + pub fn simd_relaxed_fma(x: T, y: T, z: T) -> T; + // Computes the sine of each element. /// /// `T` must be a vector of floats. diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 73bc7195ac24c..026c26479d355 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -765,6 +765,54 @@ impl Kind { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +struct Libdir { + compiler: Compiler, + target: TargetSelection, +} + +impl Step for Libdir { + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let relative_sysroot_libdir = builder.sysroot_libdir_relative(self.compiler); + let sysroot = builder.sysroot(self.compiler).join(relative_sysroot_libdir).join("rustlib"); + + if !builder.config.dry_run() { + // Avoid deleting the `rustlib/` directory we just copied (in `impl Step for + // Sysroot`). + if !builder.download_rustc() { + let sysroot_target_libdir = sysroot.join(self.target).join("lib"); + builder.verbose(|| { + eprintln!( + "Removing sysroot {} to avoid caching bugs", + sysroot_target_libdir.display() + ) + }); + let _ = fs::remove_dir_all(&sysroot_target_libdir); + t!(fs::create_dir_all(&sysroot_target_libdir)); + } + + if self.compiler.stage == 0 { + // The stage 0 compiler for the build triple is always pre-built. Ensure that + // `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use + // it when run. + dist::maybe_install_llvm_target( + builder, + self.compiler.host, + &builder.sysroot(self.compiler), + ); + } + } + + sysroot + } +} + impl<'a> Builder<'a> { fn get_step_descriptions(kind: Kind) -> Vec { macro_rules! describe { @@ -1165,56 +1213,13 @@ impl<'a> Builder<'a> { /// Returns the bindir for a compiler's sysroot. pub fn sysroot_target_bindir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf { - self.sysroot_target_libdir(compiler, target).parent().unwrap().join("bin") + self.ensure(Libdir { compiler, target }).join(target).join("bin") } /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. pub fn sysroot_target_libdir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf { - #[derive(Debug, Clone, Hash, PartialEq, Eq)] - struct Libdir { - compiler: Compiler, - target: TargetSelection, - } - impl Step for Libdir { - type Output = PathBuf; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - fn run(self, builder: &Builder<'_>) -> PathBuf { - let lib = builder.sysroot_libdir_relative(self.compiler); - let sysroot = builder - .sysroot(self.compiler) - .join(lib) - .join("rustlib") - .join(self.target) - .join("lib"); - // Avoid deleting the rustlib/ directory we just copied - // (in `impl Step for Sysroot`). - if !builder.download_rustc() { - builder.verbose(|| { - println!("Removing sysroot {} to avoid caching bugs", sysroot.display()) - }); - let _ = fs::remove_dir_all(&sysroot); - t!(fs::create_dir_all(&sysroot)); - } - - if self.compiler.stage == 0 { - // The stage 0 compiler for the build triple is always pre-built. - // Ensure that `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use it when run. - dist::maybe_install_llvm_target( - builder, - self.compiler.host, - &builder.sysroot(self.compiler), - ); - } - - sysroot - } - } - self.ensure(Libdir { compiler, target }) + self.ensure(Libdir { compiler, target }).join(target).join("lib") } pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a1c8bff0db97e..b2ffbd9c70f6a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -738,3 +738,49 @@ mod dist { ]); } } + +mod sysroot_target_dirs { + use super::{ + Build, Builder, Compiler, TEST_TRIPLE_1, TEST_TRIPLE_2, TargetSelection, configure, + }; + + #[test] + fn test_sysroot_target_libdir() { + let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); + let builder = Builder::new(&build); + let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); + let compiler = Compiler { stage: 1, host: target_triple_1 }; + let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); + let actual = builder.sysroot_target_libdir(compiler, target_triple_2); + + assert_eq!( + builder + .sysroot(compiler) + .join(builder.sysroot_libdir_relative(compiler)) + .join("rustlib") + .join(TEST_TRIPLE_2) + .join("lib"), + actual + ); + } + + #[test] + fn test_sysroot_target_bindir() { + let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); + let builder = Builder::new(&build); + let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); + let compiler = Compiler { stage: 1, host: target_triple_1 }; + let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); + let actual = builder.sysroot_target_bindir(compiler, target_triple_2); + + assert_eq!( + builder + .sysroot(compiler) + .join(builder.sysroot_libdir_relative(compiler)) + .join("rustlib") + .join(TEST_TRIPLE_2) + .join("bin"), + actual + ); + } +} diff --git a/tests/run-make/apple-deployment-target/rmake.rs b/tests/run-make/apple-deployment-target/rmake.rs index fed6d310770c0..0ae95cb1f4b16 100644 --- a/tests/run-make/apple-deployment-target/rmake.rs +++ b/tests/run-make/apple-deployment-target/rmake.rs @@ -24,21 +24,31 @@ fn minos(file: &str, version: &str) { fn main() { // These versions should generally be higher than the default versions - let (env_var, example_version, higher_example_version) = match apple_os() { - "macos" => ("MACOSX_DEPLOYMENT_TARGET", "12.0", "13.0"), + let (example_version, higher_example_version) = match apple_os() { + "macos" => ("12.0", "13.0"), // armv7s-apple-ios and i386-apple-ios only supports iOS 10.0 - "ios" if target() == "armv7s-apple-ios" || target() == "i386-apple-ios" => { - ("IPHONEOS_DEPLOYMENT_TARGET", "10.0", "10.0") - } - "ios" => ("IPHONEOS_DEPLOYMENT_TARGET", "15.0", "16.0"), - "watchos" => ("WATCHOS_DEPLOYMENT_TARGET", "7.0", "9.0"), - "tvos" => ("TVOS_DEPLOYMENT_TARGET", "14.0", "15.0"), - "visionos" => ("XROS_DEPLOYMENT_TARGET", "1.1", "1.2"), + "ios" if target() == "armv7s-apple-ios" || target() == "i386-apple-ios" => ("10.0", "10.0"), + "ios" => ("15.0", "16.0"), + "watchos" => ("7.0", "9.0"), + "tvos" => ("14.0", "15.0"), + "visionos" => ("1.1", "1.2"), _ => unreachable!(), }; - let default_version = - rustc().target(target()).env_remove(env_var).print("deployment-target").run().stdout_utf8(); - let default_version = default_version.strip_prefix("deployment_target=").unwrap().trim(); + + // Remove env vars to get `rustc`'s default + let output = rustc() + .target(target()) + .env_remove("MACOSX_DEPLOYMENT_TARGET") + .env_remove("IPHONEOS_DEPLOYMENT_TARGET") + .env_remove("WATCHOS_DEPLOYMENT_TARGET") + .env_remove("TVOS_DEPLOYMENT_TARGET") + .env_remove("XROS_DEPLOYMENT_TARGET") + .print("deployment-target") + .run() + .stdout_utf8(); + let (env_var, default_version) = output.split_once('=').unwrap(); + let env_var = env_var.trim(); + let default_version = default_version.trim(); // Test that version makes it to the object file. run_in_tmpdir(|| { diff --git a/tests/run-make/apple-sdk-version/rmake.rs b/tests/run-make/apple-sdk-version/rmake.rs index 6463ec0040359..43e805772043e 100644 --- a/tests/run-make/apple-sdk-version/rmake.rs +++ b/tests/run-make/apple-sdk-version/rmake.rs @@ -26,8 +26,7 @@ fn main() { // Fetch rustc's inferred deployment target. let current_deployment_target = rustc().target(target()).print("deployment-target").run().stdout_utf8(); - let current_deployment_target = - current_deployment_target.strip_prefix("deployment_target=").unwrap().trim(); + let current_deployment_target = current_deployment_target.split('=').last().unwrap().trim(); // Fetch current SDK version via. xcrun. // diff --git a/tests/ui/consts/const-eval-fail-too-big.rs b/tests/ui/consts/const-eval-fail-too-big.rs new file mode 100644 index 0000000000000..4b5dbc1d7a4ef --- /dev/null +++ b/tests/ui/consts/const-eval-fail-too-big.rs @@ -0,0 +1,12 @@ +//Error output test for #78834: Type is too big for the target architecture +struct B< + A: Sized = [(); { + let x = [0u8; !0usize]; + //~^ ERROR evaluation of constant value failed + 1 + }], +> { + a: A, +} + +fn main() {} diff --git a/tests/ui/consts/const-eval-fail-too-big.stderr b/tests/ui/consts/const-eval-fail-too-big.stderr new file mode 100644 index 0000000000000..ae6664832336e --- /dev/null +++ b/tests/ui/consts/const-eval-fail-too-big.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-fail-too-big.rs:4:28 + | +LL | let x = [0u8; !0usize]; + | ^^^^^^^^^^^^^^ values of the type `[u8; usize::MAX]` are too big for the target architecture + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs index 73c2cd23d86e3..1ed3767643a00 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.rs +++ b/tests/ui/higher-ranked/structually-relate-aliases.rs @@ -12,6 +12,5 @@ impl Overlap for T {} impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} //~^ ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied -//~| ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied fn main() {} diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index e9d91e45e217b..cf3e4cc85b912 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -10,17 +10,6 @@ help: consider restricting type parameter `T` LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} | ++++++++++++++++++++ -error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied - --> $DIR/structually-relate-aliases.rs:13:17 - | -LL | impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} - | ++++++++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr index 79581066a3a32..1cfc2a6d94495 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr @@ -8,10 +8,10 @@ LL | #![feature(lazy_type_alias)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: the trait bound `usize: Foo` is not satisfied - --> $DIR/alias-bounds-when-not-wf.rs:16:13 + --> $DIR/alias-bounds-when-not-wf.rs:16:15 | LL | fn hello(_: W>) {} - | ^^^^^^^^^^^ the trait `Foo` is not implemented for `usize` + | ^^^^^^^^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one --> $DIR/alias-bounds-when-not-wf.rs:6:1 diff --git a/tests/ui/print-request/macos-target.rs b/tests/ui/print-request/macos-target.rs index 197edd024746e..af74babbed48f 100644 --- a/tests/ui/print-request/macos-target.rs +++ b/tests/ui/print-request/macos-target.rs @@ -1,5 +1,6 @@ //@ only-apple //@ compile-flags: --print deployment-target +//@ normalize-stdout-test: "\w*_DEPLOYMENT_TARGET" -> "$$OS_DEPLOYMENT_TARGET" //@ normalize-stdout-test: "\d+\." -> "$$CURRENT_MAJOR_VERSION." //@ normalize-stdout-test: "\d+" -> "$$CURRENT_MINOR_VERSION" //@ check-pass diff --git a/tests/ui/print-request/macos-target.stdout b/tests/ui/print-request/macos-target.stdout index f55ef568ed67f..34ade570969f4 100644 --- a/tests/ui/print-request/macos-target.stdout +++ b/tests/ui/print-request/macos-target.stdout @@ -1 +1 @@ -deployment_target=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION +$OS_DEPLOYMENT_TARGET=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs index 9b14d410acbe3..24b9941133ee7 100644 --- a/tests/ui/simd/intrinsic/float-math-pass.rs +++ b/tests/ui/simd/intrinsic/float-math-pass.rs @@ -23,6 +23,7 @@ extern "rust-intrinsic" { fn simd_fexp(x: T) -> T; fn simd_fexp2(x: T) -> T; fn simd_fma(x: T, y: T, z: T) -> T; + fn simd_relaxed_fma(x: T, y: T, z: T) -> T; fn simd_flog(x: T) -> T; fn simd_flog10(x: T) -> T; fn simd_flog2(x: T) -> T; @@ -77,6 +78,9 @@ fn main() { let r = simd_fma(x, h, h); assert_approx_eq!(x, r); + let r = simd_relaxed_fma(x, h, h); + assert_approx_eq!(x, r); + let r = simd_fsqrt(x); assert_approx_eq!(x, r); diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr new file mode 100644 index 0000000000000..bd822970ad1ef --- /dev/null +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `Foo` for type `(_,)` + --> $DIR/overlap-const-with-nonconst.rs:23:1 + | +LL | / impl const Foo for T +LL | | where +LL | | T: ~const Bar, + | |__________________- first implementation here +... +LL | impl Foo for (T,) { + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs new file mode 100644 index 0000000000000..eb66d03faa638 --- /dev/null +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs @@ -0,0 +1,38 @@ +//@ revisions: spec min_spec + +#![feature(const_trait_impl)] +#![cfg_attr(spec, feature(specialization))] +//[spec]~^ WARN the feature `specialization` is incomplete +#![cfg_attr(min_spec, feature(min_specialization))] + +#[const_trait] +trait Bar {} +impl const Bar for T {} + +#[const_trait] +trait Foo { + fn method(&self); +} +impl const Foo for T +where + T: ~const Bar, +{ + default fn method(&self) {} +} +// specializing impl: +impl Foo for (T,) { +//~^ ERROR conflicting implementations + fn method(&self) { + println!("hi"); + } +} + +const fn dispatch(t: T) { + t.method(); +} + +fn main() { + const { + dispatch(((),)); + } +} diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr new file mode 100644 index 0000000000000..cbdcb45f6beba --- /dev/null +++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr @@ -0,0 +1,24 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-const-with-nonconst.rs:4:27 + | +LL | #![cfg_attr(spec, feature(specialization))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Foo` for type `(_,)` + --> $DIR/overlap-const-with-nonconst.rs:23:1 + | +LL | / impl const Foo for T +LL | | where +LL | | T: ~const Bar, + | |__________________- first implementation here +... +LL | impl Foo for (T,) { + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr index bffc60c65fcea..9166b8ca5d22b 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,11 +1,31 @@ -error: cannot specialize on const impl with non-const impl +error[E0119]: conflicting implementations of trait `Bar` --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1 | +LL | / impl const Bar for T +LL | | where +LL | | T: ~const Foo, + | |__________________- first implementation here +... LL | / impl Bar for T LL | | where LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier LL | | T: Specialize, - | |__________________^ + | |__________________^ conflicting implementation + +error[E0119]: conflicting implementations of trait `Baz` + --> $DIR/const-default-bound-non-const-specialized-bound.rs:48:1 + | +LL | / impl const Baz for T +LL | | where +LL | | T: ~const Foo, + | |__________________- first implementation here +... +LL | / impl const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz` +LL | | where +LL | | T: Foo, +LL | | T: Specialize, + | |__________________^ conflicting implementation -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr new file mode 100644 index 0000000000000..38fc5ddfbef52 --- /dev/null +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` + --> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1 + | +LL | impl const Value for T { + | ------------------------- first implementation here +... +LL | impl Value for FortyTwo { + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs index a3bb9b3f93eda..acf0a967a884d 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs @@ -1,7 +1,10 @@ // Tests that specializing trait impls must be at least as const as the default impl. +//@ revisions: spec min_spec #![feature(const_trait_impl)] -#![feature(min_specialization)] +#![cfg_attr(spec, feature(specialization))] +//[spec]~^ WARN the feature `specialization` is incomplete +#![cfg_attr(min_spec, feature(min_specialization))] #[const_trait] trait Value { @@ -16,7 +19,8 @@ impl const Value for T { struct FortyTwo; -impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl +impl Value for FortyTwo { + //~^ ERROR conflicting implementations fn value() -> u32 { println!("You can't do that (constly)"); 42 diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr new file mode 100644 index 0000000000000..b59c42f518936 --- /dev/null +++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr @@ -0,0 +1,22 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-default-impl-non-const-specialized-impl.rs:5:27 + | +LL | #![cfg_attr(spec, feature(specialization))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo` + --> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1 + | +LL | impl const Value for T { + | ------------------------- first implementation here +... +LL | impl Value for FortyTwo { + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr deleted file mode 100644 index e356621ba47ed..0000000000000 --- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot specialize on const impl with non-const impl - --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1 - | -LL | impl Value for FortyTwo { - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs index 632121924a63b..94b6da7124d29 100644 --- a/tests/ui/traits/const-traits/specializing-constness.rs +++ b/tests/ui/traits/const-traits/specializing-constness.rs @@ -21,8 +21,7 @@ impl const A for T { } impl A for T { -//~^ ERROR: cannot specialize -//FIXME(const_trait_impl) ~| ERROR: missing `~const` qualifier + //~^ ERROR conflicting implementations of trait `A` fn a() -> u32 { 3 } diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr index 21e21c2cb71aa..2ca70b53e4e21 100644 --- a/tests/ui/traits/const-traits/specializing-constness.stderr +++ b/tests/ui/traits/const-traits/specializing-constness.stderr @@ -1,8 +1,12 @@ -error: cannot specialize on const impl with non-const impl +error[E0119]: conflicting implementations of trait `A` --> $DIR/specializing-constness.rs:23:1 | +LL | impl const A for T { + | ---------------------------------- first implementation here +... LL | impl A for T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs index e1bd234a275a6..8fe53d6773b95 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.rs +++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs @@ -18,6 +18,6 @@ impl Overlap for T {} impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} //~^ ERROR cannot find type `Missing` in this scope -//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied +//~| ERROR the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied fn main() {} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index f6545c6ebf9de..09162970d33da 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -26,17 +26,16 @@ LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } -error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied - --> $DIR/issue-118950-root-region.rs:19:17 +error[E0277]: the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied + --> $DIR/issue-118950-root-region.rs:19:47 | LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T` + | ^ the trait `Overlap fn(Assoc<'a, T>)>` is not implemented for `T` | -help: this trait has no implementations, consider adding one - --> $DIR/issue-118950-root-region.rs:8:1 +help: consider further restricting type parameter `T` | -LL | trait ToUnit<'a> { - | ^^^^^^^^^^^^^^^^ +LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap, T: Overlap fn(Assoc<'a, T>)> {} + | ++++++++++++++++++++++++++++++++++++++ error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs b/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs new file mode 100644 index 0000000000000..1dca19d28e9ac --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs @@ -0,0 +1,46 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Minimized example from `rustc_type_ir` that demonstrates a missing deep normalization +// in the new solver when computing the implies outlives bounds of an impl. + +use std::marker::PhantomData; +use std::ops::Deref; + +pub struct SearchGraph::Cx> { + d: PhantomData, + x: PhantomData, +} + +pub trait Delegate { + type Cx; +} + +struct SearchGraphDelegate { + _marker: PhantomData, +} + +impl Delegate for SearchGraphDelegate +where + D: SolverDelegate, +{ + type Cx = D::Interner; +} + +pub trait SolverDelegate { + type Interner; +} + +struct EvalCtxt<'a, D, I> +where + D: SolverDelegate, +{ + search_graph: &'a SearchGraph>, +} + +impl<'a, D, I> EvalCtxt<'a, D, ::Interner> +where + D: SolverDelegate +{} + +fn main() {}