Auto merge of #133788 - matthiaskrgr:rollup-1p100a8, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #132723 (Unify `sysroot_target_{bin,lib}dir` handling)
 - #133041 (Print name of env var in `--print=deployment-target`)
 - #133325 (Reimplement `~const` trait specialization)
 - #133395 (Add simd_relaxed_fma intrinsic)
 - #133517 (Deeply normalize when computing implied outlives bounds)
 - #133785 (Add const evaluation error UI test.)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-12-03 09:47:39 +00:00
commit ae3703cdf2
44 changed files with 535 additions and 168 deletions

View file

@ -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() {

View file

@ -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",

View file

@ -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
) {

View file

@ -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",

View file

@ -415,6 +415,10 @@ impl<O: ForestObligation> ObligationForest<O> {
.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

View file

@ -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)]

View file

@ -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

View file

@ -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),

View file

@ -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();

View file

@ -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 {

View file

@ -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`.

View file

@ -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

View file

@ -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,

View file

@ -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()
}

View file

@ -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())
}

View file

@ -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) }
}

View file

@ -59,12 +59,16 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Result<Vec<OutlivesBound<'tcx>>, 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<Out = U>`,
// 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)
};

View file

@ -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`.

View file

@ -612,6 +612,20 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn simd_fma<T>(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<T>(x: T, y: T, z: T) -> T;
// Computes the sine of each element.
///
/// `T` must be a vector of floats.

View file

@ -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<StepDescription> {
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 {

View file

@ -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
);
}
}

View file

@ -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(|| {

View file

@ -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.
//

View file

@ -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() {}

View file

@ -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`.

View file

@ -12,6 +12,5 @@ impl<T> Overlap<T> for T {}
impl<T> Overlap<for<'a> 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() {}

View file

@ -10,17 +10,6 @@ help: consider restricting type parameter `T`
LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> 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<T> Overlap<for<'a> 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<T: for<'a> ToUnit<'a>> Overlap<for<'a> 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`.

View file

@ -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<A<usize>>) {}
| ^^^^^^^^^^^ 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

View file

@ -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

View file

@ -1 +1 @@
deployment_target=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION
$OS_DEPLOYMENT_TARGET=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION

View file

@ -23,6 +23,7 @@ extern "rust-intrinsic" {
fn simd_fexp<T>(x: T) -> T;
fn simd_fexp2<T>(x: T) -> T;
fn simd_fma<T>(x: T, y: T, z: T) -> T;
fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
fn simd_flog<T>(x: T) -> T;
fn simd_flog10<T>(x: T) -> T;
fn simd_flog2<T>(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);

View file

@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `Foo` for type `(_,)`
--> $DIR/overlap-const-with-nonconst.rs:23:1
|
LL | / impl<T> const Foo for T
LL | | where
LL | | T: ~const Bar,
| |__________________- first implementation here
...
LL | impl<T> Foo for (T,) {
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View file

@ -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<T> const Bar for T {}
#[const_trait]
trait Foo {
fn method(&self);
}
impl<T> const Foo for T
where
T: ~const Bar,
{
default fn method(&self) {}
}
// specializing impl:
impl<T> Foo for (T,) {
//~^ ERROR conflicting implementations
fn method(&self) {
println!("hi");
}
}
const fn dispatch<T: ~const Bar + Copy>(t: T) {
t.method();
}
fn main() {
const {
dispatch(((),));
}
}

View file

@ -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 <https://github.com/rust-lang/rust/issues/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<T> const Foo for T
LL | | where
LL | | T: ~const Bar,
| |__________________- first implementation here
...
LL | impl<T> 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`.

View file

@ -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<T> const Bar for T
LL | | where
LL | | T: ~const Foo,
| |__________________- first implementation here
...
LL | / impl<T> Bar for T
LL | | where
LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier
LL | | T: Specialize,
| |__________________^
| |__________________^ conflicting implementation
error: aborting due to 1 previous error
error[E0119]: conflicting implementations of trait `Baz`
--> $DIR/const-default-bound-non-const-specialized-bound.rs:48:1
|
LL | / impl<T> const Baz for T
LL | | where
LL | | T: ~const Foo,
| |__________________- first implementation here
...
LL | / impl<T> 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 2 previous errors
For more information about this error, try `rustc --explain E0119`.

View file

@ -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<T> 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`.

View file

@ -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<T> 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

View file

@ -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 <https://github.com/rust-lang/rust/issues/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<T> 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`.

View file

@ -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

View file

@ -21,8 +21,7 @@ impl<T: ~const Spec> const A for T {
}
impl<T: Spec + Sup> A for T {
//~^ ERROR: cannot specialize
//FIXME(const_trait_impl) ~| ERROR: missing `~const` qualifier
//~^ ERROR conflicting implementations of trait `A`
fn a() -> u32 {
3
}

View file

@ -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<T: ~const Spec> const A for T {
| ---------------------------------- first implementation here
...
LL | impl<T: Spec + Sup> A for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View file

@ -18,6 +18,6 @@ impl<T> Overlap<T> for T {}
impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
//~^ 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<for<'a> fn(Assoc<'a, T>)>` is not satisfied
fn main() {}

View file

@ -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<for<'a> fn(Assoc<'a, T>)>` is not satisfied
--> $DIR/issue-118950-root-region.rs:19:47
|
LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T`
| ^ the trait `Overlap<for<'a> 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<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T>, T: Overlap<for<'a> fn(Assoc<'a, T>)> {}
| ++++++++++++++++++++++++++++++++++++++
error: aborting due to 3 previous errors; 1 warning emitted

View file

@ -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<D: Delegate, X = <D as Delegate>::Cx> {
d: PhantomData<D>,
x: PhantomData<X>,
}
pub trait Delegate {
type Cx;
}
struct SearchGraphDelegate<D: SolverDelegate> {
_marker: PhantomData<D>,
}
impl<D> Delegate for SearchGraphDelegate<D>
where
D: SolverDelegate,
{
type Cx = D::Interner;
}
pub trait SolverDelegate {
type Interner;
}
struct EvalCtxt<'a, D, I>
where
D: SolverDelegate<Interner = I>,
{
search_graph: &'a SearchGraph<SearchGraphDelegate<D>>,
}
impl<'a, D, I> EvalCtxt<'a, D, <D as SolverDelegate>::Interner>
where
D: SolverDelegate<Interner = I>
{}
fn main() {}