diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index ee0cef350b42f..ac86fbe7428b0 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -790,6 +790,9 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { unreachable!("clobber-only") } InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::dreg) => "e", + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::qreg) => "e", InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), InlineAsmRegClass::Err => unreachable!(), } @@ -896,6 +899,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl unreachable!("clobber-only") } InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::dreg) => cx.type_f64(), + InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::qreg) => cx.type_f128(), InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 31701acd7bf78..e715f9cd16c9d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -734,6 +734,16 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> } else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) { // LLVM doesn't recognize r14 "{lr}".to_string() + } else if let InlineAsmReg::Sparc(reg) = reg + && let Some(num) = reg.dreg_number() + { + // LLVM numbers d registers sequentially (d0 => d0, d2 => d1, d4 => d2 etc.) + format!("{{d{}}}", num / 2) + } else if let InlineAsmReg::Sparc(reg) = reg + && let Some(num) = reg.qreg_number() + { + // LLVM numbers q registers sequentially (q0 => q0, q4 => q1, q8 => q2 etc.) + format!("{{q{}}}", num / 4) } else { format!("{{{}}}", reg.name()) } @@ -820,6 +830,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> unreachable!("clobber-only") } Sparc(SparcInlineAsmRegClass::reg) => "r", + Sparc(SparcInlineAsmRegClass::freg) => "f", + Sparc(SparcInlineAsmRegClass::dreg | SparcInlineAsmRegClass::qreg) => "e", Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), Msp430(Msp430InlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg) => "r", @@ -1043,6 +1055,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' unreachable!("clobber-only") } Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(), + Sparc(SparcInlineAsmRegClass::freg) => cx.type_f32(), + Sparc(SparcInlineAsmRegClass::dreg) => cx.type_f64(), + Sparc(SparcInlineAsmRegClass::qreg) => cx.type_f128(), Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"), Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_ssa/src/diagnostics.rs b/compiler/rustc_codegen_ssa/src/diagnostics.rs index 2b77eb2cf24fb..078822af09561 100644 --- a/compiler/rustc_codegen_ssa/src/diagnostics.rs +++ b/compiler/rustc_codegen_ssa/src/diagnostics.rs @@ -1193,6 +1193,12 @@ pub(crate) struct XcrunSdkPathWarning { #[diag("enabling the `neon` target feature on the current target is unsound due to ABI issues")] pub(crate) struct Aarch64SoftfloatNeon; +#[derive(Diagnostic)] +#[diag( + "enabling the `sse` target feature on the current target is unsupported due to LLVM backend issues" +)] +pub(crate) struct X86SoftfloatSse; + #[derive(Diagnostic)] #[diag("ignoring feature with missing prefix in `-Ctarget-feature`: `{$feature}`")] #[note("features must begin with a `+` to enable or `-` to disable it")] diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 2150cbd17aec8..96ded8f6a2002 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -3,7 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::attrs::InstructionSetAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_lint_defs::builtin::AARCH64_SOFTFLOAT_NEON; +use rustc_lint_defs::builtin::{AARCH64_SOFTFLOAT_NEON, X86_SOFTFLOAT_SSE}; use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -99,6 +99,8 @@ pub(crate) fn from_target_feature_attr( if abi_feature_constraints.incompatible.contains(&name.as_str()) { // For "neon" specifically, we emit an FCW instead of a hard error. // See . + // Similar for "sse" on x86. + // See . if tcx.sess.target.arch == Arch::AArch64 && name.as_str() == "neon" { tcx.emit_node_span_lint( AARCH64_SOFTFLOAT_NEON, @@ -106,6 +108,15 @@ pub(crate) fn from_target_feature_attr( feature_span, diagnostics::Aarch64SoftfloatNeon, ); + } else if matches!(tcx.sess.target.arch, Arch::X86 | Arch::X86_64) + && name.as_str() == "sse" + { + tcx.emit_node_span_lint( + X86_SOFTFLOAT_SSE, + tcx.local_def_id_to_hir_id(did), + feature_span, + diagnostics::X86SoftfloatSse, + ); } else { tcx.dcx().emit_err(diagnostics::InternalOnlyTargetFeatureAttr { span: feature_span, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4fa104ad6dbfe..b487187842029 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -22,7 +22,7 @@ use std::num::NonZero; use std::ops::DerefMut; use std::path::{Path, PathBuf}; use std::thread::ThreadId; -use std::{assert_matches, fmt, panic}; +use std::{assert_matches, fmt, mem, panic}; use Level::*; // Used by external projects such as `rust-gpu`. @@ -336,6 +336,15 @@ struct DiagCtxtInner { /// twice. emitted_diagnostics: FxHashSet, + /// We only want to emit `recursion_depth_exceeding_limit` once per + /// crate. Otherwise crates like `calimero-store` emit more than + /// a thousand warnings. + /// + /// We only check this in `TRACK_DIAGNOSTIC` meaning that the diagnostics + /// still get tracked by the query system, even if they don't get emitted + /// to users. + emitted_recursion_depth_exceeding_limit: bool, + /// Stashed diagnostics emitted in one stage of the compiler that may be /// stolen and emitted/cancelled by other stages (e.g. to improve them and /// add more information). All stashed diagnostics must be emitted with @@ -527,6 +536,7 @@ impl DiagCtxt { taught_diagnostics, emitted_diagnostic_codes, emitted_diagnostics, + emitted_recursion_depth_exceeding_limit, stashed_diagnostics, future_breakage_diagnostics, fulfilled_expectations, @@ -547,6 +557,7 @@ impl DiagCtxt { *taught_diagnostics = Default::default(); *emitted_diagnostic_codes = Default::default(); *emitted_diagnostics = Default::default(); + *emitted_recursion_depth_exceeding_limit = false; *stashed_diagnostics = Default::default(); *future_breakage_diagnostics = Default::default(); *fulfilled_expectations = Default::default(); @@ -879,7 +890,7 @@ impl<'a> DiagCtxtHandle<'a> { pub fn emit_future_breakage_report(&self) { let inner = &mut *self.inner.borrow_mut(); - let diags = std::mem::take(&mut inner.future_breakage_diagnostics); + let diags = mem::take(&mut inner.future_breakage_diagnostics); if !diags.is_empty() { inner.emitter.emit_future_breakage_report(diags); } @@ -919,7 +930,7 @@ impl<'a> DiagCtxtHandle<'a> { /// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled. #[must_use] pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet { - std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) + mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } /// Trigger an ICE if there are any delayed bugs and no hard errors. @@ -1195,6 +1206,7 @@ impl DiagCtxtInner { taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), + emitted_recursion_depth_exceeding_limit: false, stashed_diagnostics: Default::default(), future_breakage_diagnostics: Vec::new(), fulfilled_expectations: Default::default(), @@ -1207,7 +1219,7 @@ impl DiagCtxtInner { fn emit_stashed_diagnostics(&mut self) -> Option { let mut guar = None; let has_errors = !self.err_guars.is_empty(); - for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { + for (_, stashed_diagnostics) in mem::take(&mut self.stashed_diagnostics).into_iter() { for (_, (diag, _guar, _thread)) in stashed_diagnostics { if !diag.is_error() { // Unless they're forced, don't flush stashed warnings when @@ -1334,10 +1346,19 @@ impl DiagCtxtInner { let is_error = diagnostic.is_error(); let is_lint = diagnostic.is_lint.is_some(); + // We only emit the first occurrence of `recursion_depth_exceeding_limit`. + let silence_recursion_depth_exceeded_limit = + diagnostic.is_lint.as_ref().is_some_and(|lint| { + lint.name.eq_ignore_ascii_case( + rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT.name, + ) && mem::replace(&mut self.emitted_recursion_depth_exceeding_limit, true) + }); // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. - if !(self.flags.deduplicate_diagnostics && already_emitted) { + if !silence_recursion_depth_exceeded_limit + && !(self.flags.deduplicate_diagnostics && already_emitted) + { debug!(?diagnostic); debug!(?self.emitted_diagnostics); @@ -1460,8 +1481,7 @@ impl DiagCtxtInner { return; } - let bugs: Vec<_> = - std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); + let bugs: Vec<_> = mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0")); let decorate = backtrace || self.ice_file.is_none(); diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 20b8a04099049..ef287b737851f 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -17,6 +17,13 @@ pub(crate) use precise_captures::*; pub(crate) mod remove_or_use_generic; +#[derive(Diagnostic)] +#[diag("complex const arguments must be placed inside of a `const` block")] +pub(crate) struct ComplexConstArg { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`")] pub(crate) struct AmbiguousAssocItem<'a> { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4bdfc328a8522..92f89c2834408 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-file-filelength + //! HIR ty lowering: Lowers type-system entities[^1] from the [HIR][hir] to //! the [`rustc_middle::ty`] representation. //! @@ -2523,6 +2525,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_value(tcx, valtree, ty) } + fn try_recover_misrepresented_function_call( + &self, + hir_self_ty: &hir::Ty<'_>, + span: Span, + ) -> Option { + // Only an enum can host a tuple-variant constructor (`>::Some(..)`). + // For any other self type, a type-relative call is an associated function, not a + // constructor, and must be wrapped in `const { ... }`. We catch that here, before + // lowering the self type, so a generic struct/union written without its args + // (`FieldName::len()`, from `tracing`'s macros) reports this clear error instead + // of a spurious E0107 "missing generics" (#157152), and a primitive or foreign + // type reports it instead of an opaque downstream resolution error. Enums, + // aliases, `Self` and type parameters are let through: each may resolve to an + // enum, so they must reach constructor lowering. + let self_ty_res = match hir_self_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res, + _ => Res::Err, + }; + matches!( + self_ty_res, + Res::Def(DefKind::Struct | DefKind::Union | DefKind::ForeignTy, _) | Res::PrimTy(_) + ) + .then(|| self.dcx().emit_err(diagnostics::ComplexConstArg { span })) + } + fn lower_const_arg_tuple_call( &self, hir_id: HirId, @@ -2543,6 +2570,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_resolved_const_path(opt_self_ty, path, hir_id) } hir::QPath::TypeRelative(hir_self_ty, segment) => { + if let Some(e) = self.try_recover_misrepresented_function_call(hir_self_ty, span) { + return ty::Const::new_error(tcx, e); + } + let self_ty = self.lower_ty(hir_self_ty); match self.lower_type_relative_const_path( self_ty, @@ -2576,10 +2607,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (tcx.adt_def(parent_did), fn_args, parent_did) } _ => { - let e = self.dcx().span_err( - span, - "complex const arguments must be placed inside of a `const` block", - ); + let e = self.dcx().emit_err(diagnostics::ComplexConstArg { span }); return Const::new_error(tcx, e); } }; diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index bab3c207984f6..85e9e612dfc9c 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -85,7 +85,7 @@ impl<'tcx> InferCtxt<'tcx> { .placeholder_assumptions_for_next_solver .clone(), next_trait_solver: self.next_trait_solver, - enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(), obligation_inspector: self.obligation_inspector.clone(), canonicalizer_state: Default::default(), } @@ -115,7 +115,7 @@ impl<'tcx> InferCtxt<'tcx> { .placeholder_assumptions_for_next_solver .clone(), next_trait_solver: self.next_trait_solver, - enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(), obligation_inspector: self.obligation_inspector.clone(), canonicalizer_state: Default::default(), }; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 84ffccd6f2c80..5eafe73301ba7 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -27,7 +27,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn enable_next_solver_overflow_fcw(&self) -> bool { - self.enable_next_solver_overflow_fcw + self.enable_next_solver_overflow_fcw.get() } fn disable_trait_solver_fast_paths(&self) -> bool { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 906ffe710e03a..eed1e42311e65 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -345,7 +345,7 @@ pub struct InferCtxt<'tcx> { /// already used by default in some places so we know they won't have /// additional breakages. We also don't want spurious result in coherence /// checking so we disable the FCW there as well. - enable_next_solver_overflow_fcw: bool, + enable_next_solver_overflow_fcw: Cell, pub obligation_inspector: Cell>>, @@ -691,7 +691,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { universe: Cell::new(ty::UniverseIndex::ROOT), placeholder_assumptions_for_next_solver: RefCell::new(Default::default()), next_trait_solver, - enable_next_solver_overflow_fcw, + enable_next_solver_overflow_fcw: Cell::new(enable_next_solver_overflow_fcw), obligation_inspector: Cell::new(None), canonicalizer_state: Default::default(), } @@ -1556,6 +1556,18 @@ impl<'tcx> InferCtxt<'tcx> { u } + /// We need to disable the fcw if we're already in a fcw emitting to avoid + /// indefinite triggering. + pub fn with_disabled_next_solver_overflow_fcw(&self, mut f: F) -> R + where + F: FnMut() -> R, + { + let prev = self.enable_next_solver_overflow_fcw.replace(false); + let ret = f(); + self.enable_next_solver_overflow_fcw.set(prev); + ret + } + /// Extract [`ty::TypingMode`] of this inference context to get a `TypingEnv` /// which contains the necessary information to use the trait system without /// using canonicalization or carrying this inference context around. diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5ee3c5a741bdc..d7339d1b60269 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -157,6 +157,7 @@ pub mod hardwired { USELESS_DEPRECATED, VARARGS_WITHOUT_PATTERN, WARNINGS, + X86_SOFTFLOAT_SSE, // tidy-alphabetical-end ] } @@ -5367,7 +5368,7 @@ declare_lint! { /// on this target due to this issue, but the problem was not known at the time of /// stabilization. pub AARCH64_SOFTFLOAT_NEON, - Warn, + Deny, "detects code that could be affected by ABI issues on aarch64 softfloat targets", @future_incompatible = FutureIncompatibleInfo { reason: fcw!(FutureReleaseError #134375), @@ -5375,6 +5376,45 @@ declare_lint! { }; } +declare_lint! { + /// The `x86_softfloat_sse` lint detects usage of `#[target_feature(enable = "sse")]` or target + /// features that imply SSE on softfloat x86 and x86-64 targets. Enabling this target feature + /// in a soft-float configuration is not supported by LLVM and can lead to crashes. + /// + /// ### Example + /// + /// ```rust,ignore (needs x86_64-unknown-none) + /// #[target_feature(enable = "avx")] + /// fn with_avx() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: enabling the `sse` target feature on the current target is unsupported due to LLVM backend issues + /// --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18 + /// | + /// | #[target_feature(enable = "avx")] + /// | ^^^^^^^^^^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #117938 + /// ``` + /// + /// ### Explanation + /// + /// LLVM does not support combining the `soft-float` target feature (which is implicitly enabled + /// on these targets) with `sse`. This can lead to crashes of the backend. To prevent that, + /// Rust is turning that combination into an error. + pub X86_SOFTFLOAT_SSE, + Deny, + "detects code that could be affected by LLVM backend issues on x86 softfloat targets", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #117938), + report_in_deps: true, + }; +} + declare_lint! { /// The `tail_call_track_caller` lint detects usage of `become` attempting to tail call /// a function marked with `#[track_caller]`. diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index ba790cadfe24f..03ff0716ad979 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -115,7 +115,7 @@ use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput, - SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, + RequiredDepth, SizedTraitKind, Ty, TyCtxt, TyCtxtFeed, }; use crate::{mir, thir}; @@ -2643,7 +2643,7 @@ rustc_queries! { /// Used by `-Znext-solver` to compute proof trees. query evaluate_root_goal_for_proof_tree_raw( key: (solve::CanonicalInput<'tcx>, usize) - ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>) { + ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>, RequiredDepth) { no_hash desc { "computing proof tree for `{}` with depth `{}`", key.0.canonical.value.goal.predicate, key.1 } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7dcd364bde8bf..23c02ffcb09c4 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -172,7 +172,7 @@ impl_erasable_for_types_with_no_type_params! { // tidy-alphabetical-start (&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>), (), - (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>), + (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>, ty::RequiredDepth), Option<&'_ OsStr>, Option<&'_ [rustc_hir::PreciseCapturingArgKind]>, Option<(mir::ConstValue, Ty<'_>)>, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 637fc1d34b9e1..048e509ec88e0 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -5,13 +5,10 @@ use std::{debug_assert_matches, fmt}; use rustc_data_structures::intern::Interned; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::CRATE_HIR_ID; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def::{CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT; +use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_structures::Limit; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::{ BoundVar, CollectAndApply, DebruijnIndex, Interner, TypeFoldable, Unnormalized, VisitorResult, @@ -24,10 +21,9 @@ use crate::traits::cache::WithDepNode; use crate::traits::solve::{ self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, }; -use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ self, BoundRegion, Clause, Const, List, ParamTy, Pattern, PolyExistentialPredicate, Predicate, - Region, RegionKind, Ty, TyCtxt, + Region, RegionKind, RequiredDepth, Ty, TyCtxt, }; #[allow(rustc::usage_of_ty_tykind)] @@ -672,45 +668,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, canonical_goal: CanonicalInput<'tcx>, root_depth: usize, - ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>) { + ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>, RequiredDepth) { self.evaluate_root_goal_for_proof_tree_raw((canonical_goal, root_depth)) } - fn emit_next_solver_overflow_fcw(self, predicate: ty::Predicate<'tcx>, span: Span) { - self.emit_node_span_lint( - RECURSION_DEPTH_EXCEEDING_LIMIT, - CRATE_HIR_ID, - span, - rustc_errors::DiagDecorator(|diag| { - // FIXME: share this with overflow error in fulfillment instead of duplicating. - let pred_str = { - let s = predicate.to_string(); - if s.len() > 50 { - let mut p: FmtPrinter<'_, '_> = - FmtPrinter::new_with_limit(self, Namespace::TypeNS, Limit(6)); - predicate.print(&mut p).unwrap(); - p.into_buffer() - } else { - s - } - }; - diag.primary_message(format!( - "overflow evaluating the requirement `{pred_str}`", - )); - diag.help(format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", - self.recursion_limit() * 2, - self.crate_name(LOCAL_CRATE), - )); - diag.help( - "or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", - ); - diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); - }), - ) - } - fn item_name(self, id: DefId) -> Symbol { self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3d8e30191c700..3dec913ab9481 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -59,6 +59,7 @@ use rustc_target::callconv::FnAbi; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; pub use rustc_type_ir::fast_reject::DeepRejectCtxt; pub use rustc_type_ir::relate::VarianceDiagInfo; +pub use rustc_type_ir::search_graph::RequiredDepth; pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck}; pub use rustc_type_ir::*; use tracing::{debug, instrument}; diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 13988e2c7b918..0a307f766ebb2 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -124,4 +124,10 @@ pub trait SolverDelegate: Deref + Sized { /// Release canonicalizer state, either by deallocating it (the default) or by clearing it and /// stashing it for later reuse. fn release_canonicalizer_state(&self, _: CanonicalizerState) {} + + fn emit_next_solver_overflow_fcw( + &self, + goal: Goal::Predicate>, + span: ::Span, + ); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index aa7e1e79b5866..d7db7d90acc38 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -8,7 +8,9 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::region_constraint::{RegionConstraint, evaluate_solver_constraint}; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, PathKind}; +use rustc_type_ir::search_graph::{ + CandidateHeadUsages, LowerAvailableDepth, PathKind, RequiredDepth, +}; use rustc_type_ir::solve::{ AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo, NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition, @@ -329,9 +331,9 @@ where } /// The old solver doesn't check depth requirement when looking up cache while the next solver -/// does so. Thus the next solver is more prone to overflow. -/// To mitigate breakages, we re-evaluate the overflowed goal with doubled recursion limit -/// and emit a FCW if it succeeds. +/// does so. Thus the next solver is more prone to overflow. To mitigate breakages, we re-evaluate +/// the overflowed goal with doubled recursion limit and emit a FCW if doing so prevents overflow. +/// /// See the doc comment on `RECURSION_DEPTH_EXCEEDING_LIMIT` and #159228 for more details. fn maybe_evaluate_root_goal_with_higher_recursion_limit( delegate: &D, @@ -358,7 +360,7 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal) }); if let Ok(goal_evaluation) = &rerun_result - && goal_evaluation.certainty.is_yes() + && !goal_evaluation.certainty.is_overflow() { Ok(rerun_result) } else { @@ -366,15 +368,15 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( } }); if let Ok(rerun_result) = rerun_result { - delegate.cx().emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(goal.with(delegate.cx(), predicate), span); *initial_result = rerun_result; } } /// The old solver doesn't check depth requirement when looking up cache while the next solver -/// does so. Thus the next solver is more prone to overflow. -/// To mitigate breakages, we re-evaluate the overflowed goal with doubled recursion limit -/// and emit a FCW if it succeeds. +/// does so. Thus the next solver is more prone to overflow. To mitigate breakages, we re-evaluate +/// the overflowed goal with doubled recursion limit and emit a FCW if doing so prevents overflow. +/// /// See the doc comment on `RECURSION_DEPTH_EXCEEDING_LIMIT` and #159228 for more details. fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( delegate: &D, @@ -407,7 +409,7 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( delegate.cx().recursion_limit() * 2, ); if let Ok(response) = &new_goal_evaluation.result - && response.value.certainty.is_yes() + && !response.value.certainty.is_overflow() { Ok((new_result, new_goal_evaluation)) } else { @@ -416,7 +418,7 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( }); if let Ok(rerun_result) = rerun_result { let predicate: I::Predicate = goal_evaluation.uncanonicalized_goal.predicate; - delegate.cx().emit_next_solver_overflow_fcw(predicate, span); + delegate.emit_next_solver_overflow_fcw(goal.with(delegate.cx(), predicate), span); *initial_result = rerun_result; } } @@ -1832,18 +1834,19 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider< cx: I, canonical_goal: CanonicalInput, root_depth: usize, -) -> (QueryResult, I::Probe) { +) -> (QueryResult, I::Probe, RequiredDepth) { let mut inspect = inspect::ProofTreeBuilder::new(); - let (canonical_result, accessed_opaques) = SearchGraph::::evaluate_root_goal_for_proof_tree( - cx, - root_depth, - canonical_goal, - &mut inspect, - ); + let ((canonical_result, accessed_opaques), required_depth) = + SearchGraph::::evaluate_root_goal_for_proof_tree( + cx, + root_depth, + canonical_goal, + &mut inspect, + ); let final_revision = inspect.unwrap(); assert!(!accessed_opaques.might_rerun()); - (canonical_result, cx.mk_probe(final_revision)) + (canonical_result, cx.mk_probe(final_revision), required_depth) } /// Evaluate a goal to build a proof tree. @@ -1863,7 +1866,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, &opaque_types, typing_mode.into()); - let (canonical_result, final_revision) = + let (canonical_result, final_revision, required_depth) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal, root_depth); let proof_tree = inspect::GoalEvaluation { @@ -1871,6 +1874,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, orig_values, final_revision, result: canonical_result, + required_depth, }; let response = match canonical_result { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 693cdadec99fe..28470fc192b44 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2312,6 +2312,7 @@ symbols! { usize_legacy_mod, v1, v8plus, + v9, va_arg, va_arg_safe, va_copy, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 8d99035fd0db4..3b594253082b7 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -477,7 +477,7 @@ impl InlineAsmReg { Self::LoongArch(r) => r.overlapping_regs(|r| cb(Self::LoongArch(r))), Self::Mips(_) => cb(self), Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), - Self::Sparc(_) => cb(self), + Self::Sparc(r) => r.overlapping_regs(|r| cb(Self::Sparc(r))), Self::Xtensa(_) => cb(self), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), diff --git a/compiler/rustc_target/src/asm/sparc.rs b/compiler/rustc_target/src/asm/sparc.rs index 6261708642b28..d89a1e1903e78 100644 --- a/compiler/rustc_target/src/asm/sparc.rs +++ b/compiler/rustc_target/src/asm/sparc.rs @@ -1,7 +1,7 @@ use std::fmt; use rustc_data_structures::fx::FxIndexSet; -use rustc_span::Symbol; +use rustc_span::{Symbol, sym}; use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; @@ -9,6 +9,9 @@ use crate::spec::{RelocModel, Target}; def_reg_class! { Sparc SparcInlineAsmRegClass { reg, + freg, + dreg, + qreg, yreg, } } @@ -51,6 +54,9 @@ impl SparcInlineAsmRegClass { types! { _: I8, I16, I32, I64; } } } + Self::freg => types! { _: F32; }, + Self::dreg => types! { _: F64; }, + Self::qreg => types! { _: F128; }, Self::yreg => &[], } } @@ -75,6 +81,23 @@ fn reserved_g5( } } +fn v9_only( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + target_features: &FxIndexSet, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + // FIXME: This is the what GCC/LLVM currently use to limit access to upper-half registers, but + // it's unclear whether this is the correct behaviour. See the discussion around + // https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355. + if !target_features.contains(&sym::v9) { + Err("floating point registers in the upper half can only be used on SPARCv9") + } else { + Ok(()) + } +} + def_regs! { Sparc SparcInlineAsmReg SparcInlineAsmRegClass { // FIXME: @@ -107,6 +130,86 @@ def_regs! { r27: reg = ["r27", "i3"], // % reserved_i3 r28: reg = ["r28", "i4"], // % reserved_i4 r29: reg = ["r29", "i5"], // % reserved_i5 + f0: freg = ["f0"], + f1: freg = ["f1"], + f2: freg = ["f2"], + f3: freg = ["f3"], + f4: freg = ["f4"], + f5: freg = ["f5"], + f6: freg = ["f6"], + f7: freg = ["f7"], + f8: freg = ["f8"], + f9: freg = ["f9"], + f10: freg = ["f10"], + f11: freg = ["f11"], + f12: freg = ["f12"], + f13: freg = ["f13"], + f14: freg = ["f14"], + f15: freg = ["f15"], + f16: freg = ["f16"], + f17: freg = ["f17"], + f18: freg = ["f18"], + f19: freg = ["f19"], + f20: freg = ["f20"], + f21: freg = ["f21"], + f22: freg = ["f22"], + f23: freg = ["f23"], + f24: freg = ["f24"], + f25: freg = ["f25"], + f26: freg = ["f26"], + f27: freg = ["f27"], + f28: freg = ["f28"], + f29: freg = ["f29"], + f30: freg = ["f30"], + f31: freg = ["f31"], + d0: dreg = ["d0"], + d2: dreg = ["d2"], + d4: dreg = ["d4"], + d6: dreg = ["d6"], + d8: dreg = ["d8"], + d10: dreg = ["d10"], + d12: dreg = ["d12"], + d14: dreg = ["d14"], + d16: dreg = ["d16"], + d18: dreg = ["d18"], + d20: dreg = ["d20"], + d22: dreg = ["d22"], + d24: dreg = ["d24"], + d26: dreg = ["d26"], + d28: dreg = ["d28"], + d30: dreg = ["d30"], + d32: dreg = ["d32"] % v9_only, + d34: dreg = ["d34"] % v9_only, + d36: dreg = ["d36"] % v9_only, + d38: dreg = ["d38"] % v9_only, + d40: dreg = ["d40"] % v9_only, + d42: dreg = ["d42"] % v9_only, + d44: dreg = ["d44"] % v9_only, + d46: dreg = ["d46"] % v9_only, + d48: dreg = ["d48"] % v9_only, + d50: dreg = ["d50"] % v9_only, + d52: dreg = ["d52"] % v9_only, + d54: dreg = ["d54"] % v9_only, + d56: dreg = ["d56"] % v9_only, + d58: dreg = ["d58"] % v9_only, + d60: dreg = ["d60"] % v9_only, + d62: dreg = ["d62"] % v9_only, + q0: qreg = ["q0"], + q4: qreg = ["q4"], + q8: qreg = ["q8"], + q12: qreg = ["q12"], + q16: qreg = ["q16"], + q20: qreg = ["q20"], + q24: qreg = ["q24"], + q28: qreg = ["q28"], + q32: qreg = ["q32"] % v9_only, + q36: qreg = ["q36"] % v9_only, + q40: qreg = ["q40"] % v9_only, + q44: qreg = ["q44"] % v9_only, + q48: qreg = ["q48"] % v9_only, + q52: qreg = ["q52"] % v9_only, + q56: qreg = ["q56"] % v9_only, + q60: qreg = ["q60"] % v9_only, y: yreg = ["y"], #error = ["r0", "g0"] => "g0 is always zero and cannot be used as an operand for inline asm", @@ -135,4 +238,102 @@ impl SparcInlineAsmReg { ) -> fmt::Result { write!(out, "%{}", self.name()) } + + pub fn overlapping_regs(self, mut cb: impl FnMut(SparcInlineAsmReg)) { + cb(self); + + macro_rules! reg_conflicts { + ( + $( + $q:ident : $d0:ident $d1:ident : $f0:ident $f1:ident $f2:ident $f3:ident + ),*; + $( + $q_high:ident : $d0_high:ident $d1_high:ident + ),*; + ) => { + match self { + $( + Self::$q => { + cb(Self::$d0); + cb(Self::$d1); + cb(Self::$f0); + cb(Self::$f1); + cb(Self::$f2); + cb(Self::$f3); + } + Self::$d0 => { + cb(Self::$q); + cb(Self::$f0); + cb(Self::$f1); + } + Self::$d1 => { + cb(Self::$q); + cb(Self::$f2); + cb(Self::$f3); + } + Self::$f0 | Self::$f1 => { + cb(Self::$q); + cb(Self::$d0); + } + Self::$f2 | Self::$f3 => { + cb(Self::$q); + cb(Self::$d1); + } + )* + $( + Self::$q_high => { + cb(Self::$d0_high); + cb(Self::$d1_high); + } + Self::$d0_high | Self::$d1_high => { + cb(Self::$q_high); + } + )* + _ => {}, + } + }; + } + + // SPARC's floating-point register file is interesting in that it can be + // viewed as 16 128-bit registers, 32 64-bit registers or 32 32-bit + // registers. Because these views overlap, the registers of different + // widths will conflict (e.g. d0 overlaps with f0 and f1, and q1 + // overlaps with d2 and d3). + // + // See section 3.1.2 of The SPARC Architecture Manual: Version 9 for details. + reg_conflicts! { + q0 : d0 d2 : f0 f1 f2 f3, + q4 : d4 d6 : f4 f5 f6 f7, + q8 : d8 d10 : f8 f9 f10 f11, + q12 : d12 d14 : f12 f13 f14 f15, + q16 : d16 d18 : f16 f17 f18 f19, + q20 : d20 d22 : f20 f21 f22 f23, + q24 : d24 d26 : f24 f25 f26 f27, + q28 : d28 d30 : f28 f29 f30 f31; + q32 : d32 d34, + q36 : d36 d38, + q40 : d40 d42, + q44 : d44 d46, + q48 : d48 d50, + q52 : d52 d54, + q56 : d56 d58, + q60 : d60 d62; + } + } + + pub fn dreg_number(self) -> Option { + if self >= Self::d0 && self <= Self::d62 { + Some((self as u32 - Self::d0 as u32) * 2) + } else { + None + } + } + + pub fn qreg_number(self) -> Option { + if self >= Self::q0 && self <= Self::q60 { + Some((self as u32 - Self::q0 as u32) * 4) + } else { + None + } + } } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f891608b37b53..f282ff6792195 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -960,6 +960,8 @@ const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("leoncasa", Unstable(sym::sparc_target_feature), &[]), ("v8plus", Unstable(sym::sparc_target_feature), &[]), + // FIXME: It's unclear what this feature means when `v8plus` is disabled on 32-bit SPARC. See + // the discussion around https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355. ("v9", Unstable(sym::sparc_target_feature), &[]), // tidy-alphabetical-end ]; @@ -1291,7 +1293,9 @@ impl Target { // `x87` and all other FPU features so those do not matter. // Note that this one requirement is the entire implementation of the ABI! // LLVM handles the rest. - FeatureConstraints { required: &["soft-float"], incompatible: &[] } + // We mark "sse" as incompatible since LLVM likes to crash when both + // "soft-float" and "sse" are enabled. + FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] } } _ => unreachable!(), } @@ -1312,7 +1316,9 @@ impl Target { // `x87` and all other FPU features so those do not matter. // Note that this one requirement is the entire implementation of the ABI! // LLVM handles the rest. - FeatureConstraints { required: &["soft-float"], incompatible: &[] } + // We mark "sse" as incompatible since LLVM likes to crash when both + // "soft-float" and "sse" are enabled. + FeatureConstraints { required: &["soft-float"], incompatible: &["sse"] } } _ => unreachable!(), } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index f6c01b12ae4c0..4766ea6f2cf6e 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -14,13 +14,13 @@ pub use normalize::{ deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, normalize, }; use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{RequiredDepth, TyCtxt}; pub use select::InferCtxtSelectExt; fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, key: (CanonicalInput>, usize), -) -> (QueryResult>, &'tcx inspect::Probe>) { +) -> (QueryResult>, &'tcx inspect::Probe>, RequiredDepth) { evaluate_root_goal_for_proof_tree_raw_provider::, TyCtxt<'tcx>>( tcx, key.0, key.1, ) diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5e3c03ba7e7ba..3bff243427bb1 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,11 +1,13 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::mem; -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::attrs::lang_items::LangItem; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, @@ -15,16 +17,21 @@ use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtx use rustc_infer::traits::solve::{ ComputeGoalFastPathOutcome, FetchEligibleAssocItemResponse, Goal, SucceededInErased, }; +use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{Certainty, MaybeInfo}; +use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::{ self, CanonicalizerState, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques, TyOrConstInferVar}; use rustc_span::{DUMMY_SP, Span}; +use rustc_structures::Limit; use thin_vec::{ThinVec, thin_vec}; +use super::inspect::InferCtxtProofTreeExt; +use crate::solve::inspect::{self, InspectConfig, ProofTreeVisitor}; use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; #[repr(transparent)] @@ -504,4 +511,92 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< state.clear(); *self.canonicalizer_state.borrow_mut() = state; } + + fn emit_next_solver_overflow_fcw(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>, span: Span) { + let tcx = self.tcx; + let goal = self.resolve_vars_if_possible(goal); + let mut visitor = OverflowedGoalChain { + span, + predicates: vec![], + recursion_limit: usize::min(16, tcx.recursion_limit().0), + }; + let _ = self + .with_disabled_next_solver_overflow_fcw(|| self.visit_proof_tree(goal, &mut visitor)); + tcx.emit_node_span_lint( + RECURSION_DEPTH_EXCEEDING_LIMIT, + CRATE_HIR_ID, + span, + rustc_errors::DiagDecorator(|diag| { + // FIXME: share this with overflow error in fulfillment instead of duplicating. + let pred_str = |pred: ty::Predicate<'tcx>| { + let s = pred.to_string(); + if s.len() > 80 { + let mut p: FmtPrinter<'_, '_> = + FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(10)); + pred.print(&mut p).unwrap(); + p.into_buffer() + } else { + s + } + }; + diag.primary_message(format!( + "overflow evaluating the requirement `{}`", + pred_str(goal.predicate), + )); + for p in visitor.predicates.into_iter().skip(1) { + diag.note(format!("which requires {}", pred_str(p))); + } + diag.help( + "consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", + ); + diag.help(format!( + "or consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + tcx.recursion_limit() * 2, + tcx.crate_name(LOCAL_CRATE), + )); + diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); + }), + ) + } +} + +struct OverflowedGoalChain<'tcx> { + span: Span, + predicates: Vec>, + recursion_limit: usize, +} + +impl<'tcx> ProofTreeVisitor<'tcx> for OverflowedGoalChain<'tcx> { + type Result = ControlFlow<()>; + + fn span(&self) -> Span { + self.span + } + + fn config(&self) -> InspectConfig { + InspectConfig { max_depth: self.recursion_limit } + } + + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + self.predicates.push(goal.goal().predicate); + if let Some(cand) = goal.unique_applicable_candidate() { + goal.infcx().probe(|_| { + if let Some(nested_goal_with_largest_required_depth) = cand + .instantiate_nested_goals(self.span) + .into_iter() + .max_by_key(|g| g.required_depth()) + { + nested_goal_with_largest_required_depth.visit_with(self) + } else { + ControlFlow::Continue(()) + } + })?; + } + ControlFlow::Continue(()) + } + + fn on_recursion_limit(&mut self) -> Self::Result { + ControlFlow::Break(()) + } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index f7d6fe2481b2d..aaba2f86da598 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -14,7 +14,7 @@ use std::assert_matches; use rustc_infer::infer::InferCtxt; use rustc_macros::extension; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{TyCtxt, VisitorResult, eager_resolve_vars, try_visit}; +use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, eager_resolve_vars, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; @@ -30,7 +30,10 @@ pub struct InspectConfig { pub struct InspectGoal<'a, 'tcx> { infcx: &'a SolverDelegate<'tcx>, + // Record how deep we are in nested goals from the root goal. depth: usize, + // Required depth to complete the evaluation of this goal. + required_depth: RequiredDepth, orig_values: ThinVec>, prev_universe: ty::UniverseIndex, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -231,6 +234,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.depth } + pub fn required_depth(&self) -> RequiredDepth { + self.required_depth + } + pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] { &self.orig_values } @@ -338,8 +345,13 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { let infcx = <&SolverDelegate<'tcx>>::from(infcx); let prev_universe = infcx.universe(); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } = - root; + let inspect::GoalEvaluation { + uncanonicalized_goal, + orig_values, + final_revision, + result, + required_depth, + } = root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. let result = result.map(|ok| ok.value.certainty); @@ -353,6 +365,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { result, final_revision, source, + required_depth, } } diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs index 6f4b461575075..2444990749411 100644 --- a/compiler/rustc_type_ir/src/generic_visit.rs +++ b/compiler/rustc_type_ir/src/generic_visit.rs @@ -20,29 +20,35 @@ use crate::Interner; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. /// -/// To implement this conveniently, use the derive macro located in -/// `rustc_macros`. -pub trait GenericTypeVisitable { +/// ## Safety +/// +/// A manual implementation **must visit** every field. +/// +/// Therefore, it is advised to instead derive this using the derive +/// macro located in `rustc_macros`. +pub unsafe trait GenericTypeVisitable { fn generic_visit_with(&self, visitor: &mut V); } /////////////////////////////////////////////////////////////////////////// // Traversal implementations. -impl> GenericTypeVisitable for &T { +unsafe impl> GenericTypeVisitable for &T { fn generic_visit_with(&self, visitor: &mut V) { T::generic_visit_with(*self, visitor) } } -impl, U: GenericTypeVisitable> GenericTypeVisitable for (T, U) { +unsafe impl, U: GenericTypeVisitable> GenericTypeVisitable + for (T, U) +{ fn generic_visit_with(&self, visitor: &mut V) { self.0.generic_visit_with(visitor); self.1.generic_visit_with(visitor); } } -impl, B: GenericTypeVisitable, C: GenericTypeVisitable> +unsafe impl, B: GenericTypeVisitable, C: GenericTypeVisitable> GenericTypeVisitable for (A, B, C) { fn generic_visit_with(&self, visitor: &mut V) { @@ -52,7 +58,7 @@ impl, B: GenericTypeVisitable, C: GenericTypeVi } } -impl> GenericTypeVisitable for Option { +unsafe impl> GenericTypeVisitable for Option { fn generic_visit_with(&self, visitor: &mut V) { match self { Some(v) => v.generic_visit_with(visitor), @@ -61,7 +67,7 @@ impl> GenericTypeVisitable for Option { } } -impl, E: GenericTypeVisitable> GenericTypeVisitable +unsafe impl, E: GenericTypeVisitable> GenericTypeVisitable for Result { fn generic_visit_with(&self, visitor: &mut V) { @@ -72,54 +78,56 @@ impl, E: GenericTypeVisitable> GenericTypeVisit } } -impl> GenericTypeVisitable for Arc { +unsafe impl> GenericTypeVisitable for Arc { fn generic_visit_with(&self, visitor: &mut V) { (**self).generic_visit_with(visitor) } } -impl> GenericTypeVisitable for Box { +unsafe impl> GenericTypeVisitable for Box { fn generic_visit_with(&self, visitor: &mut V) { (**self).generic_visit_with(visitor) } } -impl> GenericTypeVisitable for Vec { +unsafe impl> GenericTypeVisitable for Vec { fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); } } -impl> GenericTypeVisitable for ThinVec { +unsafe impl> GenericTypeVisitable for ThinVec { fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); } } -impl, const N: usize> GenericTypeVisitable for SmallVec<[T; N]> { +unsafe impl, const N: usize> GenericTypeVisitable + for SmallVec<[T; N]> +{ fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); } } -impl> GenericTypeVisitable for [T] { +unsafe impl> GenericTypeVisitable for [T] { fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); } } -impl, Ix: Idx> GenericTypeVisitable for IndexVec { +unsafe impl, Ix: Idx> GenericTypeVisitable for IndexVec { fn generic_visit_with(&self, visitor: &mut V) { self.iter().for_each(|it| it.generic_visit_with(visitor)); } } -impl GenericTypeVisitable for std::hash::BuildHasherDefault { +unsafe impl GenericTypeVisitable for std::hash::BuildHasherDefault { fn generic_visit_with(&self, _visitor: &mut V) {} } #[expect(rustc::default_hash_types, rustc::potential_query_instability)] -impl< +unsafe impl< Visitor, Key: GenericTypeVisitable, Value: GenericTypeVisitable, @@ -133,7 +141,7 @@ impl< } #[expect(rustc::default_hash_types, rustc::potential_query_instability)] -impl, S: GenericTypeVisitable> GenericTypeVisitable +unsafe impl, S: GenericTypeVisitable> GenericTypeVisitable for std::collections::HashSet { fn generic_visit_with(&self, visitor: &mut V) { @@ -142,7 +150,7 @@ impl, S: GenericTypeVisitable> GenericTypeVisit } } -impl< +unsafe impl< Visitor, Key: GenericTypeVisitable, Value: GenericTypeVisitable, @@ -155,7 +163,7 @@ impl< } } -impl, S: GenericTypeVisitable> GenericTypeVisitable +unsafe impl, S: GenericTypeVisitable> GenericTypeVisitable for indexmap::IndexSet { fn generic_visit_with(&self, visitor: &mut V) { @@ -167,7 +175,7 @@ impl, S: GenericTypeVisitable> GenericTypeVisit macro_rules! trivial_impls { ( $($ty:ty),* $(,)? ) => { $( - impl + unsafe impl GenericTypeVisitable for $ty { fn generic_visit_with(&self, _visitor: &mut V) {} @@ -176,7 +184,7 @@ macro_rules! trivial_impls { }; } -impl GenericTypeVisitable for std::marker::PhantomData { +unsafe impl GenericTypeVisitable for std::marker::PhantomData { fn generic_visit_with(&self, _visitor: &mut V) {} } @@ -215,6 +223,7 @@ trivial_impls!( rustc_abi::ExternAbi, ); -impl GenericTypeVisitable for crate::FnSigKind { +// SAFETY: `FnSigKind` is a packed representation, therefore visiting its fields doesn't make sense +unsafe impl GenericTypeVisitable for crate::FnSigKind { fn generic_visit_with(&self, _visitor: &mut V) {} } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1113aa4f6af51..d230791304527 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,6 +15,7 @@ use crate::intern::Interned; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use crate::relate::Relate; +use crate::search_graph::RequiredDepth; use crate::solve::{ AccessedOpaques, CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect, }; @@ -500,9 +501,7 @@ pub trait Interner: self, canonical_goal: CanonicalInput, root_depth: usize, - ) -> (QueryResult, Self::Probe); - - fn emit_next_solver_overflow_fcw(self, predicate: Self::Predicate, span: Self::Span); + ) -> (QueryResult, Self::Probe, RequiredDepth); fn item_name(self, item_index: Self::DefId) -> Self::Symbol; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9bd7698b852e1..b7fa0c77e44ee 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -66,7 +66,6 @@ mod const_kind; mod flags; mod fold; mod generic_arg; -#[cfg(not(feature = "nightly"))] mod generic_visit; mod infer_ctxt; mod interner; @@ -97,7 +96,6 @@ pub use const_kind::*; pub use flags::*; pub use fold::*; pub use generic_arg::*; -#[cfg(not(feature = "nightly"))] pub use generic_visit::*; pub use infer_ctxt::*; pub use interner::*; diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 2592c0579c741..2923709432ee5 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -117,8 +117,8 @@ pub enum RegionConstraint { /// and there may wind up being assumptions we can use to prove this when we're in a smaller universe. PlaceholderTyOutlives(I::Ty, Region, S), - And(Box<[RegionConstraint]>), - Or(Box<[RegionConstraint]>), + And(#[generic_type_visitable(bounds())] Box<[RegionConstraint]>), + Or(#[generic_type_visitable(bounds())] Box<[RegionConstraint]>), } /// A solver region constraint together with the span that caused each leaf constraint. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index fcbc8b281d132..200ded3cca761 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -1,11 +1,11 @@ use derive_where::derive_where; -use super::{AvailableDepth, Cx, NestedGoals}; +use super::{AvailableDepth, Cx, NestedGoals, RequiredDepth}; use crate::data_structures::HashMap; use crate::search_graph::EvaluationResult; struct Success { - required_depth: usize, + required_depth: RequiredDepth, nested_goals: NestedGoals, result: X::Tracked, } @@ -23,13 +23,13 @@ struct WithOverflow { #[derive_where(Default; X: Cx)] struct CacheEntry { success: Option>, - with_overflow: HashMap>, + with_overflow: HashMap>, } #[derive_where(Debug; X: Cx)] pub(super) struct CacheData<'a, X: Cx> { pub(super) result: X::Result, - pub(super) required_depth: usize, + pub(super) required_depth: RequiredDepth, pub(super) encountered_overflow: bool, pub(super) nested_goals: &'a NestedGoals, } @@ -97,7 +97,7 @@ impl GlobalCache { }); } - let additional_depth = available_depth.0; + let additional_depth = RequiredDepth(available_depth.0); if let Some(WithOverflow { nested_goals, result }) = entry.with_overflow.get(&additional_depth) && candidate_is_applicable(nested_goals) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index b1635e7e4097c..c081898f26f56 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -18,6 +18,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::iter; use std::marker::PhantomData; +use std::ops::Sub; use derive_where::derive_where; #[cfg(feature = "nightly")] @@ -275,6 +276,14 @@ pub enum LowerAvailableDepth { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct AvailableDepth(usize); + +impl Sub for AvailableDepth { + type Output = AvailableDepth; + fn sub(self, rhs: RequiredDepth) -> AvailableDepth { + AvailableDepth(self.0.checked_sub(rhs.0).unwrap()) + } +} + impl AvailableDepth { /// Returns the remaining depth allowed for nested goals. /// @@ -311,11 +320,14 @@ impl AvailableDepth { /// Whether we're allowed to use a global cache entry which required /// the given depth. - fn cache_entry_is_applicable(self, additional_depth: usize) -> bool { - self.0 >= additional_depth + fn cache_entry_is_applicable(self, required_depth: RequiredDepth) -> bool { + self.0 >= required_depth.0 } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RequiredDepth(pub usize); + #[derive(Clone, Copy, Debug)] struct CycleHead { paths_to_head: PathsToNested, @@ -569,7 +581,7 @@ struct ProvisionalCacheEntry { #[derive_where(Debug; X: Cx)] struct EvaluationResult { encountered_overflow: bool, - required_depth: usize, + required_depth: RequiredDepth, heads: CycleHeads, nested_goals: NestedGoals, result: X::Result, @@ -750,7 +762,7 @@ impl, X: Cx> SearchGraph { root_depth: usize, input: X::Input, inspect: &mut D::ProofTreeBuilder, - ) -> X::Result { + ) -> (X::Result, RequiredDepth) { let mut this = SearchGraph::::new(root_depth); let available_depth = AvailableDepth(root_depth); let step_kind_from_parent = PathKind::Inductive; // is never used @@ -767,7 +779,7 @@ impl, X: Cx> SearchGraph { nested_goals: Default::default(), }); let evaluation_result = this.evaluate_goal_in_task(cx, input, inspect); - evaluation_result.result + (evaluation_result.result, evaluation_result.required_depth) } /// Probably the most involved method of the whole solver. @@ -864,9 +876,7 @@ impl, X: Cx> SearchGraph { evaluation_result.encountered_overflow, UpdateParentGoalCtxt::Ordinary { nested_goals: &evaluation_result.nested_goals, - min_reachable_available_depth: AvailableDepth( - available_depth.0 - evaluation_result.required_depth, - ), + min_reachable_available_depth: available_depth - evaluation_result.required_depth, }, ); let result = evaluation_result.result; @@ -1270,9 +1280,7 @@ impl, X: Cx> SearchGraph { encountered_overflow, UpdateParentGoalCtxt::Ordinary { nested_goals, - min_reachable_available_depth: AvailableDepth( - available_depth.0 - required_depth, - ), + min_reachable_available_depth: available_depth - required_depth, }, ); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 429009c46b314..5a93b941f3a64 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -5,6 +5,7 @@ use rustc_index::IndexVec; use crate::search_graph::{ AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind, + RequiredDepth, }; rustc_index::newtype_index! { @@ -59,8 +60,8 @@ pub(super) struct StackEntry { } impl StackEntry { - pub(super) fn required_depth(&self) -> usize { - self.available_depth.0 - self.min_reached_available_depth.0 + pub(super) fn required_depth(&self) -> RequiredDepth { + RequiredDepth(self.available_depth.0 - self.min_reached_available_depth.0) } } diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 783ee23fd9fbd..3f0d7f5893265 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -21,6 +21,7 @@ use derive_where::derive_where; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; use thin_vec::ThinVec; +use crate::search_graph::RequiredDepth; use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; @@ -52,6 +53,7 @@ pub struct GoalEvaluation { pub orig_values: ThinVec, pub final_revision: I::Probe, pub result: QueryResult, + pub required_depth: RequiredDepth, } /// A self-contained computation during trait solving. This either diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index bafd8d72dc437..e1d2b53366066 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -1,5 +1,8 @@ +use std::ops::ControlFlow; + use indexmap::IndexSet; use quote::{ToTokens, quote}; +use syn::parse::Parse; use syn::visit_mut::VisitMut; use syn::{Attribute, parse_quote}; use synstructure::decl_derive; @@ -13,9 +16,44 @@ decl_derive!( decl_derive!( [Lift_Generic, attributes(lift)] => lift_derive ); -#[cfg(not(feature = "nightly"))] decl_derive!( - [GenericTypeVisitable] => customizable_type_visitable_derive + [ GenericTypeVisitable, attributes(generic_type_visitable)] => + /// By default, `#[derive(GenericTypeVisitable)]` will add `GenericTypeVisitable` + /// bounds to every field of the item. However, this results in infinite recursion + /// for types whose fields mention `Self`, such as: + /// + /// ``` + /// struct List { + /// next: Option> + /// } + /// ``` + /// + /// The `#[generic_type_visitable(bounds(...))]` attribute provides an escape + /// hatch: it allows you to override the list of trait bounds added to the field's type. + /// Namely, it should contain `GenericTypeVisitable` bounds for all the non-`Self` + /// types present in the field. + /// + /// For the example above, that list will be empty: + /// ```ignore (would need to import GenericTypeVisitable to get this to compile) + /// #[derive(GenericTypeVisitable)] + /// struct List { + /// #[generic_type_visitable(bounds())] + /// next: Option> + /// } + /// ``` + /// + /// For a more complicated type: + /// ```ignore (would need to import GenericTypeVisitable to get this to compile) + /// #[derive(GenericTypeVisitable)] + /// struct Foo { + /// #[generic_type_visitable(bounds())] + /// just_self: Box, + /// #[generic_type_visitable(bounds(Bar: GenericTypeVisitable))] + /// contains_self: (Box, Bar), + /// } + /// struct Bar; + /// ``` + customizable_type_visitable_derive ); struct TransformedTy { @@ -28,13 +66,8 @@ enum TypeParameterPath { GenericParameter(syn::Ident), } -enum TypeParameterTransform { - Continue, - Stop, -} - type TypeParameterVisitor = - fn(TypeParameterPath, &mut syn::TypePath, &mut IndexSet) -> TypeParameterTransform; + fn(TypeParameterPath, &mut syn::TypePath, &mut IndexSet) -> ControlFlow<()>; fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool { let mut ignored = false; @@ -183,7 +216,7 @@ fn type_foldable_generic_parameters( if let TypeParameterPath::GenericParameter(param) = path { generic_parameter_bounds.insert(param); } - TypeParameterTransform::Continue + ControlFlow::Continue(()) }) .generic_parameter_bounds } @@ -295,12 +328,12 @@ fn lift(ty: syn::Type, generic_parameters: &[syn::Ident]) -> TransformedTy { match path { TypeParameterPath::Interner => { *ty.path.segments.first_mut().unwrap() = parse_quote! { J }; - TypeParameterTransform::Continue + ControlFlow::Continue(()) } TypeParameterPath::GenericParameter(param) => { generic_parameter_bounds.insert(param.clone()); *ty = parse_quote! { <#param as ::rustc_type_ir::lift::Lift>::Lifted }; - TypeParameterTransform::Stop + ControlFlow::Break(()) } } }) @@ -338,9 +371,7 @@ fn transform_type_parameters( }; if let Some(path) = path { - if let TypeParameterTransform::Stop = - (self.visit)(path, i, &mut self.generic_parameter_bounds) - { + if (self.visit)(path, i, &mut self.generic_parameter_bounds).is_break() { return; } } @@ -358,7 +389,6 @@ fn transform_type_parameters( TransformedTy { ty, generic_parameter_bounds: visitor.generic_parameter_bounds } } -#[cfg(not(feature = "nightly"))] fn customizable_type_visitable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { @@ -367,15 +397,32 @@ fn customizable_type_visitable_derive( } s.add_impl_generic(parse_quote!(__V)); - s.add_bounds(synstructure::AddBounds::Fields); + s.add_bounds(synstructure::AddBounds::None); + + let mut wc = vec![]; let body_visit = s.each(|bind| { + let field = bind.ast(); + let ty = field.ty.clone(); + + match field_generic_type_visitable_bound(field) { + Ok(Some(bounds)) => wc.extend(bounds), + Ok(None) => { + // no overridden bounds, add the default one + wc.push(parse_quote! { #ty: ::rustc_type_ir::GenericTypeVisitable::<__V> }); + } + Err(err) => return err.into_compile_error(), + } + quote! { ::rustc_type_ir::GenericTypeVisitable::<__V>::generic_visit_with(#bind, __visitor); } }); s.bind_with(|_| synstructure::BindStyle::Move); + for wc in wc { + s.add_where_predicate(wc); + } - s.bound_impl( + s.unsafe_bound_impl( quote!(::rustc_type_ir::GenericTypeVisitable<__V>), quote! { fn generic_visit_with( @@ -388,8 +435,45 @@ fn customizable_type_visitable_derive( ) } -#[cfg(feature = "nightly")] -#[proc_macro_derive(GenericTypeVisitable)] -pub fn customizable_type_visitable_derive(_: proc_macro::TokenStream) -> proc_macro::TokenStream { - proc_macro::TokenStream::new() +fn field_generic_type_visitable_bound( + field: &syn::Field, +) -> syn::Result>> { + let mut attrs = + field.attrs.iter().filter(|attr| attr.path().is_ident("generic_type_visitable")); + let Some(attr) = attrs.next() else { + return Ok(None); + }; + + if attrs.next().is_some() { + return Err(syn::Error::new_spanned( + field, + "multiple `generic_type_visitable` attributes on field", + )); + } + + parse_generic_type_visitable_bound(attr).map(Some) +} + +mod kw { + syn::custom_keyword!(bounds); +} + +/// Parses a bound like: +/// +/// ```ignore (would need to import GenericTypeVisitable to get this to compile) +/// #[generic_type_visitable(bounds(Foo: GenericTypeVisitable, Bar: GenericTypeVisitable))] +/// ``` +fn parse_generic_type_visitable_bound( + attr: &Attribute, +) -> syn::Result> { + attr.parse_args_with(|input: syn::parse::ParseStream<'_>| { + input.parse::()?; + let predicates; + syn::parenthesized!(predicates in input); + + let proof = + predicates.parse_terminated(syn::WherePredicate::parse, syn::Token![,])?.into_iter(); + + if input.is_empty() { Ok(proof) } else { Err(input.error("unexpected token")) } + }) } diff --git a/library/alloc/src/vec/partial_eq.rs b/library/alloc/src/vec/partial_eq.rs index 943c9309836d3..2d5a839cc8c30 100644 --- a/library/alloc/src/vec/partial_eq.rs +++ b/library/alloc/src/vec/partial_eq.rs @@ -32,6 +32,12 @@ __impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[sta __impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } #[cfg(not(no_global_oom_handling))] __impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +#[cfg(not(no_global_oom_handling))] +__impl_slice_eq1! { [A: Allocator] Vec, Cow<'_, [U]> where U: Clone, #[stable(feature = "partialeq_cow_for_vec_and_slice", since = "CURRENT_RUSTC_VERSION")] } +#[cfg(not(no_global_oom_handling))] +__impl_slice_eq1! { [] &[T], Cow<'_, [U]> where U: Clone, #[stable(feature = "partialeq_cow_for_vec_and_slice", since = "CURRENT_RUSTC_VERSION")] } +#[cfg(not(no_global_oom_handling))] +__impl_slice_eq1! { [] &mut [T], Cow<'_, [U]> where U: Clone, #[stable(feature = "partialeq_cow_for_vec_and_slice", since = "CURRENT_RUSTC_VERSION")] } __impl_slice_eq1! { const, [A: Allocator, const N: usize] Vec, [U; N], #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[stable(feature = "rust1", since = "1.0.0")] } __impl_slice_eq1! { const, [A: Allocator, const N: usize] Vec, &[U; N], #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[stable(feature = "rust1", since = "1.0.0")] } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 077005afd5d38..787452df7f680 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -1339,6 +1339,25 @@ fn test_from_cow() { assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]); } +#[test] +fn test_partial_eq_cow_symmetric() { + let v: Vec = vec![1, 2, 3]; + let c: Cow<'_, [i32]> = Cow::Borrowed(&[1, 2, 3]); + + assert_eq!(c, v); + assert_eq!(v, c); + + let s: &[i32] = &[1, 2, 3]; + assert_eq!(s, c); + + let mut arr = [1, 2, 3]; + let ms: &mut [i32] = &mut arr; + assert_eq!(ms, c); + + let v2: Vec = vec![1, 2, 4]; + assert!(v2 != c); +} + #[allow(dead_code)] fn assert_covariance() { fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 3a7ab744c0402..5c16416266139 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2565,6 +2565,9 @@ Please disable assertions with `rust.debug-assertions = false`. if builder.config.rust_optimize_tests { cmd.arg("--optimize-tests"); } + if !builder.config.docs_minification { + cmd.arg("--disable-minification"); + } if builder.config.rust_randomize_layout { cmd.arg("--rust-randomized-layout"); } diff --git a/src/tools/compiletest/src/cli.rs b/src/tools/compiletest/src/cli.rs index c2bccab30804f..45681eabe03a3 100644 --- a/src/tools/compiletest/src/cli.rs +++ b/src/tools/compiletest/src/cli.rs @@ -257,6 +257,9 @@ struct Args { /// Run tests with optimizations enabled. #[arg(long)] optimize_tests: bool, + /// Pass `--disable-minification` to rustdoc when generating docs for tests. + #[arg(long)] + disable_minification: bool, /// Run tests verbosely, showing all output. #[arg(long)] verbose: bool, @@ -441,6 +444,7 @@ pub(crate) fn parse_config(args: Vec) -> Config { cxxflags: args.cxxflags, default_codegen_backend, diff_command: args.compiletest_diff_tool, + disable_minification: args.disable_minification, edition: args.edition, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 871431fe0d70f..4123dcf5b600a 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -553,6 +553,11 @@ pub(crate) struct Config { /// *only* applied to the [`PassFailMode::RunPass`] test crate and not its auxiliaries. pub(crate) optimize_tests: bool, + /// Whether rustdoc should disable CSS/JS minification when generating docs for tests. + /// + /// Forwarded from bootstrap's `build.docs-minification = false`. + pub(crate) disable_minification: bool, + /// Target platform tuple. pub(crate) target: String, diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 992ace208a42f..6facfe362c4eb 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -122,6 +122,7 @@ struct ConfigBuilder { rustc_debug_assertions: bool, std_debug_assertions: bool, std_remap_debuginfo: bool, + disable_minification: bool, } impl ConfigBuilder { @@ -200,6 +201,11 @@ impl ConfigBuilder { self } + fn disable_minification(&mut self, is_enabled: bool) -> &mut Self { + self.disable_minification = is_enabled; + self + } + fn build(&mut self) -> Config { let args = &[ "compiletest", @@ -266,6 +272,9 @@ impl ConfigBuilder { if self.std_remap_debuginfo { args.push("--with-std-remap-debuginfo".to_owned()); } + if self.disable_minification { + args.push("--disable-minification".to_owned()); + } args.push("--rustc-path".to_string()); args.push(std::env::var("TEST_RUSTC").expect("must be configured by bootstrap")); @@ -309,6 +318,15 @@ fn should_fail() { assert_eq!(d.should_fail, ShouldFail::Yes); } +#[test] +fn disable_minification_flag() { + let config: Config = cfg().build(); + assert!(!config.disable_minification); + + let config: Config = cfg().disable_minification(true).build(); + assert!(config.disable_minification); +} + #[test] fn revisions() { let config: Config = cfg().build(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8d40ff093d571..a08a96f0d7be5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1049,10 +1049,18 @@ impl<'test> TestCx<'test> { match kind { DocKind::Html => {} DocKind::Json => { - rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options"); + rustdoc.arg("--output-format").arg("json"); } } + // Both JSON output and `--disable-minification` are unstable rustdoc options. + if matches!(kind, DocKind::Json) || self.config.disable_minification { + rustdoc.arg("-Zunstable-options"); + } + if self.config.disable_minification { + rustdoc.arg("--disable-minification"); + } + if let Some(ref linker) = self.config.target_linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -1611,6 +1619,15 @@ impl<'test> TestCx<'test> { compiler.arg("-Zwasm-proc-macros"); } + // `--disable-minification` is an unstable rustdoc option. Rustdoc UI tests intentionally + // exercise diagnostics for unstable options, so don't enable them for that suite. + if compiler_kind == CompilerKind::Rustdoc + && self.config.disable_minification + && self.config.mode != TestMode::Ui + { + compiler.arg("-Zunstable-options").arg("--disable-minification"); + } + // Hide libstd sources from ui tests to make sure we generate the stderr // output that users will see. // Without this, we may be producing good diagnostics in-tree but users diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 8965b7b145849..b2d23bcf8ec0a 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -96,6 +96,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { target_rustcflags: Default::default(), rust_randomized_layout: Default::default(), optimize_tests: Default::default(), + disable_minification: Default::default(), target: Default::default(), host: Default::default(), cdb: Default::default(), diff --git a/tests/assembly-llvm/asm/sparc-types.rs b/tests/assembly-llvm/asm/sparc-types.rs index 3eb3528991efd..e7f2d84e470a0 100644 --- a/tests/assembly-llvm/asm/sparc-types.rs +++ b/tests/assembly-llvm/asm/sparc-types.rs @@ -3,17 +3,26 @@ //@ assembly-output: emit-asm //@[sparc] compile-flags: --target sparc-unknown-none-elf //@[sparc] needs-llvm-components: sparc -//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu --cfg v9 //@[sparcv8plus] needs-llvm-components: sparc -//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparcv8plus] filecheck-flags: --check-prefix v9 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu --cfg v9 //@[sparc64] needs-llvm-components: sparc -//@ compile-flags: -Zmerge-functions=disabled +//@[sparc64] filecheck-flags: --check-prefix v9 +//@ compile-flags: -Zmerge-functions=disabled -Copt-level=3 +//@ compile-flags: --check-cfg=cfg(v9) +//@ min-llvm-version: 22 -#![feature(no_core, asm_experimental_arch)] +#![deny(unexpected_cfgs)] +#![feature(no_core, asm_experimental_arch, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] +#[cfg_attr(v9, cfg(not(target_feature = "v9")))] +#[cfg_attr(not(v9), cfg(target_feature = "v9"))] +compile_error!("v9 cfg mismatch"); + extern crate minicore; use minicore::*; @@ -25,7 +34,7 @@ extern "C" { } macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn $func(x: $ty) -> $ty { let y; asm!(concat!($mov," {}, {}"), in($class) x, out($class) y); @@ -33,14 +42,24 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { } };} -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] - pub unsafe fn $func(x: $ty) -> $ty { - let y; - asm!(concat!($mov, " %", $reg, ", %", $reg), in($reg) x, lateout($reg) y); - y - } -};} +macro_rules! check_reg { + ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[unsafe(no_mangle)] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " %", $reg, ", %", $reg), in($reg) x, lateout($reg) y); + y + } + }; + ($func:ident, $ty:ty, $reg:tt, $asm_reg:tt, $mov:literal) => { + #[unsafe(no_mangle)] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " %", $asm_reg, ", %", $asm_reg), in($reg) x, lateout($reg) y); + y + } + }; +} // CHECK-LABEL: sym_fn_32: // CHECK: !APP @@ -143,3 +162,53 @@ check_reg!(r9_i32, i32, "r9", "mov"); // sparc64-NEXT: !NO_APP #[cfg(sparc64)] check_reg!(r9_i64, i64, "r9", "mov"); + +// CHECK-LABEL: freg_f32: +// CHECK: !APP +// CHECK-NEXT: fmovs %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(freg_f32, f32, freg, "fmovs"); + +// CHECK-LABEL: dreg_f64: +// CHECK: !APP +// CHECK-NEXT: fmovs %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(dreg_f64, f64, dreg, "fmovs"); + +// CHECK-LABEL: qreg_f128: +// CHECK: !APP +// CHECK-NEXT: fmovs %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK-NEXT: !NO_APP +check!(qreg_f128, f128, qreg, "fmovs"); + +// CHECK-LABEL: f0_f32: +// CHECK: !APP +// CHECK-NEXT: fmovs %f0, %f0 +// CHECK-NEXT: !NO_APP +check_reg!(f0_f32, f32, "f0", "fmovs"); + +// CHECK-LABEL: d0_f64: +// CHECK: !APP +// CHECK-NEXT: fmovs %f0, %f0 +// CHECK-NEXT: !NO_APP +check_reg!(d0_f64, f64, "d0", "f0", "fmovs"); + +// CHECK-LABEL: q0_f128: +// CHECK: !APP +// CHECK-NEXT: fmovs %f0, %f0 +// CHECK-NEXT: !NO_APP +check_reg!(q0_f128, f128, "q0", "f0", "fmovs"); + +// v9-LABEL: d62_f64: +// v9: !APP +// v9-NEXT: fmovd %f62, %f62 +// v9-NEXT: !NO_APP +#[cfg(v9)] +check_reg!(d62_f64, f64, "d62", "f62", "fmovd"); + +// v9-LABEL: q60_f128: +// v9: !APP +// v9-NEXT: fmovd %f60, %f60 +// v9-NEXT: !NO_APP +#[cfg(v9)] +check_reg!(q60_f128, f128, "q60", "f60", "fmovd"); diff --git a/tests/ui/asm/sparc/bad-reg.rs b/tests/ui/asm/sparc/bad-reg.rs index c44f6c5790bf9..8cac5eb6b4ad0 100644 --- a/tests/ui/asm/sparc/bad-reg.rs +++ b/tests/ui/asm/sparc/bad-reg.rs @@ -9,7 +9,7 @@ //@ ignore-backends: gcc #![crate_type = "rlib"] -#![feature(no_core, asm_experimental_arch)] +#![feature(no_core, asm_experimental_arch, f128)] #![no_core] extern crate minicore; @@ -54,5 +54,9 @@ fn f() { //~| ERROR type `i32` cannot be used with this register class asm!("/* {} */", out(yreg) _); //~^ ERROR can only be used as a clobber + asm!("", in("d62") 0.0_f64); + //[sparc]~^ ERROR cannot use register `d62` + asm!("", in("q60") 0.0_f128); + //[sparc]~^ ERROR cannot use register `q60` } } diff --git a/tests/ui/asm/sparc/bad-reg.sparc.stderr b/tests/ui/asm/sparc/bad-reg.sparc.stderr index e0580ad3232f5..06b607ff007ac 100644 --- a/tests/ui/asm/sparc/bad-reg.sparc.stderr +++ b/tests/ui/asm/sparc/bad-reg.sparc.stderr @@ -94,5 +94,17 @@ LL | asm!("/* {} */", in(yreg) x); | = note: register class `yreg` supports these types: -error: aborting due to 15 previous errors +error: cannot use register `d62`: floating point registers in the upper half can only be used on SPARCv9 + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", in("d62") 0.0_f64); + | ^^^^^^^^^^^^^^^^^ + +error: cannot use register `q60`: floating point registers in the upper half can only be used on SPARCv9 + --> $DIR/bad-reg.rs:59:18 + | +LL | asm!("", in("q60") 0.0_f128); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/asm/sparc/reg-conflict.rs b/tests/ui/asm/sparc/reg-conflict.rs new file mode 100644 index 0000000000000..70e138733042c --- /dev/null +++ b/tests/ui/asm/sparc/reg-conflict.rs @@ -0,0 +1,41 @@ +//@ add-minicore +//@ revisions: sparc sparcv8plus sparc64 +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu +//@[sparcv8plus] needs-llvm-components: sparc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ ignore-backends: gcc + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch, f128)] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn f() { + unsafe { + asm!("", in("f6") 0.0_f32, in("d6") 0.0_f64); + //~^ ERROR register `d6` conflicts with register `f6` + asm!("", in("f7") 0.0_f32, in("d6") 0.0_f64); + //~^ ERROR register `d6` conflicts with register `f7` + asm!("", in("f8") 0.0_f32, in("q8") 0.0_f128); + //~^ ERROR register `q8` conflicts with register `f8` + asm!("", in("f9") 0.0_f32, in("q8") 0.0_f128); + //~^ ERROR register `q8` conflicts with register `f9` + asm!("", in("f10") 0.0_f32, in("q8") 0.0_f128); + //~^ ERROR register `q8` conflicts with register `f10` + asm!("", in("f11") 0.0_f32, in("q8") 0.0_f128); + //~^ ERROR register `q8` conflicts with register `f11` + asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + //~^ ERROR register `q12` conflicts with register `d12` + asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + //~^ ERROR register `q12` conflicts with register `d12` + asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + //~^ ERROR register `q12` conflicts with register `d14` + asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + //~^ ERROR register `q12` conflicts with register `d14` + } +} diff --git a/tests/ui/asm/sparc/reg-conflict.sparc.stderr b/tests/ui/asm/sparc/reg-conflict.sparc.stderr new file mode 100644 index 0000000000000..fef74ef77b36d --- /dev/null +++ b/tests/ui/asm/sparc/reg-conflict.sparc.stderr @@ -0,0 +1,82 @@ +error: register `d6` conflicts with register `f6` + --> $DIR/reg-conflict.rs:20:36 + | +LL | asm!("", in("f6") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f6` + +error: register `d6` conflicts with register `f7` + --> $DIR/reg-conflict.rs:22:36 + | +LL | asm!("", in("f7") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f7` + +error: register `q8` conflicts with register `f8` + --> $DIR/reg-conflict.rs:24:36 + | +LL | asm!("", in("f8") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f8` + +error: register `q8` conflicts with register `f9` + --> $DIR/reg-conflict.rs:26:36 + | +LL | asm!("", in("f9") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f9` + +error: register `q8` conflicts with register `f10` + --> $DIR/reg-conflict.rs:28:37 + | +LL | asm!("", in("f10") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f10` + +error: register `q8` conflicts with register `f11` + --> $DIR/reg-conflict.rs:30:37 + | +LL | asm!("", in("f11") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f11` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:32:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:34:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:36:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:38:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/asm/sparc/reg-conflict.sparc64.stderr b/tests/ui/asm/sparc/reg-conflict.sparc64.stderr new file mode 100644 index 0000000000000..fef74ef77b36d --- /dev/null +++ b/tests/ui/asm/sparc/reg-conflict.sparc64.stderr @@ -0,0 +1,82 @@ +error: register `d6` conflicts with register `f6` + --> $DIR/reg-conflict.rs:20:36 + | +LL | asm!("", in("f6") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f6` + +error: register `d6` conflicts with register `f7` + --> $DIR/reg-conflict.rs:22:36 + | +LL | asm!("", in("f7") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f7` + +error: register `q8` conflicts with register `f8` + --> $DIR/reg-conflict.rs:24:36 + | +LL | asm!("", in("f8") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f8` + +error: register `q8` conflicts with register `f9` + --> $DIR/reg-conflict.rs:26:36 + | +LL | asm!("", in("f9") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f9` + +error: register `q8` conflicts with register `f10` + --> $DIR/reg-conflict.rs:28:37 + | +LL | asm!("", in("f10") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f10` + +error: register `q8` conflicts with register `f11` + --> $DIR/reg-conflict.rs:30:37 + | +LL | asm!("", in("f11") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f11` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:32:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:34:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:36:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:38:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/asm/sparc/reg-conflict.sparcv8plus.stderr b/tests/ui/asm/sparc/reg-conflict.sparcv8plus.stderr new file mode 100644 index 0000000000000..fef74ef77b36d --- /dev/null +++ b/tests/ui/asm/sparc/reg-conflict.sparcv8plus.stderr @@ -0,0 +1,82 @@ +error: register `d6` conflicts with register `f6` + --> $DIR/reg-conflict.rs:20:36 + | +LL | asm!("", in("f6") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f6` + +error: register `d6` conflicts with register `f7` + --> $DIR/reg-conflict.rs:22:36 + | +LL | asm!("", in("f7") 0.0_f32, in("d6") 0.0_f64); + | ---------------- ^^^^^^^^^^^^^^^^ register `d6` + | | + | register `f7` + +error: register `q8` conflicts with register `f8` + --> $DIR/reg-conflict.rs:24:36 + | +LL | asm!("", in("f8") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f8` + +error: register `q8` conflicts with register `f9` + --> $DIR/reg-conflict.rs:26:36 + | +LL | asm!("", in("f9") 0.0_f32, in("q8") 0.0_f128); + | ---------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f9` + +error: register `q8` conflicts with register `f10` + --> $DIR/reg-conflict.rs:28:37 + | +LL | asm!("", in("f10") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f10` + +error: register `q8` conflicts with register `f11` + --> $DIR/reg-conflict.rs:30:37 + | +LL | asm!("", in("f11") 0.0_f32, in("q8") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^ register `q8` + | | + | register `f11` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:32:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d12` + --> $DIR/reg-conflict.rs:34:37 + | +LL | asm!("", in("d12") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d12` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:36:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: register `q12` conflicts with register `d14` + --> $DIR/reg-conflict.rs:38:37 + | +LL | asm!("", in("d14") 0.0_f64, in("q12") 0.0_f128); + | ----------------- ^^^^^^^^^^^^^^^^^^ register `q12` + | | + | register `d14` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/const-generics/gca/direct-const-arg-fn-call.rs b/tests/ui/const-generics/gca/direct-const-arg-fn-call.rs new file mode 100644 index 0000000000000..f4a604e2b4700 --- /dev/null +++ b/tests/ui/const-generics/gca/direct-const-arg-fn-call.rs @@ -0,0 +1,84 @@ +//! Regression test for #157152. +//! +//! Under `min_generic_const_args` with `macroless_generic_const_args`, a braced const +//! argument containing an associated-function call (e.g. `FieldName::len()`, as generated +//! by `tracing`'s logging macros as `FieldName<{ FieldName::len(name) }>`) was lowered as +//! a tuple-struct constructor. Lowering the callee's `Self` type `FieldName`, written +//! without its `const N: usize` argument, then produced a spurious "missing generics" +//! error (E0107) plus follow-on errors, which made `tracing` fail to compile in any crate +//! enabling the feature. +//! +//! It should instead report that the call must be wrapped in a `const` block, and +//! the wrapped form must compile. The same holds for any self type that cannot host a +//! tuple-variant constructor (unions, primitives, foreign types), not just structs. +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args, macroless_generic_const_args)] +#![feature(generic_const_args)] +#![feature(extern_types)] +#![expect(incomplete_features)] + +struct FieldName([u8; N]); + +impl FieldName<0> { + const fn len() -> usize { + 5 + } + + const fn len_of(name: &str) -> usize { + name.len() + } +} + +// The associated-function call is not a constructor, so the bare braces are +// rejected with a clear diagnostic instead of a spurious "missing generics" error. +fn bad(_: FieldName<{ FieldName::len() }>) {} +//~^ ERROR complex const arguments must be placed inside of a `const` block + +// Wrapping the call in a `const` block makes it an anonymous const and compiles. +fn good(_: FieldName<{ const { FieldName::len() } }>) {} + +// The exact shape from #157152: `tracing`'s macros expand a field name to +// `FieldName::len(stringify!(field))`. Same as `bad` but with a string argument, which +// the diagnostic ignores; the self type is still a bare generic struct. +fn bad_tracing(_: FieldName<{ FieldName::len_of("id") }>) {} +//~^ ERROR complex const arguments must be placed inside of a `const` block + +fn good_tracing(_: FieldName<{ const { FieldName::len_of("id") } }>) {} + +union Tag { + bytes: [u8; N], +} + +impl Tag<0> { + const fn width() -> usize { + 7 + } +} + +// Unions behave exactly like structs: the call is an associated function, not a +// constructor, so the bare braces are rejected the same way. +fn bad_union(_: Tag<{ Tag::width() }>) {} +//~^ ERROR complex const arguments must be placed inside of a `const` block + +fn good_union(_: Tag<{ const { Tag::width() } }>) {} + +// A primitive can't host a constructor either, and has no generics to omit, so it never +// hits the "missing generics" path. No `good_` counterpart: `from_str_radix` returns a +// `Result`, not a `usize`, so the wrapped form can't form a valid const arg. This case +// only checks that the bare form is rejected. +fn bad_prim(_: FieldName<{ u32::from_str_radix("10", 10) }>) {} +//~^ ERROR complex const arguments must be placed inside of a `const` block + +unsafe extern "C" { + type Opaque; +} + +// A foreign type has no constructor and no inherent associated functions. The guard +// rejects it from the self type's resolution alone, before the `foo` segment is resolved. +// Without that, downstream resolution gives an opaque "invalid base path" error (plus an +// E0223) rather than this clear one. +fn bad_foreign(_: FieldName<{ Opaque::foo() }>) {} +//~^ ERROR complex const arguments must be placed inside of a `const` block + +fn main() {} diff --git a/tests/ui/const-generics/gca/direct-const-arg-fn-call.stderr b/tests/ui/const-generics/gca/direct-const-arg-fn-call.stderr new file mode 100644 index 0000000000000..b73cc02dae915 --- /dev/null +++ b/tests/ui/const-generics/gca/direct-const-arg-fn-call.stderr @@ -0,0 +1,32 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/direct-const-arg-fn-call.rs:35:23 + | +LL | fn bad(_: FieldName<{ FieldName::len() }>) {} + | ^^^^^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/direct-const-arg-fn-call.rs:44:31 + | +LL | fn bad_tracing(_: FieldName<{ FieldName::len_of("id") }>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/direct-const-arg-fn-call.rs:61:23 + | +LL | fn bad_union(_: Tag<{ Tag::width() }>) {} + | ^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/direct-const-arg-fn-call.rs:70:28 + | +LL | fn bad_prim(_: FieldName<{ u32::from_str_radix("10", 10) }>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/direct-const-arg-fn-call.rs:81:31 + | +LL | fn bad_foreign(_: FieldName<{ Opaque::foo() }>) {} + | ^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/consts/too_generic_eval_ice.current.stderr b/tests/ui/consts/too_generic_eval_ice.current.stderr index 02bcaee80154f..061945e344ede 100644 --- a/tests/ui/consts/too_generic_eval_ice.current.stderr +++ b/tests/ui/consts/too_generic_eval_ice.current.stderr @@ -30,15 +30,15 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - `&mut [T]` implements `PartialEq<[U; N]>` - and 11 others + `&mut [T]` implements `PartialEq>` + and 13 others error: aborting due to 4 previous errors diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr index 359deee7bee4b..64e40ebdd7bdf 100644 --- a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr @@ -6,15 +6,15 @@ LL | assert_ne!(buf, b"----"); | = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - `&mut [T]` implements `PartialEq<[U; N]>` - and 11 others + `&mut [T]` implements `PartialEq>` + and 13 others error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:19:5 @@ -24,15 +24,15 @@ LL | assert_eq!(buf, b"----"); | = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq>` `&[T]` implements `PartialEq<[U; N]>` `&[u8; N]` implements `PartialEq` `&[u8; N]` implements `PartialEq` `&[u8]` implements `PartialEq` `&[u8]` implements `PartialEq` - `&mut [T]` implements `PartialEq>` - `&mut [T]` implements `PartialEq<[U; N]>` - and 11 others + `&mut [T]` implements `PartialEq>` + and 13 others error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:5:30 diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.aarch64.stderr similarity index 60% rename from tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr rename to tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.aarch64.stderr index 9595d1aba477f..72828f701d66f 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.aarch64.stderr @@ -1,31 +1,31 @@ error: enabling the `neon` target feature on the current target is unsound due to ABI issues - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:13:18 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:16:36 | -LL | #[target_feature(enable = "neon")] - | ^^^^^^^^^^^^^^^ +LL | #[cfg_attr(aarch64, target_feature(enable = "neon"))] + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #134375 note: the lint level is defined here - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:8:9 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:9 | -LL | #![deny(aarch64_softfloat_neon)] +LL | #![deny(aarch64_softfloat_neon, x86_softfloat_sse)] | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: error: enabling the `neon` target feature on the current target is unsound due to ABI issues - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:13:18 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:16:36 | -LL | #[target_feature(enable = "neon")] - | ^^^^^^^^^^^^^^^ +LL | #[cfg_attr(aarch64, target_feature(enable = "neon"))] + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #134375 note: the lint level is defined here - --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:8:9 + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:9 | -LL | #![deny(aarch64_softfloat_neon)] +LL | #![deny(aarch64_softfloat_neon, x86_softfloat_sse)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs index dba9e2366d9e9..937c8d93ae940 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs @@ -1,16 +1,22 @@ //@ compile-flags: --crate-type=lib -//@ compile-flags: --target=aarch64-unknown-none-softfloat -//@ needs-llvm-components: aarch64 +//@ revisions: aarch64 x86_64 +//@[aarch64] compile-flags: --target=aarch64-unknown-none-softfloat +//@[aarch64] needs-llvm-components: aarch64 +//@[x86_64] compile-flags: --target=x86_64-unknown-none +//@[x86_64] needs-llvm-components: x86 //@ add-minicore //@ ignore-backends: gcc #![feature(no_core)] #![no_core] -#![deny(aarch64_softfloat_neon)] +#![deny(aarch64_softfloat_neon, x86_softfloat_sse)] extern crate minicore; use minicore::*; -#[target_feature(enable = "neon")] -//~^ERROR: enabling the `neon` target feature on the current target is unsound -//~|WARN: previously accepted +#[cfg_attr(aarch64, target_feature(enable = "neon"))] +//[aarch64]~^ERROR: enabling the `neon` target feature on the current target is unsound +//[aarch64]~|WARN: previously accepted +#[cfg_attr(x86_64, target_feature(enable = "avx"))] +//[x86_64]~^ERROR: enabling the `sse` target feature on the current target is unsupported +//[x86_64]~|WARN: previously accepted pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.x86_64.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.x86_64.stderr new file mode 100644 index 0000000000000..52f577b02bae7 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.x86_64.stderr @@ -0,0 +1,31 @@ +error: enabling the `sse` target feature on the current target is unsupported due to LLVM backend issues + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:19:35 + | +LL | #[cfg_attr(x86_64, target_feature(enable = "avx"))] + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #117938 +note: the lint level is defined here + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:33 + | +LL | #![deny(aarch64_softfloat_neon, x86_softfloat_sse)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: enabling the `sse` target feature on the current target is unsupported due to LLVM backend issues + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:19:35 + | +LL | #[cfg_attr(x86_64, target_feature(enable = "avx"))] + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #117938 +note: the lint level is defined here + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:33 + | +LL | #![deny(aarch64_softfloat_neon, x86_softfloat_sse)] + | ^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.rs b/tests/ui/traits/next-solver/overflow-discards-constraints.rs index 1516184dfde81..810d756625b01 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.rs +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.rs @@ -11,10 +11,6 @@ // Setting it to 12 would make it compile. #![recursion_limit = "6"] - -//~^^^^^^^^^^^^^^ WARN: overflow evaluating the requirement `(): Trait` [recursion_depth_exceeding_limit] -//~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - trait Trait {} struct W1(T); @@ -71,7 +67,7 @@ fn foo() fn main() { foo(); // register a `(): Trait` obligation - //~^ WARN: overflow evaluating the requirement `(): Trait<_>` [recursion_depth_exceeding_limit] + //~^ WARN: overflow evaluating the requirement `(): Trait` [recursion_depth_exceeding_limit] //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr index eeeace3180091..ae2680cf6394e 100644 --- a/tests/ui/traits/next-solver/overflow-discards-constraints.stderr +++ b/tests/ui/traits/next-solver/overflow-discards-constraints.stderr @@ -1,23 +1,20 @@ -warning: overflow evaluating the requirement `(): Trait<_>` - --> $DIR/overflow-discards-constraints.rs:73:5 +warning: overflow evaluating the requirement `(): Trait` + --> $DIR/overflow-discards-constraints.rs:69:5 | LL | foo(); // register a `(): Trait` obligation | ^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires W1: Trait + = note: which requires W2: Trait + = note: which requires W3: Trait + = note: which requires W4: Trait + = note: which requires W5: Trait + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `(): Trait` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`overflow_discards_constraints`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr index 41849b8d2f49a..94c87862ae716 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr @@ -1,23 +1,22 @@ warning: overflow evaluating the requirement `Foo>>>>>: Sync` - --> $DIR/fcw-on-auto-trait.rs:25:5 + --> $DIR/fcw-on-auto-trait.rs:22:5 | LL | require_sync::>>>>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires Option>>>>>: Sync + = note: which requires Foo>>>>: Sync + = note: which requires Option>>>>: Sync + = note: which requires Foo>>>: Sync + = note: which requires Option>>>: Sync + = note: which requires Foo>>: Sync + = note: which requires Option>>: Sync + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `Foo>>>>>: Sync` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_auto_trait`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs index 9252a04b9f6ce..73c0a5c153893 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs @@ -7,9 +7,6 @@ // and emit an FCW for this. // See the `NEXT_TRAIT_SOLVER_OVERFLOW` FCW. -//[next]~^^^^^^^^^ WARN: overflow evaluating the requirement `Foo>>>>>: Sync` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - #![recursion_limit = "8"] // The field order matters 😂 diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr index 76cc281cffd57..6c9224a7120c5 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr @@ -1,68 +1,17 @@ -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - --> $DIR/fcw-on-normalization.rs:45:12 +warning: overflow evaluating the requirement `>>>>>>>>> as HasAssoc>::Assoc == ()` + --> $DIR/fcw-on-normalization.rs:40:12 | LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: which requires >>>>>>>> as HasAssoc>::Assoc == () + = note: which requires >>>>>>> as HasAssoc>::Assoc == () + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) = note: this lint is attached to the whole crate and can't be disabled on a per-function basis = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #159228 = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: overflow evaluating the requirement `W>>>>>>>>>: HasAssoc` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` - --> $DIR/fcw-on-normalization.rs:45:12 - | -LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_on_normalization`) - = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved - = note: this lint is attached to the whole crate and can't be disabled on a per-function basis - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #159228 - -warning: 6 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs index fa5d518640dfc..c8fa0366f2944 100644 --- a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs @@ -7,11 +7,6 @@ // and emit an FCW for this. // See the `recursion_depth_exceeding_limit` FCW. -//[next]~^^^^^^^^^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -//[next]~| WARN: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` [recursion_depth_exceeding_limit] -//[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - #![recursion_limit = "8"] trait Trait { @@ -43,15 +38,8 @@ fn foo() { a.anyone_can_call(); let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; - //[next]~^ WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `>>>>>> as HasAssoc>::Assoc == _` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `W>>>>>>>>>: HasAssoc` [recursion_depth_exceeding_limit] + //[next]~^ WARN: overflow evaluating the requirement `>>>>>>>>> as HasAssoc>::Assoc == ()` [recursion_depth_exceeding_limit] //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //[next]~| WARN: overflow evaluating the requirement `>>>>> as HasAssoc>::Assoc well-formed` [recursion_depth_exceeding_limit] - //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - // Force normalization when looking up methods and the self_ty is normalized to infer. b.anyone_can_call(); } diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr new file mode 100644 index 0000000000000..92c0a480869df --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.next.stderr @@ -0,0 +1,22 @@ +warning: overflow evaluating the requirement `u32: Constrain>>>, W, _>>, _>>` + --> $DIR/fcw-overflow-to-ambig-with-constraints.rs:29:5 + | +LL | fun_times(); + | ^^^^^^^^^^^ + | + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, _>>, _>: Count + = note: which requires W>>>, W>>>, W<_, _>>>: Count + = note: which requires W>>>, W>>>, W<_, _>>>: Count + = note: which requires W>>>, W>>>, W<(), _>>>: Count + = help: consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = help: or consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`fcw_overflow_to_ambig_with_constraints`) + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs new file mode 100644 index 0000000000000..d8606225f246f --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-overflow-to-ambig-with-constraints.rs @@ -0,0 +1,32 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for `calimero-store` + +#![recursion_limit = "8"] +struct W(T, U); +trait Count {} +impl Count for W {} +impl Count for () {} +// Old solver is able to use cache entries from lower recursion depths, +// new one correctly tracks their required depth, so it needs more than 8 steps. +type Four = W>>>; + +trait Constrain {} +impl Constrain for u32 {} + +trait Equal {} +impl Equal for T {} + +fn fun_times() +where + u32: Constrain>>>, + T: Equal, +{} + +fn main() { + fun_times(); + //[next]~^ WARN: overflow evaluating the requirement `u32: Constrain>>>, W, _>>, _>>` + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +}