diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 8102208ec519d..d244e6c59e5f9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -306,7 +306,8 @@ pub fn parse_cfg_attr( features: Option<&Features>, lint_node_id: ast::NodeId, ) -> Option<(CfgEntry, Vec<(WithTokens, Span)>)> { - match &cfg_attr.get_normal_item().args { + let item = cfg_attr.get_normal_item(); + match &item.args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => { check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim); match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { @@ -316,11 +317,11 @@ pub fn parse_cfg_attr( Err(e) => { let suggestions = CFG_ATTR_TEMPLATE.suggestions( ParsedDescription::Attribute, - cfg_attr.get_normal_item().unsafety, + item.unsafety, sym::cfg_attr, ); e.with_span_suggestions( - cfg_attr.get_normal_item().span, + item.span, "must be of the form", suggestions, Applicability::HasPlaceholders, @@ -334,25 +335,24 @@ pub fn parse_cfg_attr( } } _ => { - let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = - cfg_attr.get_normal_item().args - { - (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) - } else { - (cfg_attr.get_normal_item().span, AttributeParseErrorReason::ExpectedList) - }; + let (span, reason) = + if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = item.args { + (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) + } else { + (item.span, AttributeParseErrorReason::ExpectedList) + }; sess.dcx().emit_err(AttributeParseError { span, - inner_span: cfg_attr.get_normal_item().span, + inner_span: item.span, template: CFG_ATTR_TEMPLATE, - path: AttrPath::from_ast(&cfg_attr.get_normal_item().path, identity), + path: AttrPath::from_ast(&item.path, identity), description: ParsedDescription::Attribute, reason, suggestions: diagnostics::AttributeParseErrorSuggestions::CreatedByTemplate( CFG_ATTR_TEMPLATE.suggestions( ParsedDescription::Attribute, - cfg_attr.get_normal_item().unsafety, + item.unsafety, sym::cfg_attr, ), ), @@ -389,13 +389,14 @@ fn parse_cfg_attr_internal<'a>( )?; let pred_span = pred_start.with_hi(parser.token.span.hi()); + let item = attribute.get_normal_item(); let cfg_predicate = AttributeParser::parse_single_args( sess, attribute.span, - attribute.get_normal_item().span, + item.span, attribute.style, AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span }, - Some(attribute.get_normal_item().unsafety), + Some(item.unsafety), AttributeSafety::Normal, ParsedDescription::Attribute, pred_span, diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index fb4a32d864fbe..a43cd918c8f35 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1235,7 +1235,7 @@ pub(crate) struct UnknownVersionLiteral { #[diag("multiple `{$name}` attributes")] pub(crate) struct UnusedMultiple { #[primary_span] - #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] + #[suggestion("remove this attribute", code = "", applicability = "unspecified")] pub this: Span, #[note("attribute also specified here")] pub other: Span, @@ -2061,7 +2061,7 @@ pub(crate) struct AdditionalCommaSuggestion { #[derive(Diagnostic)] #[diag("unused attribute")] pub(crate) struct UnusedDuplicate { - #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] + #[suggestion("remove this attribute", code = "", applicability = "unspecified")] pub this: Span, #[note("attribute also specified here")] pub other: Span, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 7537e2f9f1495..2bc361968a761 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -415,7 +415,7 @@ impl<'tcx> BorrowExplanation<'tcx> { let mut preds = path .iter() .filter_map(|constraint| match constraint.category { - ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred), + ConstraintCategory::Predicate(pred, _) if !pred.is_dummy() => Some(pred), _ => None, }) .collect::>(); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0b9615634fe1e..c101191102979 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -58,7 +58,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::ClosureUpvar(_) => "closure capture ", ConstraintCategory::Usage => "this usage ", ConstraintCategory::SolverRegionConstraint(_) - | ConstraintCategory::Predicate(_) + | ConstraintCategory::Predicate(_, _) | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c35c7ab311572..39361a886bd77 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -232,7 +232,7 @@ pub struct ClosureOutlivesRequirement<'tcx> { // Make sure this enum doesn't unintentionally grow #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); +rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 24); /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing /// that must outlive some region. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b547d24c7198c..60b258eca80df 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -275,11 +275,11 @@ impl<'tcx> BestBlame<'tcx> { .path .iter() .find_map(|constraint| { - if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + if let ConstraintCategory::Predicate(predicate_span, def_id) = constraint.category { // We currently do not store the `DefId` in the `ConstraintCategory` // for performances reasons. The error reporting code used by NLL only // uses the span, so this doesn't cause any problems at the moment. - Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span)) + Some(ObligationCauseCode::WhereClause(def_id, predicate_span)) } else { None } diff --git a/compiler/rustc_borrowck/src/region_infer/region_context.rs b/compiler/rustc_borrowck/src/region_infer/region_context.rs index a6f7c19ff0c17..327acb7da3fb8 100644 --- a/compiler/rustc_borrowck/src/region_infer/region_context.rs +++ b/compiler/rustc_borrowck/src/region_infer/region_context.rs @@ -742,7 +742,7 @@ impl<'tcx> RegionInferenceContextInner<'tcx> { // Generic arguments are unlikely to be what relates regions together ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 3, // We handle predicates and opaque types specially; don't prioritize them here. - ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4, + ConstraintCategory::Predicate(_, _) | ConstraintCategory::OpaqueType => 4, // `Boring` constraints can correspond to user-written code and have useful spans, // but don't provide any other useful information for diagnostics. ConstraintCategory::Boring => 5, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 9e4a39873753c..b295a66ee74ee 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -142,15 +142,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn normalize_and_prove_instantiated_clauses( &mut self, - // Keep this parameter for now, in case we start using - // it in `ConstraintCategory` at some point. - _def_id: DefId, + def_id: DefId, instantiated_clauses: ty::InstantiatedClauses<'tcx>, locations: Locations, ) { for (clause, span) in instantiated_clauses { debug!(?span, ?clause); - let category = ConstraintCategory::Predicate(span); + let category = ConstraintCategory::Predicate(span, def_id); let clause = self.normalize_with_category(clause, locations, category); self.prove_clause(clause, locations, category); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0a6fb9d5da47a..0e8565aef3f0b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1361,7 +1361,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int)) => (), _ => { span_mirbug!( self, @@ -1379,7 +1379,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (), + (Some(CastTy::Int), Some(CastTy::Ptr(_))) => (), _ => { span_mirbug!( self, @@ -1396,7 +1396,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (), + (Some(from), Some(to)) if from.is_int_like() && to.is_int_like() => (), _ => { span_mirbug!( self, @@ -1413,7 +1413,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Float)) => (), + (Some(CastTy::Int), Some(CastTy::Float)) => (), _ => { span_mirbug!( self, @@ -1430,7 +1430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Float), Some(CastTy::Int(_))) => (), + (Some(CastTy::Float), Some(CastTy::Int)) => (), _ => { span_mirbug!( self, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index e52da1136dd64..d4817d7ad25ac 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -339,7 +339,9 @@ fn make_format_args( parse::Suggestion::UsePositional => { let captured_arg_span = fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { + if is_source_literal + && let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) + { let span = match args.unnamed_args().last() { Some(arg) => arg.expr.span, None => fmt_span, @@ -360,17 +362,21 @@ fn make_format_args( } } parse::Suggestion::ReorderFormatParameter(span, replacement) => { - let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = - Some(diagnostics::InvalidFormatStringSuggestion::ReorderFormatParameter { - span, - replacement, - }); + if is_source_literal { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::ReorderFormatParameter { + span, + replacement, + }); + } } parse::Suggestion::AddMissingColon(span) => { - let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = - Some(diagnostics::InvalidFormatStringSuggestion::AddMissingColon { span }); + if is_source_literal { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = + Some(diagnostics::InvalidFormatStringSuggestion::AddMissingColon { span }); + } } parse::Suggestion::UseRustDebugPrintingMacro => { // This targets `println!("{=}", x);` and `println!("{0=}", x);` diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index cad775cc98641..76b2c428ec84d 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -28,7 +28,7 @@ macro_rules! define_stable_id_collections { } pub mod default { - use super::{FxBuildHasher, FxHashMap, FxHashSet}; + use super::{FxBuildHasher, FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; // FIXME: These two functions will become unnecessary after // lands and we start using the corresponding @@ -40,4 +40,12 @@ pub mod default { pub const fn fx_hash_set() -> FxHashSet { FxHashSet::with_hasher(FxBuildHasher) } + + pub const fn fx_index_map() -> FxIndexMap { + FxIndexMap::with_hasher(FxBuildHasher) + } + + pub const fn fx_index_set() -> FxIndexSet { + FxIndexSet::with_hasher(FxBuildHasher) + } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index efed5994f63fe..e7f20766bc8eb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -115,7 +115,11 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran Err(CopyImplementationError::HasDestructor(did)) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; let impl_ = tcx.def_span(did); - Err(tcx.dcx().emit_err(diagnostics::CopyImplOnTypeWithDtor { span, impl_ })) + Err(tcx.dcx().emit_err(diagnostics::TraitImplOnTypeWithDtor { + span, + impl_, + trait_name: sym::Copy, + })) } Err(CopyImplementationError::HasUnsafeFields) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; @@ -537,6 +541,15 @@ pub(crate) fn reborrow_info<'tcx>( assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field.ty, field.span)?; } + if let Some(did) = def.destructor(tcx).map(|dtor| dtor.did) { + let impl_ = tcx.def_span(did); + return Err(tcx.dcx().emit_err(diagnostics::TraitImplOnTypeWithDtor { + span, + impl_, + trait_name: sym::Reborrow, + })); + } + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 421f0b52d5a3b..7e5e794b75f78 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -296,13 +296,14 @@ pub(crate) struct FieldAlreadyDeclaredNestedHelp { } #[derive(Diagnostic)] -#[diag("the trait `Copy` cannot be implemented for this type; the type has a destructor", code = E0184)] -pub(crate) struct CopyImplOnTypeWithDtor { +#[diag("the trait `{$trait_name}` cannot be implemented for this type; the type has a destructor", code = E0184)] +pub(crate) struct TraitImplOnTypeWithDtor { #[primary_span] - #[label("`Copy` not allowed on types with destructors")] + #[label("`{$trait_name}` not allowed on types with destructors")] pub span: Span, #[note("destructor declared here")] pub impl_: Span, + pub trait_name: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 02e6b8188a876..14cb73e28c871 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -39,7 +39,7 @@ use rustc_lint_defs::builtin::{TRIVIAL_CASTS, TRIVIAL_NUMERIC_CASTS}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::cast::{CastKind, CastTy}; +use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, Unnormalized, VariantDef, elaborate, @@ -52,6 +52,22 @@ use tracing::{debug, instrument}; use super::FnCtxt; use crate::{diagnostics, type_error_struct}; +/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) +/// (or rustc_hir_typeck/src/cast.rs). +#[derive(Copy, Clone, Debug)] +pub enum CastKind { + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast, +} + /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] @@ -912,7 +928,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// directly. coercion-cast is handled in check instead of here. fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result> { use rustc_middle::ty::cast::CastTy::*; - use rustc_middle::ty::cast::IntTy::*; let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { @@ -947,7 +962,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // a cast. ty::Ref(_, inner_ty, mutbl) => { return match t_cast { - Int(_) | Float => match *inner_ty.kind() { + Int | CEnum | Bool | Char | Float => match *inner_ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -979,19 +994,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { } match (t_from, t_cast) { // These types have invariants! can't cast into them. - (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), + (_, CEnum | FnPtr) => Err(CastError::NonScalar), // * -> Bool - (_, Int(Bool)) => Err(CastError::CastToBool), + (_, Bool) => Err(CastError::CastToBool), // * -> Char - (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast - (_, Int(Char)) => Err(CastError::CastToChar), + (Int, Char) if self.expr_ty == fcx.tcx.types.u8 => { + Ok(CastKind::U8CharCast) // u8-char-cast + } + (_, Char) => Err(CastError::CastToChar), // prim -> float,ptr - (Int(Bool) | Int(CEnum) | Int(Char), Float) => Err(CastError::NeedViaInt), + (Bool | CEnum | Char, Float) => Err(CastError::NeedViaInt), - (Int(Bool) | Int(CEnum) | Int(Char) | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => { + (Bool | CEnum | Char | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => { Err(CastError::IllegalCast) } @@ -999,24 +1016,24 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast // ptr-addr-cast - (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), + (Ptr(m_expr), Int) => self.check_ptr_addr_cast(fcx, m_expr), - (FnPtr, Int(_)) => { + (FnPtr, Int) => { // FIXME(#95489): there should eventually be a lint for these casts Ok(CastKind::FnPtrAddrCast) } // addr-ptr-cast - (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), + (Int, Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // fn-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // enum -> int - (Int(CEnum), Int(_)) => self.check_enum_cast(fcx), + (CEnum, Int) => self.check_enum_cast(fcx), // prim -> prim - (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), + (Char | Bool, Int) => Ok(CastKind::PrimIntCast), - (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + (Int | Float, Int | Float) => Ok(CastKind::NumericCast), } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e02cc9a7acd1f..a7ce6a4353b59 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -463,7 +463,7 @@ pub enum SubregionOrigin<'tcx> { trait_item_def_id: DefId, }, - AscribeUserTypeProvePredicate(Span), + AscribeUserTypeProvePredicate(Span, DefId), // FIXME(-Zassumptions-on-binders): this is a temporary hack until we support // proper diagnostics for solver region constraints. @@ -478,7 +478,9 @@ impl<'tcx> SubregionOrigin<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self { Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), - Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), + Self::AscribeUserTypeProvePredicate(span, def_id) => { + ConstraintCategory::Predicate(*span, *def_id) + } Self::SolverRegionConstraint(span) => ConstraintCategory::SolverRegionConstraint(*span), _ => ConstraintCategory::BoringNoLocation, } @@ -1840,7 +1842,7 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::Reborrow(a) => a, SubregionOrigin::ReferenceOutlivesReferent(_, a) => a, SubregionOrigin::CompareImplItemObligation { span, .. } => span, - SubregionOrigin::AscribeUserTypeProvePredicate(span) => span, + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => span, SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), SubregionOrigin::SolverRegionConstraint(a) => a, } @@ -1874,8 +1876,8 @@ impl<'tcx> SubregionOrigin<'tcx> { parent: Box::new(default()), }, - traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => { - SubregionOrigin::AscribeUserTypeProvePredicate(span) + traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span, def_id) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, def_id) } traits::ObligationCauseCode::ObjectTypeBound(ty, _reg) => { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index beb63ad61493c..79b590ab854f2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -775,7 +775,11 @@ extern "C" LLVMRustResult LLVMRustOptimize( SmallVector Plugins; PluginsStr.split(Plugins, ',', -1, false); for (auto PluginPath : Plugins) { +#if LLVM_VERSION_GE(24, 0) + auto Plugin = PassPlugin::load(PluginPath); +#else auto Plugin = PassPlugin::Load(PluginPath.str()); +#endif if (!Plugin) { auto Err = Plugin.takeError(); auto ErrMsg = llvm::toString(std::move(Err)); diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 9685ac89011e5..3a008514f7d07 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -5,7 +5,7 @@ use std::cmp::Ordering; use std::hash::Hash; -use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry, default}; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; use rustc_hir::def::DefKind; use rustc_hir::{ItemKind, Node, UseKind, UseTree}; @@ -277,9 +277,9 @@ impl EffectiveVisibilities { } } -impl Default for EffectiveVisibilities { +const impl Default for EffectiveVisibilities { fn default() -> Self { - EffectiveVisibilities { map: Default::default() } + EffectiveVisibilities { map: default::fx_index_map() } } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 616b1719359f1..2e84fd80f35e5 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_span::def_id::DefId; use rustc_span::{Span, Symbol}; use super::{ConstValue, SourceInfo}; @@ -129,7 +130,7 @@ pub enum ConstraintCategory<'tcx> { /// A constraint from a user-written predicate /// with the provided span, written on the item /// with the given `DefId` - Predicate(Span), + Predicate(Span, DefId), /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs index 4ab2fbe914965..8faf6f68f49c9 100644 --- a/compiler/rustc_middle/src/query/arena_cached.rs +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -5,13 +5,15 @@ use rustc_span::ErrorGuaranteed; use crate::ty::TyCtxt; -/// Helper trait that allows `arena_cache` queries to return `Option<&T>` -/// instead of `&Option`, and avoid allocating `None` in the arena. +/// Helper trait that allows `arena_cache` queries to return: +/// - `Option<&T>` instead of `&Option`, and avoid allocating `None` in the arena; or +/// - `Result<&T, ErrorGuaranteed>` instead of `&Result`, and avoid allocating +/// `Err(ErrorGuaranteed)` in the arena. /// -/// An arena-cached query must be declared to return a type that implements -/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then -/// determines the types returned by the provider and stored in the arena, -/// and provides a function to bridge between the three types. +/// An arena-cached query must be declared to return a type that implements this trait, i.e. +/// `&'tcx T`, `Option<&'tcx T>`, or `Result<&'tcx T, ErrorGuaranteed>`. This trait then determines +/// the types returned by the provider and stored in the arena, and provides a function to bridge +/// between the three types. pub trait ArenaCached<'tcx>: Sized { /// Type that is returned by the query provider. type Provided; diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 4fd91caa94cd7..3e057e96ddb6b 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -1,4 +1,5 @@ -//! This contains documentation which is linked from query modifiers used in the `rustc_queries!` proc macro. +//! This contains documentation which is linked from query modifiers used in the `rustc_queries!` +//! proc macro. //! //! The dummy items in this module are used to enable hover documentation for //! modifier names in the query list, and to allow find-all-references to list @@ -10,10 +11,12 @@ /// # `arena_cache` query modifier /// /// Query return values must impl `Copy` and be small, but some queries must return values that -/// doesn't meet those criteria. Queries marked with this modifier have their values allocated in -/// an arena and the query returns a reference to the value. There are two cases. +/// don't meet those criteria. Queries marked with this modifier have their values allocated in +/// an arena and the query returns a reference to the value. There are three cases. /// - If the provider function returns `T` then the query will return `&'tcx T`. /// - If the provider function returns `Option` then the query will return `Option<&'tcx T>`. +/// - If the provider function returns `Result` then the query will return +/// `Result<&'tcx T, ErrorGuaranteed>`. /// /// The query plumbing takes care of the arenas and the type manipulations. pub(crate) struct arena_cache; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a50c5226c052d..493f6989f342c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -137,8 +137,8 @@ impl<'tcx> ObligationCause<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self.code() { ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(), - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span) => { - ConstraintCategory::Predicate(*predicate_span) + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span, def_id) => { + ConstraintCategory::Predicate(*predicate_span, *def_id) } _ => ConstraintCategory::BoringNoLocation, } @@ -402,7 +402,7 @@ pub enum ObligationCauseCode<'tcx> { output_ty: Option>, }, - AscribeUserTypeProvePredicate(Span), + AscribeUserTypeProvePredicate(Span, DefId), RustCall, diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 25fc0775b1a32..fc8a6de5d232e 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -1,35 +1,20 @@ -// Helpers for handling cast expressions, used in both -// typeck and codegen. +// Helpers for handling cast expressions. -use rustc_macros::{StableHash, TyDecodable, TyEncodable}; use rustc_span::bug; use crate::mir; use crate::ty::{self, Ty}; -/// Types that are represented as ints. +/// Valid types for the result of a non-coercion cast #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IntTy { - U(ty::UintTy), - I, +pub enum CastTy<'tcx> { + /// `iN`, `uN`, and integer inference variables. + Int, + /// C-like (fieldless) enums. CEnum, Bool, Char, -} - -impl IntTy { - pub fn is_signed(self) -> bool { - matches!(self, Self::I) - } -} - -// Valid types for the result of a non-coercion cast -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CastTy<'tcx> { - /// Various types that are represented as ints and handled mostly - /// in the same way, merged for easier matching. - Int(IntTy), - /// Floating-point types. + /// `fN` and float inference variables. Float, /// Function pointers. FnPtr, @@ -37,40 +22,28 @@ pub enum CastTy<'tcx> { Ptr(ty::TypeAndMut<'tcx>), } -/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) -/// (or rustc_hir_analysis/check/cast.rs). -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash)] -pub enum CastKind { - PtrPtrCast, - PtrAddrCast, - AddrPtrCast, - NumericCast, - EnumCast, - PrimIntCast, - U8CharCast, - ArrayPtrCast, - FnPtrPtrCast, - FnPtrAddrCast, -} - impl<'tcx> CastTy<'tcx> { /// Returns `Some` for integral/pointer casts. /// Casts like unsizing casts will return `None`. pub fn from_ty(t: Ty<'tcx>) -> Option> { match *t.kind() { - ty::Bool => Some(CastTy::Int(IntTy::Bool)), - ty::Char => Some(CastTy::Int(IntTy::Char)), - ty::Int(_) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)), - ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), - ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))), - ty::Float(_) => Some(CastTy::Float), - ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), + ty::Bool => Some(CastTy::Bool), + ty::Char => Some(CastTy::Char), + ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int), + ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), + ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::CEnum), ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })), ty::FnPtr(..) => Some(CastTy::FnPtr), _ => None, } } + + pub fn is_int_like(self) -> bool { + match self { + CastTy::Int | CastTy::CEnum | CastTy::Bool | CastTy::Char => true, + CastTy::Float | CastTy::FnPtr | CastTy::Ptr(_) => false, + } + } } /// Returns `mir::CastKind` from the given parameters. @@ -78,15 +51,17 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin let from = CastTy::from_ty(from_ty); let cast = CastTy::from_ty(cast_ty); let cast_kind = match (from, cast) { - (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + (Some(from), Some(cast)) if from.is_int_like() && cast.is_int_like() => { + mir::CastKind::IntToInt + } + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int)) => { mir::CastKind::PointerExposeProvenance } - (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, - (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt, + (Some(CastTy::Int), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr, - (Some(CastTy::Float), Some(CastTy::Int(_))) => mir::CastKind::FloatToInt, - (Some(CastTy::Int(_)), Some(CastTy::Float)) => mir::CastKind::IntToFloat, + (Some(CastTy::Float), Some(CastTy::Int)) => mir::CastKind::FloatToInt, + (Some(CastTy::Int), Some(CastTy::Float)) => mir::CastKind::IntToFloat, (Some(CastTy::Float), Some(CastTy::Float)) => mir::CastKind::FloatToFloat, (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PtrToPtr, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b6e204dd52a11..be4679320e9c7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1135,7 +1135,7 @@ impl<'tcx> TyCtxt<'tcx> { | CrateType::Cdylib | CrateType::Sdylib => false, CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, - }) + }) && !self.sess.opts.actually_rustdoc } pub fn needs_hir_hash(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 243ad73e3dfb8..925915c88cdb4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2115,28 +2115,9 @@ impl<'tcx> Ty<'tcx> { match self.kind() { ty::Bool => Some(sym::bool), ty::Char => Some(sym::char), - ty::Float(f) => match f { - ty::FloatTy::F16 => Some(sym::f16), - ty::FloatTy::F32 => Some(sym::f32), - ty::FloatTy::F64 => Some(sym::f64), - ty::FloatTy::F128 => Some(sym::f128), - }, - ty::Int(f) => match f { - ty::IntTy::Isize => Some(sym::isize), - ty::IntTy::I8 => Some(sym::i8), - ty::IntTy::I16 => Some(sym::i16), - ty::IntTy::I32 => Some(sym::i32), - ty::IntTy::I64 => Some(sym::i64), - ty::IntTy::I128 => Some(sym::i128), - }, - ty::Uint(f) => match f { - ty::UintTy::Usize => Some(sym::usize), - ty::UintTy::U8 => Some(sym::u8), - ty::UintTy::U16 => Some(sym::u16), - ty::UintTy::U32 => Some(sym::u32), - ty::UintTy::U64 => Some(sym::u64), - ty::UintTy::U128 => Some(sym::u128), - }, + ty::Int(i) => Some(i.name()), + ty::Uint(u) => Some(u.name()), + ty::Float(f) => Some(f.name()), ty::Str => Some(sym::str), _ => None, } diff --git a/compiler/rustc_monomorphize/src/diagnostics.rs b/compiler/rustc_monomorphize/src/diagnostics.rs index a1930dbea3cda..7635050603c41 100644 --- a/compiler/rustc_monomorphize/src/diagnostics.rs +++ b/compiler/rustc_monomorphize/src/diagnostics.rs @@ -96,7 +96,7 @@ pub(crate) struct EncounteredErrorWhileInstantiatingGlobalAsm { #[derive(Diagnostic)] #[diag("using `fn main` requires the standard library")] #[help( - "use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]`" + "use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[unsafe(no_mangle)]`" )] pub(crate) struct StartNotFound; 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 c841845392429..40febd26806a6 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 @@ -63,6 +63,8 @@ enum CurrentGoalKind { /// These are currently the only goals whose impl where-clauses are considered to be /// productive steps. CoinductiveTrait, + /// A `ProjectionGoal`. These are temporarily special wrt to cycle handling. + Projection, // FIXME: Consider renaming `PredicateKind::NormalizesTo` to match with this /// Unlike other goals, `NormalizesTo` goals aren't independent goals but just implementation /// details for handling projections of associated terms. When we encounter a `Projection` goal @@ -89,6 +91,7 @@ impl CurrentGoalKind { CurrentGoalKind::Misc } } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => CurrentGoalKind::Projection, ty::PredicateKind::NormalizesTo(_) => { CurrentGoalKind::ProjectionComputeAssocTermCandidate } @@ -428,46 +431,29 @@ where } /// Computes the `PathKind` for the step from the current goal to the - /// nested goal required due to `source`. + /// nested goal. See #136824 for a more detailed reasoning for this why we care about + /// the step from a goal to its nested goals. /// - /// See #136824 for a more detailed reasoning for this behavior. We - /// consider cycles to be coinductive if they 'step into' a where-clause - /// of a coinductive trait. We will likely extend this function in the future - /// and will need to clearly document it in the rustc-dev-guide before - /// stabilization. - pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind { - match source { - // We treat these goals as unknown for now. It is likely that most miscellaneous - // nested goals will be converted to an inductive variant in the future. - // - // Having unknown cycles is always the safer option, as changing that to either - // succeed or hard error is backwards compatible. If we incorrectly treat a cycle - // as inductive even though it should not be, it may be unsound during coherence and - // fixing it may cause inference breakage or introduce ambiguity. - GoalSource::Misc => PathKind::Unknown, - GoalSource::NormalizeGoal(path_kind) => path_kind, - GoalSource::ImplWhereBound => match self.current_goal_kind { - // We currently only consider a cycle coinductive if it steps - // into a where-clause of a coinductive trait. - CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive, - // We probably want to make all traits coinductive in the future, - // so we treat cycles involving where-clauses of not-yet coinductive - // traits as ambiguous for now. - CurrentGoalKind::Misc | CurrentGoalKind::ProjectionComputeAssocTermCandidate => { - PathKind::Unknown - } - }, - // Relating types is always unproductive. If we were to map proof trees to - // corecursive functions as explained in #136824, relating types never - // introduces a constructor which could cause the recursion to be guarded. - // - // FIXME(-Znext-solver=coinductive): For now we treat all inductive cycles as - // `Unknown`. See the comment in `fn initial_provisional_result`. - GoalSource::TypeRelating => PathKind::Unknown, - // These goal sources are likely unproductive and can be changed to - // `PathKind::Inductive`. Keeping them as unknown until we're confident - // about this and have an example where it is necessary. - GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown, + /// For now we're entirely ignoring the reason why the current goal depends on the + /// nested goal and instead only depend on the current goal itself. This closely + /// matches the old solver. This is something we'll likely improve as we go forward + /// afterwards. + // FIXME(-Znext-solver=coinductive): Nothing interesting going on here right now + // and we're ignoring the goal source. We should change this going forward. + pub(super) fn step_kind_to_nested(&self, _source: GoalSource) -> PathKind { + match self.current_goal_kind { + // We currently consider a cycle involving a trait goal for a coinductive + // trait as coinductive as long as it otherwise only includes normalization. + CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive, + // We do need to treat cycles involving only coinductive trait goals + // and normalization as coinductive due to trait-system-refactor-initiative#10. + CurrentGoalKind::ProjectionComputeAssocTermCandidate | CurrentGoalKind::Projection => { + PathKind::Unknown + } + // We probably want to make all traits coinductive in the future, + // so we treat cycles involving where-clauses of not-yet coinductive + // traits as ambiguous for now. + CurrentGoalKind::Misc => PathKind::ForcedAmbiguity, } } @@ -771,7 +757,7 @@ where let (goal, opaque_types) = self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = self.typing_mode(); - let step_kind = self.step_kind_for_source(source); + let step_kind = self.step_kind_to_nested(source); let tracing_span = tracing::span!( Level::DEBUG, @@ -1109,11 +1095,8 @@ where source: GoalSource, mut goal: Goal, ) -> Result<(), NoSolutionOrRerunNonErased> { - goal.predicate = self.normalize( - GoalSource::NormalizeGoal(self.step_kind_for_source(source)), - goal.param_env, - ty::Unnormalized::new_wip(goal.predicate), - )?; + goal.predicate = + self.normalize(goal.param_env, ty::Unnormalized::new_wip(goal.predicate))?; self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); if let Some(GoalEvaluation { goal, certainty, has_changed: _, stalled_on }) = @@ -1339,10 +1322,12 @@ where let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; for &goal in goals.iter() { let source = match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Subtype { .. } - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { - GoalSource::TypeRelating + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { + GoalSource::Normalization } + // FIXME(-Znext-solver=coinductive): subtyping goals should + // likely be unproductive + ty::PredicateKind::Subtype { .. } => GoalSource::Misc, // FIXME(-Znext-solver=coinductive): should these WF goals also be unproductive? ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc, p => unreachable!("unexpected nested goal in `relate`: {p:?}"), @@ -1519,9 +1504,7 @@ where match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - self.delegate.evaluate_const(param_env, alias_const, |ty| { - self.normalize(GoalSource::Misc, param_env, ty) - }) + self.delegate.evaluate_const(param_env, alias_const, |ty| self.normalize(param_env, ty)) } pub(super) fn evaluate_const_and_instantiate_projection_term( @@ -1803,7 +1786,6 @@ where pub(super) fn normalize>( &mut self, - source: GoalSource, param_env: I::ParamEnv, value: ty::Unnormalized, ) -> Result { @@ -1819,6 +1801,7 @@ where let infer_term = self.next_term_infer_of_alias_kind(alias_term); let pred = ty::ProjectionClause { projection_term: alias_term, term: infer_term }; let goal = Goal::new(self.cx(), param_env, pred); + let source = GoalSource::Normalization; self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); let GoalEvaluation { goal, certainty, has_changed: _, stalled_on } = self.evaluate_goal(source, goal, None)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 924a705205e1c..099c755d78427 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -118,7 +118,7 @@ where goal: Goal>, ) -> QueryResultOrRerunNonErased { let ty::OutlivesClause(ty, lt) = goal.predicate; - let ty = self.normalize(GoalSource::Misc, goal.param_env, ty::Unnormalized::new_wip(ty))?; + let ty = self.normalize(goal.param_env, ty::Unnormalized::new_wip(ty))?; // The normalized type can still contain non-rigid higher ranked aliases if their // normalization ends up with ambiguity. Or we have non-rigid aliases inside rigid ones. @@ -456,7 +456,7 @@ where ); // We normalize the self type to be able to relate it with // types from candidates. - self.add_goal(GoalSource::TypeRelating, projection_goal)?; + self.add_goal(GoalSource::Normalization, projection_goal)?; self.try_evaluate_added_goals()?; Ok(self.deeply_resolve_ignoring_regions(normalized_term)) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 388b334ccf618..4203ae8c509cc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -439,7 +439,7 @@ where let term = match target_item_kind { ty::AliasTermKind::ProjectionTy { .. } => { let t = cx.type_of(target_item_def_id).instantiate(cx, target_args); - let t = ecx.normalize(GoalSource::Misc, goal.param_env, t)?; + let t = ecx.normalize(goal.param_env, t)?; t.into() } ty::AliasTermKind::ProjectionConst { def_id } @@ -447,7 +447,7 @@ where cx.const_of_item(ty::AliasConstKind::Projection { def_id }) => { let c = c.instantiate(cx, target_args); - let c = ecx.normalize(GoalSource::Misc, goal.param_env, c)?; + let c = ecx.normalize(goal.param_env, c)?; c.into() } ty::AliasTermKind::ProjectionConst { .. } => { diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs index 4481e1bc144ac..dfcc89b91a4f2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs @@ -34,14 +34,14 @@ where let actual = match free_alias.kind { ty::AliasTermKind::FreeTy { def_id } => { let free = cx.type_of(def_id.into()).instantiate(cx, free_alias.args); - let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; + let free = self.normalize(goal.param_env, free)?; free.into() } ty::AliasTermKind::FreeConst { def_id } if let Some(free) = cx.const_of_item(ty::AliasConstKind::Free { def_id }) => { let free = free.instantiate(cx, free_alias.args); - let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; + let free = self.normalize(goal.param_env, free)?; free.into() } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs index d519d1e538f1a..45ece5a0589fb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs @@ -45,7 +45,7 @@ where let normalized: I::Term = match inherent_kind { ty::AliasTermKind::InherentTy { def_id } => { let inherent = cx.type_of(def_id.into()).instantiate(cx, inherent_args); - let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; + let inherent = self.normalize(goal.param_env, inherent)?; inherent.into() } ty::AliasTermKind::InherentConstImpl { def_id } @@ -53,7 +53,7 @@ where cx.const_of_item(ty::AliasConstKind::InherentImpl { def_id }) => { let inherent = inherent.instantiate(cx, inherent_args); - let normalized_ct = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; + let normalized_ct = self.normalize(goal.param_env, inherent)?; let normalized = normalized_ct.into(); let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args); self.push_const_arg_has_type_goal(goal.param_env, term, normalized)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs index 9d6b8875071ba..f6521e579d722 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs @@ -69,7 +69,7 @@ where let ( NestedNormalizationGoals(nested_goals), GoalEvaluation { goal: _, certainty, stalled_on: _, has_changed: _ }, - ) = self.evaluate_goal_raw(GoalSource::TypeRelating, normalizes_to)?; + ) = self.evaluate_goal_raw(GoalSource::Normalization, normalizes_to)?; trace!(?nested_goals); diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 2f56056449779..048c8bb45361b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -99,8 +99,7 @@ where _ => re, }) }); - let actual = - self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; } TypingMode::Coherence @@ -145,7 +144,7 @@ where _ => re, }) }); - let actual = self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) @@ -154,7 +153,7 @@ where TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args); - let actual = self.normalize(GoalSource::Misc, goal.param_env, actual)?; + let actual = self.normalize(goal.param_env, actual)?; self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) .map_err(Into::into) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b92da685bc6a5..f4f0529698fa4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1425,11 +1425,11 @@ pub struct Resolver<'ra, 'tcx> { extern_module_map: RwLock>>, /// Maps glob imports to the names of items actually imported. - glob_map: FxIndexMap>, + glob_map: FxIndexMap> = default::fx_index_map(), glob_error: Option = None, visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), used_imports: FxHashSet = default::fx_hash_set(), - maybe_unused_trait_imports: FxIndexSet, + maybe_unused_trait_imports: FxIndexSet = default::fx_index_set(), /// Privacy errors are delayed until the end in order to deduplicate them. privacy_errors: Vec> = Vec::new(), @@ -1450,7 +1450,7 @@ pub struct Resolver<'ra, 'tcx> { builtin_macros: FxHashMap = default::fx_hash_map(), registered_attr_tools: &'tcx RegisteredTools, registered_lint_tools: &'tcx RegisteredTools, - macro_use_prelude: FxIndexMap>, + macro_use_prelude: FxIndexMap> = default::fx_index_map(), /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap> = default::fx_hash_map(), /// Lazily populated cache of macro definitions loaded from external crates. @@ -1460,9 +1460,9 @@ pub struct Resolver<'ra, 'tcx> { non_macro_attr: &'ra Arc, local_macro_def_scopes: FxHashMap> = default::fx_hash_map(), ast_transform_scopes: FxHashMap> = default::fx_hash_map(), - unused_macros: FxIndexMap, + unused_macros: FxIndexMap = default::fx_index_map(), /// A map from the macro to all its potentially unused arms and the `LocalDefId` of the macro itself. - unused_macro_rules: FxIndexMap)>, + unused_macro_rules: FxIndexMap)> = default::fx_index_map(), proc_macro_stubs: FxHashSet = default::fx_hash_set(), /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1529,25 +1529,25 @@ pub struct Resolver<'ra, 'tcx> { /// Generic args to suggest for required params (e.g. `<'_>`, `<_, _>`), if any. item_required_generic_args_suggestions: FxHashMap = default::fx_hash_map(), delegation_fn_sigs: LocalDefIdMap = Default::default(), - delegation_infos: FxIndexMap, - delegation_inherent_fn_map: FxIndexMap>, + delegation_infos: FxIndexMap = default::fx_index_map(), + delegation_inherent_fn_map: FxIndexMap> = default::fx_index_map(), main_def: Option = None, - trait_impls: FxIndexMap>, + trait_impls: FxIndexMap> = default::fx_index_map(), /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec = Vec::new(), - paths_matching_assoc_types: UnordSet, - confused_type_with_std_module: FxIndexMap, + paths_matching_assoc_types: UnordSet = Default::default(), + confused_type_with_std_module: FxIndexMap = default::fx_index_map(), /// Names of items that were stripped out via cfg with their corresponding cfg meta item. stripped_cfg_items: Vec> = Vec::new(), - effective_visibilities: EffectiveVisibilities, - macro_reachable_adts: FxIndexMap>, + effective_visibilities: EffectiveVisibilities = Default::default(), + macro_reachable_adts: FxIndexMap> = default::fx_index_map(), - doc_link_resolutions: FxIndexMap, - doc_link_traits_in_scope: FxIndexMap>, + doc_link_resolutions: FxIndexMap = default::fx_index_map(), + doc_link_traits_in_scope: FxIndexMap> = default::fx_index_map(), all_macro_rules: UnordSet = Default::default(), /// Invocation ids of all glob delegations. @@ -1860,9 +1860,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), - glob_map: Default::default(), - maybe_unused_trait_imports: Default::default(), - arenas, dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_type_decls: PrimTy::ALL @@ -1891,31 +1888,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(), registered_attr_tools, registered_lint_tools, - macro_use_prelude: Default::default(), extern_macro_map: Default::default(), dummy_ext_bang: arenas.alloc_macro(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: arenas.alloc_macro(SyntaxExtension::dummy_derive(edition)), non_macro_attr: arenas.alloc_macro(SyntaxExtension::non_macro_attr(edition)), - unused_macros: Default::default(), - unused_macro_rules: Default::default(), single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), owners, current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), invocation_parents, - trait_impls: Default::default(), - confused_type_with_std_module: Default::default(), - paths_matching_assoc_types: Default::default(), - stripped_cfg_items: Default::default(), - effective_visibilities: Default::default(), - macro_reachable_adts: Default::default(), - doc_link_resolutions: Default::default(), - doc_link_traits_in_scope: Default::default(), current_crate_outer_attr_insert_span, disambiguators: Default::default(), - delegation_infos: Default::default(), - delegation_inherent_fn_map: Default::default(), features: tcx.features(), .. }; diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 0e3ccf33c3ffe..e444e605d3b5a 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -1,6 +1,7 @@ use arrayvec::ArrayVec; use rustc_abi::{ - BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface, + BackendRepr, FieldsShape, Float, HasDataLayout, Integer, Numeric, Primitive, Reg, RegKind, + Size, TyAbiInterface, }; use crate::callconv::{ArgAbi, ArgAttribute, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; @@ -56,6 +57,22 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 128 { + // NOTE: Complex is returned indirectly. + if let Some(component) = ret.layout.complex_number(cx) { + match component { + Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => { + // Return a Complex<{integer}> packed into a single register when that fits. + ret.cast_to(Reg { kind: RegKind::Integer, size }); + } + _ => { + // Otherwise pass in 2 registers. + let reg = Reg { kind: component.reg_kind(), size: component.size() }; + ret.cast_to(CastTarget::pair(reg, reg)); + } + } + return; + } + // Unlike other architectures which return aggregates in registers, MIPS n64 limits the // use of float registers to structures (not unions) containing exactly one or two // float fields. @@ -103,6 +120,52 @@ where extend_integer_width_mips(arg, 64); } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { arg.make_indirect(); + } else if let Some(component) = arg.layout.complex_number(cx) + && !matches!(component, Numeric::Float(Float::F16)) + { + let slot = dl.pointer_size(); + let curr_offset = offset.align_to(align); + + const NUM_ARG_SLOTS: u64 = 8; + + match component { + Numeric::Float(Float::F16B) => unreachable!("Complex is not C-compatible"), + Numeric::Float(Float::F16) => unreachable!("not supported on mips64"), + Numeric::Float(Float::F32 | Float::F64) => { + // Only pass a Complex/Complex in FPRs when two argument slots are free. + if curr_offset.bytes() / slot.bytes() + 2 <= NUM_ARG_SLOTS { + // Both components claim a slot, even a Complex which could fit in one + // slot. + // + // FIXME(complex_numbers): c-variadic arguments are passed in GPRs, so need a + // special carve-out here and Complex is bitpacked into one 64-bit GPR. + *offset = curr_offset + slot * 2; + let unit = Reg { kind: RegKind::Float, size: component.size() }; + let cast_target = CastTarget::from(Uniform::new(unit, size)); + arg.cast_to(cast_target); + return; + } + + // Otherwise pack it into GPRs (or the stack) like an integer of the same size. + arg.cast_to_and_pad_i32(Uniform::new(Reg::i64(), size), pad_i32); + } + Numeric::Float(Float::F128) => { + // Complex is passed in 4 FPRs, but aligned to 16 so may need padding. + let reg = Reg { kind: RegKind::Float, size: arg.layout.field(cx, 0).size }; + arg.cast_to_and_pad_i32(CastTarget::pair(reg, reg), pad_i32); + } + Numeric::Int(Integer::I8 | Integer::I16 | Integer::I32, _) => { + // Cast Complex into i16, Complex to i32, etc. + let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size }); + // The inreg attribute makes the bits land in the right (upper) bits on BE targets. + arg.cast_to(cast_target.with_attrs(ArgAttribute::InReg.into())); + } + Numeric::Int(Integer::I64 | Integer::I128, _) => { + // Complex and Complex are passed as 2 separate arguments. + let cast_target = CastTarget::from(Reg { kind: RegKind::Integer, size }); + arg.cast_to(cast_target); + } + } } else { match arg.layout.fields { FieldsShape::Primitive => unreachable!(), diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index edc23b6c50b45..487de8f54ee62 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -733,17 +733,17 @@ impl<'a, Ty> FnAbi<'a, Ty> { let spec = cx.target_spec(); match &spec.arch { Arch::X86 => { - let (flavor, regparm) = match abi { + let flavor = match abi { ExternAbi::Fastcall { .. } | ExternAbi::Vectorcall { .. } => { - (x86::Flavor::FastcallOrVectorcall, None) + x86::Flavor::FastcallOrVectorcall } ExternAbi::C { .. } | ExternAbi::Cdecl { .. } | ExternAbi::Stdcall { .. } => { - (x86::Flavor::General, cx.x86_abi_opt().regparm) + x86::Flavor::General { regparam: cx.x86_abi_opt().regparm } } - _ => (x86::Flavor::General, None), + _ => x86::Flavor::General { regparam: None }, }; let reg_struct_return = cx.x86_abi_opt().reg_struct_return; - let opts = x86::X86Options { flavor, regparm, reg_struct_return }; + let opts = x86::X86Options { flavor, reg_struct_return }; if spec.is_like_msvc { x86_win32::compute_abi_info(cx, self, opts); } else { diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 3476f41e3bc75..efe88bff6504c 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -2,7 +2,7 @@ use rustc_abi::{ AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout, }; -use crate::callconv::{ArgAttribute, FnAbi, PassMode, TyAbiInterface}; +use crate::callconv::{ArgAbi, ArgAttribute, FnAbi, PassMode, TyAbiInterface}; use crate::spec::{HasTargetSpec, RustcAbi}; /// Is this a struct with a single float field? @@ -37,65 +37,135 @@ where } } -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub(crate) enum Flavor { - General, + General { regparam: Option }, FastcallOrVectorcall, } +#[derive(Clone, Copy)] pub(crate) struct X86Options { pub flavor: Flavor, - pub regparm: Option, pub reg_struct_return: bool, } -pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) +fn classify_ret<'a, Ty, C>(cx: &C, opts: X86Options, ret: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - if !fn_abi.ret.is_ignore() { - if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() { - // Returning a structure. Most often, this will use - // a hidden first argument. On some platforms, though, - // small structs are returned as integers. - // - // Some links: - // https://www.angelcode.com/dev/callconv/callconv.html - // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp - let t = cx.target_spec(); - if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) { - // `_Complex _Float16` is returned as `<2 x half>`. - let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) }; - fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size }); - } else if t.abi_return_struct_as_int - || opts.reg_struct_return - || fn_abi.ret.layout.is_complex_number(cx) - { - // According to Clang, everyone but MSVC returns single-element - // float aggregates directly in a floating-point register. - if is_single_fp_element(fn_abi.ret.layout, cx) { - match fn_abi.ret.layout.size.bytes() { - 2 => fn_abi.ret.cast_to(Reg::f16()), - 4 => fn_abi.ret.cast_to(Reg::f32()), - 8 => fn_abi.ret.cast_to(Reg::f64()), - _ => fn_abi.ret.make_indirect(), - } - } else { - match fn_abi.ret.layout.size.bytes() { - 1 => fn_abi.ret.cast_to(Reg::i8()), - 2 => fn_abi.ret.cast_to(Reg::i16()), - 4 => fn_abi.ret.cast_to(Reg::i32()), - 8 => fn_abi.ret.cast_to(Reg::i64()), - _ => fn_abi.ret.make_indirect(), - } + if ret.layout.is_aggregate() && ret.layout.is_sized() { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // https://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = cx.target_spec(); + if let Some(Float::F16) = ret.layout.complex_float(cx) { + // `_Complex _Float16` is returned as `<2 x half>`. + let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) }; + ret.cast_to(Reg { kind, size: ret.layout.size }); + } else if t.abi_return_struct_as_int + || opts.reg_struct_return + || ret.layout.is_complex_number(cx) + { + // According to Clang, everyone but MSVC returns single-element + // float aggregates directly in a floating-point register. + if is_single_fp_element(ret.layout, cx) { + match ret.layout.size.bytes() { + 2 => ret.cast_to(Reg::f16()), + 4 => ret.cast_to(Reg::f32()), + 8 => ret.cast_to(Reg::f64()), + _ => ret.make_indirect(), } } else { - fn_abi.ret.make_indirect(); + match ret.layout.size.bytes() { + 1 => ret.cast_to(Reg::i8()), + 2 => ret.cast_to(Reg::i16()), + 4 => ret.cast_to(Reg::i32()), + 8 => ret.cast_to(Reg::i64()), + _ => ret.make_indirect(), + } } } else { - fn_abi.ret.extend_integer_width_to(32); + ret.make_indirect(); } + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + + if arg.layout.is_aggregate() { + // We need to compute the alignment of the `byval` argument. The rules can be found in + // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized + // here, they are: + // + // 1. If the natural alignment of the type is <= 4, the alignment is 4. + // + // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. + // This doesn't matter here because we only pass aggregates via `byval`, not vectors. + // + // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector + // type is 16. + // + // 4. If none of these conditions are true, the alignment is 4. + + fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match layout.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false, + BackendRepr::SimdVector { .. } => true, + BackendRepr::Memory { .. } => { + for i in 0..layout.fields.count() { + if contains_vector(cx, layout.field(cx, i)) { + return true; + } + } + false + } + BackendRepr::SimdScalableVector { .. } => { + panic!("scalable vectors are unsupported") + } + } + } + + let byval_align = if arg.layout.align.abi < align_4 { + // (1.) + align_4 + } else if t.is_like_darwin && contains_vector(cx, arg.layout) { + // (3.) + align_16 + } else { + // (4.) + align_4 + }; + + arg.pass_by_stack_offset(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } +} + +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + classify_ret(cx, opts, &mut fn_abi.ret); } for arg in fn_abi.args.iter_mut() { @@ -108,61 +178,7 @@ where continue; } - let t = cx.target_spec(); - let align_4 = Align::from_bytes(4).unwrap(); - let align_16 = Align::from_bytes(16).unwrap(); - - if arg.layout.is_aggregate() { - // We need to compute the alignment of the `byval` argument. The rules can be found in - // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized - // here, they are: - // - // 1. If the natural alignment of the type is <= 4, the alignment is 4. - // - // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. - // This doesn't matter here because we only pass aggregates via `byval`, not vectors. - // - // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector - // type is 16. - // - // 4. If none of these conditions are true, the alignment is 4. - - fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool - where - Ty: TyAbiInterface<'a, C> + Copy, - { - match layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false, - BackendRepr::SimdVector { .. } => true, - BackendRepr::Memory { .. } => { - for i in 0..layout.fields.count() { - if contains_vector(cx, layout.field(cx, i)) { - return true; - } - } - false - } - BackendRepr::SimdScalableVector { .. } => { - panic!("scalable vectors are unsupported") - } - } - } - - let byval_align = if arg.layout.align.abi < align_4 { - // (1.) - align_4 - } else if t.is_like_darwin && contains_vector(cx, arg.layout) { - // (3.) - align_16 - } else { - // (4.) - align_4 - }; - - arg.pass_by_stack_offset(Some(byval_align)); - } else { - arg.extend_integer_width_to(32); - } + classify_arg(cx, arg); } fill_inregs(cx, fn_abi, opts, false); @@ -176,9 +192,6 @@ pub(crate) fn fill_inregs<'a, Ty, C>( ) where Ty: TyAbiInterface<'a, C> + Copy, { - if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) { - return; - } // Mark arguments as InReg like clang does it, // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. @@ -188,8 +201,19 @@ pub(crate) fn fill_inregs<'a, Ty, C>( // IsSoftFloatABI is only set to true on ARM platforms, // which in turn can't be x86? - // 2 for fastcall/vectorcall, regparm limited by 3 otherwise - let mut free_regs = opts.regparm.unwrap_or(2).into(); + // The number of registers available for argument passing. + // + // An `extern "fastcall"` and `extern "vectorcall"` function always have 2 registers available. + // Otherwise the `regparam` count (in the range 0..=3) determines the number of available + // registers. If unspecified, no registers are used for argument passing. + let mut free_regs = match opts.flavor { + Flavor::FastcallOrVectorcall => 2, + Flavor::General { regparam } => u64::from(regparam.unwrap_or(0)), + }; + + if free_regs == 0 { + return; + } // For types generating PassMode::Cast, InRegs will not be set. // Maybe, this is a FIXME diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 5ab2834807d67..57e997f45d4c5 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -131,17 +131,16 @@ where } fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option { - if *i >= cls.len() { + let Some(Some(class)) = cls.get(*i) else { return None; - } + }; - match cls[*i] { - None => None, - Some(Class::Int) => { + match class { + Class::Int => { *i += 1; Some(if size.bytes() < 8 { Reg { kind: RegKind::Integer, size } } else { Reg::i64() }) } - Some(Class::Sse) => { + Class::Sse => { let vec_len = 1 + cls[*i + 1..].iter().take_while(|&&c| c == Some(Class::SseUp)).count(); *i += vec_len; @@ -154,7 +153,7 @@ fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option unreachable!("reg_component: unhandled class {:?}", c), + c => unreachable!("reg_component: unhandled class {:?}", c), } } diff --git a/compiler/rustc_trait_selection/src/diagnostics.rs b/compiler/rustc_trait_selection/src/diagnostics.rs index 90f6faaad1dc1..d673b99d00d05 100644 --- a/compiler/rustc_trait_selection/src/diagnostics.rs +++ b/compiler/rustc_trait_selection/src/diagnostics.rs @@ -1166,7 +1166,7 @@ impl<'tcx> ActualImplExplNotes<'tcx> { pub(crate) struct TraitPlaceholderMismatch<'tcx> { #[primary_span] pub span: Span, - #[label("doesn't satisfy where-clause")] + #[label("unsatisfied where-clause on `{$def_id}`")] pub satisfy_span: Option, #[label("due to a where-clause on `{$def_id}`...")] pub where_span: Option, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index be5c2b3c96915..390e21e34ef4c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -255,15 +255,43 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ) -> Diag<'tcx> { let span = cause.span; + let mut code = cause.code(); + loop { + match code { + ObligationCauseCode::MatchImpl(inner_cause, _) => { + code = inner_cause.code(); + } + ObligationCauseCode::ImplDerived(derived) => { + code = &derived.derived.parent_code; + } + ObligationCauseCode::BuiltinDerived(derived) => { + code = &derived.parent_code; + } + ObligationCauseCode::WellFormedDerived(derived) => { + code = &derived.parent_code; + } + ObligationCauseCode::ImplDerivedHost(derived) => { + code = &derived.derived.parent_code; + } + ObligationCauseCode::BuiltinDerivedHost(derived) => { + code = &derived.parent_code; + } + _ => break, + } + } let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = if let ObligationCauseCode::WhereClause(def_id, span) - | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code() + | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *code && def_id != CRATE_DEF_ID.to_def_id() { ( true, Some(span), - Some(self.tcx().def_span(def_id)), + Some( + self.tcx() + .opt_item_ident(def_id) + .map_or_else(|| self.tcx().def_span(def_id), |n| n.span), + ), None, self.tcx().def_path_str(def_id), ) @@ -356,6 +384,17 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let mut current_code = cause.code(); let mut coroutine_def_id = None; + if cause.body_def_id != CRATE_DEF_ID { + self.cx.note_obligation_cause_code( + cause.body_def_id, + &mut err, + actual_trait_ref, + self.tcx().param_env(cause.body_def_id), + cause.code(), + &mut vec![], + &mut Default::default(), + ); + } loop { match current_code { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index e708900aad487..d356a62200cfd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -294,7 +294,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); } - SubregionOrigin::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => { RegionOriginNote::Plain { span, msg: msg!("...so that the where clause holds") } .add_to_diag(err); } @@ -551,7 +551,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err } - SubregionOrigin::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span, _) => { let instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 47d2b7a8c98d5..9219c709eee83 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3832,7 +3832,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - pub(super) fn note_obligation_cause_code( + pub(crate) fn note_obligation_cause_code( &self, body_def_id: LocalDefId, err: &mut Diag<'_>, @@ -3903,7 +3903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::Misc | ObligationCauseCode::WellFormed(..) - | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) @@ -4418,6 +4417,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } + ObligationCauseCode::MatchImpl(ref cause, _) => { + self.note_obligation_cause_code_inner( + body_def_id, + err, + predicate, + param_env, + &cause.code(), + obligated_types, + seen_requirements, + closure_capture_ty, + ); + } ObligationCauseCode::BuiltinDerived(ref data) => { let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index d30421a762ea9..5ccd7ff7ef55b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -510,7 +510,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { match (child_mode, nested_goal.source()) { ( ChildMode::Trait(_) | ChildMode::Host(_), - GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), + GoalSource::Misc | GoalSource::Normalization, ) => { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index b4ab3b9729fd3..2fcb7f1741f5a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -109,7 +109,7 @@ fn relate_mir_and_user_args<'tcx>( let cause = ObligationCause::new( span, CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(clause_span), + ObligationCauseCode::AscribeUserTypeProvePredicate(clause_span, def_id), ); let instantiated_clause = ocx.normalize(&cause, param_env, instantiated_clause); diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index c6d88bb6603de..5d1472d5941f2 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -16,7 +16,6 @@ use tracing::debug; use crate::inherent::*; use crate::lang_items::SolverTraitLangItem; use crate::region_constraint::RegionConstraint; -use crate::search_graph::PathKind; use crate::{ self as ty, Canonical, CanonicalVarValues, CantBeErased, Const, ConstVid, FloatVid, GenericArgKind, InferConst, IntVid, Interner, TermKind, TyVid, TypingMode, Upcast, @@ -411,22 +410,15 @@ impl Goal { /// Why a specific goal has to be proven. /// -/// This is necessary as we treat nested goals different depending on -/// their source. This is used to decide whether a cycle is coinductive. -/// See the documentation of `EvalCtxt::step_kind_for_source` for more details -/// about this. +/// This is used by proof tree visitors, especially for diagnostics purposes. /// -/// It is also used by proof tree visitors, e.g. for diagnostics purposes. +/// FIXME(-Znext-solver=coinductive): This will also matter in the future when +/// deciding whether a step in a cycle is coinductive. We're currently still +/// matching the old solver behavior here for now, so the `GoalSource` is ignored. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum GoalSource { Misc, - /// A nested goal required to prove that types are equal/subtypes. - /// This is always an unproductive step. - /// - /// This is also used for all `NormalizesTo` goals as we they are used - /// to relate types in `AliasRelate`. - TypeRelating, /// We're proving a where-bound of an impl. ImplWhereBound, /// Const conditions that need to hold for `[const]` alias bounds to hold. @@ -438,12 +430,8 @@ pub enum GoalSource { /// 2. for rigid projections's trait goal, /// 3. for GAT where clauses. AliasWellFormed, - /// In case normalizing aliases in nested goals cycles, eagerly normalizing these - /// aliases in the context of the parent may incorrectly change the cycle kind. - /// Normalizing aliases in goals therefore tracks the original path kind for this - /// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more - /// details. - NormalizeGoal(PathKind), + /// Normalizing happens in the current context and is unproductive by itself. + Normalization, } #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal)] diff --git a/library/alloc/src/rcs/rc.rs b/library/alloc/src/rcs/rc.rs index 8cca09d1d4a8c..04e08c47fb587 100644 --- a/library/alloc/src/rcs/rc.rs +++ b/library/alloc/src/rcs/rc.rs @@ -1985,10 +1985,55 @@ impl Rc { unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; } - /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to - /// this allocation. + /// Determine whether this is the unique reference to the underlying data. + /// + /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to the same allocation; + /// returns `false` otherwise. + /// + /// If this function returns `true`, it is safe to call [`get_mut_unchecked`] + /// immediately afterward. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_is_unique)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert!(Rc::is_unique(&x)); + /// + /// let y = Rc::clone(&x); + /// assert!(!Rc::is_unique(&x)); + /// drop(y); + /// + /// // Weak references also count, because they could be upgraded at any time. + /// let z = Rc::downgrade(&x); + /// assert!(!Rc::is_unique(&x)); + /// ``` + /// + /// # Pointer invalidation + /// + /// This function will always return the same value as `Rc::get_mut(rc).is_some()`. However, + /// unlike that operation it does not produce any mutable references to the underlying data, + /// meaning no pointers to the data inside the `Rc` are invalidated by the call. Thus, the + /// following code is valid, even though it would be UB if it used `Rc::get_mut`: + /// + /// ``` + /// #![feature(arc_is_unique)] + /// + /// use std::rc::Rc; + /// + /// let rc = Rc::new(5); + /// let pointer: *const i32 = &*rc; + /// assert!(Rc::is_unique(&rc)); + /// assert_eq!(unsafe { *pointer }, 5); + /// ``` + /// + /// [`get_mut_unchecked`]: Self::get_mut_unchecked #[inline] - fn is_unique(this: &Self) -> bool { + #[unstable(feature = "arc_is_unique", issue = "138938")] + pub fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index 97629be8ec6ef..9a70ea74345be 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -189,7 +189,7 @@ const _: () = (); /// /// For more information, see the Reference on [the `cfg` attribute]. /// -/// [`cfg_attr`]: ../reference/conditional-compilation.html#the-cfg_attr-attribute +/// [`cfg_attr`]: ./attribute.cfg_attr.html /// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute /// [`if`]: ./keyword.if.html const _: () = (); @@ -707,3 +707,48 @@ const _: () = (); /// [Clippy]: https://github.com/rust-lang/rust-clippy /// [the `automatically_derived` attribute]: ../reference/attributes/derive.html#the-automatically_derived-attribute const _: () = (); + +#[doc(attribute = "cfg_attr")] +// +/// The `cfg_attr` attribute is used to conditionally apply one or more attributes to an item. +/// +/// Example: +/// +/// ```rust +/// // The struct derives `Debug` when the `debug_impls` feature is enabled. +/// #[cfg_attr(feature = "debug_impls", derive(Debug))] +/// struct X; +/// ``` +/// +/// You can apply multiple attributes by separating them with commas: +/// +/// ```rust +/// #[cfg_attr(feature = "nightly", allow(dead_code), deny(unused_variables))] +/// // This function only gets the `allow(dead_code)` and `deny(unused_variables)` attributes when +/// // `feature = "nightly"` is active. +/// fn nightly_only_function() { +/// let x = 42; +/// } +/// ``` +/// +/// For complex conditions, you can combine `all(...)`, `any(...)`, and `not(...)`. +/// +/// * `all`: True if all given predicates are true. +/// * `any`: True if at least one of the given predicates is true. +/// * `not`: True if the predicate is false. +/// +/// ```rust +/// #[cfg_attr( +/// all(feature = "system", feature = "disk"), +/// doc = "These docs only show up if both `system`, and `disk` are enabled.", +/// )] +/// mod my_module { +/// // ... +/// } +/// ``` +/// +/// For more information, see the Reference on [the `cfg_attr` attribute]. +/// +/// [`cfg`]: ./attribute.cfg.html +/// [the `cfg_attr` attribute]: ../reference/conditional-compilation.html#the-cfg_attr-attribute +const _: () = (); diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index db05d7fdc5087..e53e4df1ea43d 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1544,9 +1544,10 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] - #[must_use = "this returns the clamped value and does not modify the original"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f128) -> f128 { + pub const fn clamp_magnitude(self, limit: f128) -> f128 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 273ef3688ca5f..4ad41bd6cfa4b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1530,9 +1530,10 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] - #[must_use = "this returns the clamped value and does not modify the original"] + #[rustc_const_unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f16) -> f16 { + pub const fn clamp_magnitude(self, limit: f16) -> f16 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d3dea38dc2fcf..2dc3ddf31cac5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1699,11 +1699,11 @@ impl f32 { /// assert_eq!(2.0f32.clamp_magnitude(3.0), 2.0); /// assert_eq!((-2.0f32).clamp_magnitude(3.0), -2.0); /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f32) -> f32 { + pub const fn clamp_magnitude(self, limit: f32) -> f32 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7c5082749cd11..cd3cfe1bd4c60 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1677,11 +1677,11 @@ impl f64 { /// assert_eq!(2.0f64.clamp_magnitude(3.0), 2.0); /// assert_eq!((-2.0f64).clamp_magnitude(3.0), -2.0); /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + #[must_use = "method returns a new number and does not mutate the original value"] #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] - pub fn clamp_magnitude(self, limit: f64) -> f64 { + pub const fn clamp_magnitude(self, limit: f64) -> f64 { assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4cbd012e0021b..058c0229aa530 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3961,14 +3961,15 @@ macro_rules! int_impl { /// ``` /// #![feature(clamp_magnitude)] #[doc = concat!("assert_eq!(120", stringify!($SelfT), ".clamp_magnitude(100), 100);")] - #[doc = concat!("assert_eq!(-120", stringify!($SelfT), ".clamp_magnitude(100), -100);")] + #[doc = concat!("assert_eq!((-120", stringify!($SelfT), ").clamp_magnitude(100), -100);")] #[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")] - #[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")] + #[doc = concat!("assert_eq!((-80", stringify!($SelfT), ").clamp_magnitude(100), -80);")] /// ``` - #[must_use = "this returns the clamped value and does not modify the original"] - #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] - pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self { + #[must_use = "method returns a new number and does not mutate the original value"] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + pub const fn clamp_magnitude(self, limit: $UnsignedT) -> Self { if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) { self.clamp(-limit, limit) } else { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 355e9a3c59da7..c97e6f4c45395 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -2612,6 +2612,50 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { NonZero::new_unchecked(self.get().cast_unsigned()) } } + /// Clamps this number to a symmetric range centred around zero. + /// + /// The method clamps the number's magnitude (absolute value) to be at most `limit`. + /// + /// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more + /// explicit about the intent. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_magnitude)] + /// # use std::num::NonZero; + /// # + #[doc = concat!("let limit = NonZero::<", stringify!($Uint), ">::new(100).unwrap();")] + /// + /// assert_eq!( + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(120).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(100).unwrap(),")] + /// ); + /// + /// assert_eq!( + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-120).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-100).unwrap(),")] + /// ); + /// + /// assert_eq!( + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(80).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(80).unwrap(),")] + /// ); + /// + /// assert_eq!( + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-80).unwrap().clamp_magnitude(limit),")] + #[doc = concat!(" NonZero::<", stringify!($Int), ">::new(-80).unwrap(),")] + /// ); + /// ``` + #[inline] + #[must_use = "method returns a new number and does not mutate the original value"] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + #[unstable(feature = "clamp_magnitude", issue = "148519")] + pub const fn clamp_magnitude(self, limit: NonZero<$Uint>) -> Self { + // SAFETY: a non-zero value clamped to the magnitude of a non-zero value is still non-zero. + unsafe { Self::new_unchecked(self.get().clamp_magnitude(limit.get())) } + } + }; } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 1334b551217a8..fc2430a10edb4 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(cfg_overflow_checks)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] +#![feature(clamp_magnitude)] #![feature(clamp_to)] #![feature(clone_to_uninit)] #![feature(cmp_minmax)] diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs index 0f96e55f6914e..fdb605780a2c6 100644 --- a/library/coretests/tests/num/clamp_magnitude.rs +++ b/library/coretests/tests/num/clamp_magnitude.rs @@ -1,3 +1,7 @@ +use core::num::*; + +use crate::num::assert_biteq; + macro_rules! check_int_clamp { ($t:ty, $ut:ty) => { let min = <$t>::MIN; @@ -32,6 +36,16 @@ macro_rules! check_int_clamp { // Limit larger than type max (uN > iN::MAX) assert_eq!(max.clamp_magnitude(max_u), max); assert_eq!(min.clamp_magnitude(max_u), min); + + // Const clamping + const C1: $t = (100 as $t).clamp_magnitude(50); + assert_eq!(C1, 50); + const C2: $t = (-100 as $t).clamp_magnitude(50); + assert_eq!(C2, -50); + const C3: $t = (30 as $t).clamp_magnitude(50); + assert_eq!(C3, 30); + const C4: $t = (-30 as $t).clamp_magnitude(50); + assert_eq!(C4, -30); }; } @@ -65,8 +79,81 @@ fn test_clamp_magnitude_isize() { check_int_clamp!(isize, usize); } +macro_rules! check_nonzero_clamp { + ($t:ty, $ut:ty) => { + let min = <$t>::MIN; + let max = <$t>::MAX; + let max_u = <$ut>::MAX; + + // Basic clamping + let lim = <$ut>::new(50).unwrap(); + assert_eq!(<$t>::new(100).unwrap().clamp_magnitude(lim), <$t>::new(50).unwrap()); + assert_eq!(<$t>::new(-100).unwrap().clamp_magnitude(lim), <$t>::new(-50).unwrap()); + assert_eq!(<$t>::new(30).unwrap().clamp_magnitude(lim), <$t>::new(30).unwrap()); + assert_eq!(<$t>::new(-30).unwrap().clamp_magnitude(lim), <$t>::new(-30).unwrap()); + + // Exact boundary + assert_eq!(<$t>::new(50).unwrap().clamp_magnitude(lim), <$t>::new(50).unwrap()); + assert_eq!(<$t>::new(-50).unwrap().clamp_magnitude(lim), <$t>::new(-50).unwrap()); + + // MIN/MAX values + // Symmetric range [-MAX, MAX] + assert_eq!(max.clamp_magnitude(max.try_into().unwrap()), max); + assert_eq!(min.clamp_magnitude(max.try_into().unwrap()), -max); + + // Full range (limit covers MIN) + let min_abs = min.unsigned_abs(); + assert_eq!(min.clamp_magnitude(min_abs), min); + + // Limit larger than type max (uN > iN::MAX) + assert_eq!(max.clamp_magnitude(max_u), max); + assert_eq!(min.clamp_magnitude(max_u), min); + + // Const clamping + const LIM: $ut = <$ut>::new(50).unwrap(); + const C1: $t = <$t>::new(100).unwrap().clamp_magnitude(LIM); + assert_eq!(C1, <$t>::new(50).unwrap()); + const C2: $t = <$t>::new(-100).unwrap().clamp_magnitude(LIM); + assert_eq!(C2, <$t>::new(-50).unwrap()); + const C3: $t = <$t>::new(30).unwrap().clamp_magnitude(LIM); + assert_eq!(C3, <$t>::new(30).unwrap()); + const C4: $t = <$t>::new(-30).unwrap().clamp_magnitude(LIM); + assert_eq!(C4, <$t>::new(-30).unwrap()); + }; +} + +#[test] +fn test_clamp_magnitude_nonzero_i8() { + check_nonzero_clamp!(NonZeroI8, NonZeroU8); +} + +#[test] +fn test_clamp_magnitude_nonzero_i16() { + check_nonzero_clamp!(NonZeroI16, NonZeroU16); +} + +#[test] +fn test_clamp_magnitude_nonzero_i32() { + check_nonzero_clamp!(NonZeroI32, NonZeroU32); +} + +#[test] +fn test_clamp_magnitude_nonzero_i64() { + check_nonzero_clamp!(NonZeroI64, NonZeroU64); +} + +#[test] +fn test_clamp_magnitude_nonzero_i128() { + check_nonzero_clamp!(NonZeroI128, NonZeroU128); +} + +#[test] +fn test_clamp_magnitude_nonzero_isize() { + check_nonzero_clamp!(NonZeroIsize, NonZeroUsize); +} + macro_rules! check_float_clamp { - ($t:ty) => { + ($t:ty, $huge: expr) => { // Basic clamping assert_eq!((5.0 as $t).clamp_magnitude(3.0), 3.0); assert_eq!((-5.0 as $t).clamp_magnitude(3.0), -3.0); @@ -78,10 +165,13 @@ macro_rules! check_float_clamp { assert_eq!((-3.0 as $t).clamp_magnitude(3.0), -3.0); // Zero cases - assert_eq!((0.0 as $t).clamp_magnitude(1.0), 0.0); - assert_eq!((-0.0 as $t).clamp_magnitude(1.0), 0.0); - assert_eq!((5.0 as $t).clamp_magnitude(0.0), 0.0); - assert_eq!((-5.0 as $t).clamp_magnitude(0.0), 0.0); + type Float = $t; + assert_biteq!((0.0 as $t).clamp_magnitude(1.0), 0.0); + assert_biteq!((-0.0 as $t).clamp_magnitude(1.0), -0.0); + assert_biteq!((5.0 as $t).clamp_magnitude(0.0), 0.0); + assert_biteq!((-5.0 as $t).clamp_magnitude(0.0), -0.0); + assert_biteq!((5.0 as $t).clamp_magnitude(-0.0), 0.0); + assert_biteq!((-5.0 as $t).clamp_magnitude(-0.0), -0.0); // Special values - Infinity let inf = <$t>::INFINITY; @@ -98,42 +188,95 @@ macro_rules! check_float_clamp { let max = <$t>::MAX; let min = <$t>::MIN; // Large limit - let huge = 1e30; - assert_eq!(max.clamp_magnitude(huge), huge); - assert_eq!(min.clamp_magnitude(huge), -huge); + assert_eq!(max.clamp_magnitude($huge), $huge); + assert_eq!(min.clamp_magnitude($huge), -$huge); + + // NaN + let nan = <$t>::NAN; + assert!(nan.clamp_magnitude(1.0).is_nan()); + + // Const clamping + const C1: $t = (5.0 as $t).clamp_magnitude(3.0); + assert_eq!(C1, 3.0); + const C2: $t = (-5.0 as $t).clamp_magnitude(3.0); + assert_eq!(C2, -3.0); + const C3: $t = (2.0 as $t).clamp_magnitude(3.0); + assert_eq!(C3, 2.0); + const C4: $t = (-2.0 as $t).clamp_magnitude(3.0); + assert_eq!(C4, -2.0); }; } +#[test] +#[cfg(target_has_reliable_f16)] +fn test_clamp_magnitude_f16() { + check_float_clamp!(f16, 1e3); +} + #[test] fn test_clamp_magnitude_f32() { - check_float_clamp!(f32); + check_float_clamp!(f32, 1e30); } #[test] fn test_clamp_magnitude_f64() { - check_float_clamp!(f64); + check_float_clamp!(f64, 1e300); +} + +#[test] +#[cfg(target_has_reliable_f128)] +fn test_clamp_magnitude_f128() { + check_float_clamp!(f128, 1e3000); } #[test] -#[should_panic(expected = "limit must be non-negative")] +#[cfg(target_has_reliable_f16)] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f16_panic_negative_limit() { + let _ = 1.0f16.clamp_magnitude(-1.0); +} + +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f32_panic_negative_limit() { let _ = 1.0f32.clamp_magnitude(-1.0); } #[test] -#[should_panic(expected = "limit must be non-negative")] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f64_panic_negative_limit() { let _ = 1.0f64.clamp_magnitude(-1.0); } #[test] -#[should_panic] +#[cfg(target_has_reliable_f128)] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f128_panic_negative_limit() { + let _ = 1.0f128.clamp_magnitude(-1.0); +} + +#[test] +#[cfg(target_has_reliable_f16)] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f16_panic_nan_limit() { + let _ = 1.0f16.clamp_magnitude(f16::NAN); +} + +#[test] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f32_panic_nan_limit() { let _ = 1.0f32.clamp_magnitude(f32::NAN); } #[test] -#[should_panic] +#[should_panic(expected = "limit must be non-negative and not NaN")] fn test_clamp_magnitude_f64_panic_nan_limit() { let _ = 1.0f64.clamp_magnitude(f64::NAN); } + +#[test] +#[cfg(target_has_reliable_f128)] +#[should_panic(expected = "limit must be non-negative and not NaN")] +fn test_clamp_magnitude_f128_panic_nan_limit() { + let _ = 1.0f128.clamp_magnitude(f128::NAN); +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index b1c3001790f07..f892734d8b95d 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -24,6 +24,7 @@ mod u8; mod bignum; mod carryless_mul; mod cast; +mod clamp_magnitude; mod complex; mod const_from; mod dec2flt; diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index dd6e4a690e326..0520da62ffae9 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -87,7 +87,7 @@ enum AddressKind<'a> { /// return /// } /// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// ``` #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] @@ -188,7 +188,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.is_unnamed(), false); /// Ok(()) /// } @@ -202,7 +202,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.is_unnamed(), true); /// Ok(()) /// } @@ -226,7 +226,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); /// Ok(()) /// } @@ -240,7 +240,7 @@ impl SocketAddr { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixListener::local_addr` should not fail"); /// assert_eq!(addr.as_pathname(), None); /// Ok(()) /// } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index e03ecd7eed9ea..f80a3a887c54d 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -273,7 +273,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// let sock_copy = sock.try_clone().expect("`UnixDatagram::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -292,7 +292,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// let addr = sock.local_addr().expect("`UnixDatagram::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -317,7 +317,7 @@ impl UnixDatagram { /// let sock = UnixDatagram::unbound()?; /// sock.connect("/path/to/the/socket")?; /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// let addr = sock.peer_addr().expect("`UnixDatagram::peer_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -390,7 +390,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::bind("/path/to/the/socket")?; /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// sock.recv(buf.as_mut_slice()).expect("`UnixDatagram::recv` should not fail"); /// Ok(()) /// } /// ``` @@ -523,7 +523,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("`UnixDatagram::send_to` should not fail"); /// Ok(()) /// } /// ``` @@ -561,7 +561,7 @@ impl UnixDatagram { /// let addr = bound.local_addr()?; /// /// let sock = UnixDatagram::unbound()?; - /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); + /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("`UnixDatagram::send_to_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -595,8 +595,8 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// sock.connect("/some/sock").expect("`UnixDatagram::connect` should not fail"); + /// sock.send(b"omelette au fromage").expect("`UnixDatagram` is not connected"); /// Ok(()) /// } /// ``` @@ -638,7 +638,7 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock") - /// .expect("send_vectored_with_ancillary_to function failed"); + /// .expect("`UnixDatagram::send_vectored_with_ancillary_to` should not fail"); /// Ok(()) /// } /// ``` @@ -686,7 +686,7 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); /// sock.send_vectored_with_ancillary(bufs, &mut ancillary) - /// .expect("send_vectored_with_ancillary function failed"); + /// .expect("`UnixDatagram::send_vectored_with_ancillary` should not fail"); /// Ok(()) /// } /// ``` @@ -719,7 +719,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); + /// .expect("`UnixDatagram::set_read_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -765,7 +765,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); + /// .expect("`UnixDatagram::set_write_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -804,7 +804,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); + /// .expect("`UnixDatagram::set_read_timeout` should not fail"); /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -826,7 +826,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); + /// .expect("`UnixDatagram::set_write_timeout` should not fail"); /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -846,7 +846,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// sock.set_nonblocking(true).expect("`UnixDatagram::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` @@ -914,7 +914,7 @@ impl UnixDatagram { /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// sock.shutdown(Shutdown::Both).expect("`UnixDatagram::shutdown` should not fail"); /// Ok(()) /// } /// ``` @@ -941,7 +941,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let socket = UnixDatagram::bind("/tmp/sock")?; /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); + /// let len = socket.peek(&mut buf).expect("`UnixDatagram::peek` should not fail"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index b7f8d25a85ae5..793e2378e716d 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -200,7 +200,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// let listener_copy = listener.try_clone().expect("`UnixListener::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -219,7 +219,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// let addr = listener.local_addr().expect("`UnixListener::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -244,7 +244,7 @@ impl UnixListener { /// /// fn main() -> std::io::Result<()> { /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// listener.set_nonblocking(true).expect("`UnixListener::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 31a908dfe187e..dba49d0406bf1 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -199,7 +199,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// let sock_copy = socket.try_clone().expect("`UnixStream::try_clone` should not fail"); /// Ok(()) /// } /// ``` @@ -218,7 +218,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// let addr = socket.local_addr().expect("`UnixStream::local_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -237,7 +237,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// let addr = socket.peer_addr().expect("`UnixStream::peer_addr` should not fail"); /// Ok(()) /// } /// ``` @@ -257,7 +257,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// let peer_cred = socket.peer_cred().expect("`UnixStream::peer_cred` should not fail"); /// Ok(()) /// } /// ``` @@ -295,7 +295,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("`UnixStream::set_read_timeout` should not fail"); /// Ok(()) /// } /// ``` @@ -340,7 +340,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); + /// .expect("`UnixStream::connect` should not fail"); /// Ok(()) /// } /// ``` @@ -378,7 +378,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("`UnixStream::set_read_timeout` should not fail"); /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -400,7 +400,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); + /// .expect("`UnixStream::set_write_timeout` should not fail"); /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); /// Ok(()) /// } @@ -420,7 +420,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// socket.set_nonblocking(true).expect("`UnixStream::set_nonblocking` should not fail"); /// Ok(()) /// } /// ``` @@ -493,7 +493,7 @@ impl UnixStream { /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// socket.shutdown(Shutdown::Both).expect("`UnixStream::shutdown` should not fail"); /// Ok(()) /// } /// ``` @@ -520,7 +520,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); + /// let len = socket.peek(&mut buf).expect("`UnixStream::peek` should not fail"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 93b05b9859d28..ca5c28dcd88bd 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -47,9 +47,6 @@ cfg_select! { mod vexos; use vexos as imp; } - target_vendor = "apple" => { - mod darwin; - } _ => { mod unsupported; use unsupported as imp; diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 359deab6f6d7d..54c716959e154 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -50,12 +50,12 @@ fn main() -> Result<()> { let old = fs::read_to_string(&path)?; let mut new = comply(&old); if cli.reflow_harder { - new = lengthen_lines(&new, cli.line_length_limit) + new = reformat(&new, cli.line_length_limit) } if new == old { compliant.push(path.clone()); } else if cli.overwrite { - fs::write(&path, lengthen_lines(&new, cli.line_length_limit))?; + fs::write(&path, reformat(&new, cli.line_length_limit))?; made_compliant.push(path.clone()); } else { not_compliant.push(path.clone()); @@ -133,7 +133,8 @@ fn comply(content: &str) -> String { new_content.join("\n") + "\n" } -fn lengthen_lines(content: &str, limit: usize) -> String { +// This reformats lines, so that changes of "fn comply" look more pretty +fn reformat(content: &str, limit: usize) -> String { let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect(); let mut new_content = content.clone(); let mut new_n = 0; @@ -239,6 +240,8 @@ o? whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. The "; let expected = " # some. heading @@ -272,12 +275,15 @@ whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. +The "; assert_eq!(expected, comply(original)); } #[test] -fn test_lengthen_lines() { +fn test_reformat_lines() { let original = "\ do not split short sentences @@ -308,6 +314,18 @@ html comment closing handle the indented well +split on comma (filler), of +current line + + split on comma (filler), of + current line + +split on +comma (filler), of next line + + split on + comma (filler), of next line + [a target]: https://example.com [another target]: https://example.com "; @@ -339,10 +357,22 @@ html comment closing handle the indented well +split on comma (filler), +of current line + + split on comma (filler), + of current line + +split on comma (filler), +of next line + + split on comma (filler), + of next line + [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, lengthen_lines(original, 50)); + assert_eq!(expected, reformat(original, 30)); } #[test] @@ -351,48 +381,3 @@ fn should_pass() { let original = "if you see `input isn't interesting! verify interesting-ness test`."; assert_eq!(original, comply(original)); } - -#[test] -fn split_on_comma_of_current_line() { - let original = " -Each derived value has a dependency, on other values, which could themselves be either base or -derived. - - Each derived value has a dependency, on other values, which could themselves be either base or - derived. -"; - let expected = " -Each derived value has a dependency, on other values, -which could themselves be either base or derived. - - Each derived value has a dependency, on other values, - which could themselves be either base or derived. -"; - assert_eq!(expected, lengthen_lines(original, 100)) -} - -#[test] -fn split_on_comma_of_next_line() { - let original = " -Because of canonicalization of regions and -inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and - inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - let expected = " -Because of canonicalization of regions and inference variables, -encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and inference variables, - encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - assert_eq!(expected, lengthen_lines(original, 100)) -} - -#[test] -fn should_split() { - let original = "the queries that we do, as well as the **query DAG**. The"; - let expected = "the queries that we do, as well as the **query DAG**.\nThe\n"; - assert_eq!(expected, comply(original)); -} diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6b9ce9470f137..af092f4d3417d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -56fad885ebfb0447660870715da4dfa75deae93d +7d2cd0fbc092625ea371da704f15f80216d2220e diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 4572d001f12d3..4fe42ebffd574 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -15,8 +15,8 @@ See [bootstrap/README.md][bootstrap-internals] to read about bootstrap internals - Stage 3: the same-result test Compiling `rustc` is done in stages. -Here's a diagram, adapted from Jynn -Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, +Here's a diagram, +adapted from Jynn Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, with detailed explanations below. The `A`, `B`, `C`, and `D` show the ordering of the stages of bootstrapping. @@ -298,12 +298,12 @@ but `lib` will never be part of the search path. #### `-Z force-unstable-if-unmarked` -Since `lib/rustlib/` is part of the search path we have to be careful about -which crates are included in it. -In particular, all crates except for the -standard library are built with the flag `-Z force-unstable-if-unmarked`, -which means that you have to use `#![feature(rustc_private)]` in order to load it (as -opposed to the standard library, which is always available). +Since `lib/rustlib/` is part of the search path, +we have to be careful about which crates are included in it. +In particular, all crates, except for the standard library, +are built with the flag `-Z force-unstable-if-unmarked`, +meaning that you have to use `#![feature(rustc_private)]` in order to load it +(as opposed to the standard library, which is always available). The `-Z force-unstable-if-unmarked` flag has a variety of purposes to help enforce that the correct crates are marked as `unstable`. diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index 74e78aab145a1..2738782db9e48 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -5,7 +5,7 @@ Most of the kinds of `ty::Const` that exist have direct parallels to kinds of types that exist, for example `ConstKind::Param` is equivalent to `TyKind::Param`. The main interesting points here are: -- [`ConstKind::Unevaluated`], which is equivalent to `TyKind::Alias` and in the long term should be renamed (as well as introducing an `AliasConstKind` to parallel `ty::AliasKind`). +- [`ConstKind::Alias`], which is equivalent to `TyKind::Alias`. - [`ConstKind::Value`], which is the final value of a `ty::Const` after monomorphization. This is somewhat similar to fully concrete things like `TyKind::Str` or `TyKind::ADT`. @@ -27,7 +27,8 @@ struct Foo; type Alias = [u8; 1 + 1]; ``` -In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. The desugaring would look something like: +In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. +The desugaring would look something like: ```rust struct Foo; @@ -35,7 +36,7 @@ const ANON: usize = 1 + 1; type Alias = [u8; ANON]; ``` -Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Unevaluated`]). +Where the array length in `[u8; ANON]` isn't itself an anon const containing a usage of `ANON`, but a kind of "direct" usage of the `ANON` const item ([`ConstKind::Alias`]). Anon consts do not inherit any generic parameters of the item they are inside of: ```rust @@ -81,9 +82,11 @@ type Alias = [u8; ANON]; When we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too, and feed `type_of(ANON) -> usize`. This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. -After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Unevaluated` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_min_const_items` is enabled). +After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. +This is equivalent to how we would represent a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). -This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. +This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. +Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. ### Enforcing lack of generic parameters @@ -215,7 +218,7 @@ Proving `ConstArgHasType` goals is implemented by first computing the type of th A rough outline of how the type of a Const Argument may be computed: - [`ConstKind::Param(N)`][`ConstKind::Param`] can be looked up in the [`ParamEnv`] to find a `ConstArgHasType(N, ty)` clause - [`ConstKind::Value`] stores the type of the value inside itself so can trivially be accessed -- [`ConstKind::Unevaluated`] can have its type computed by calling the `type_of` query +- [`ConstKind::Alias`] can have its type computed by calling the `type_of` query - See the implementation of proving `ConstArgHasType` goals for more detailed information `ConstArgHasType` is *the* soundness critical way that we check Const Arguments have the correct type. @@ -238,11 +241,11 @@ what actually happens is a *type checking* error when type checking the anon con Looking at the above example, this corresponds to `[u8; ANON]` being a well formed type because `ANON` has type `usize`, but the *body* of `ANON` being illformed and resulting in a type checking error because `true` can't be returned from a const item of type `usize`. [ambig-unambig-ty-and-consts]: ./ambig-unambig-ty-and-consts.md -[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html -[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Infer -[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param -[`ConstKind::Unevaluated`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Unevaluated -[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Value +[`ConstKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html +[`ConstKind::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Infer +[`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Param +[`ConstKind::Alias`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Alias +[`ConstKind::Value`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/type.ConstKind.html#variant.Value [const_arg_has_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstArgHasType [`ParamEnv`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#impl-TyCtxt%3C'tcx%3E/method.generics_of diff --git a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md index 4f5bdaa1e6795..1cdc7c0929142 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/llvm-codegen.md @@ -1,13 +1,13 @@ # LLVM codegen -When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a -["debug record"][dbg_record] that is format-agnostic. +When Rust calls an LLVM `DIBuilder` function, +LLVM translates the given information to a ["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records -It is important to note that tags within the debug records are **always stored as DWARF tags**. If -the target calls for PDB debug info, during codegen the debug records will then be passed through +It is important to note that tags within the debug records are **always stored as DWARF tags**. +If the target calls for PDB debug info, during codegen, the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. [cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md index bcbe960034b02..5b80c42afc3de 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/testing.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -36,9 +36,8 @@ To help remedy this: # The `repr` directive > [!IMPORTANT] -> As of July 2026, this command is only supported by LLDB. GDB support is planned, but -> has not been implemented. It is unclear whether this directive will ever be suited for use with -> CDB. +> As of September 2026, this command is only supported for LLDB and GDB. +> It is unclear whether this directive will ever be suited for use with CDB. In short, `$DEBUGGER-repr` commands are desugared to: @@ -53,7 +52,7 @@ and runs special logic on them, testing against data stored in "Target groups" cover the set of targets where we cannot guarantee identical output. Those targets are defined by the - [`Target` enum in `common.py`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L54). + [`Target` enum in `common.py`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L54). As of Jul 2026, this list includes `non_windows`, `windows_gnu`, and `windows_msvc`. It is intentionally kept as short as possible, since each target is a new set of test data that must be updated when changes are made. @@ -66,7 +65,7 @@ invocation (e.g. `./x test tests/debuginfo/basic-types/main.rs --bless`). and if no errors occur, saves the data back to the target file (or creates a new file if necessary). The schema of the input data is defined by the classes in -[`common.py`](https://github.com/rust-lang/rust/blob/be3d26db984c6f96335faca1f254dc04873cb1c1/src/etc/lldb_batchmode/common.py). +[`common.py`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py). The top-level container is `TargetData`. This schema is identical for all debuggers. @@ -98,6 +97,13 @@ as well (e.g. if you are on a Windows machine, bless once for `x86_64-pc-windows ## Implementation +Many of the details of the implementation are shared between LLDB and GDB, +and live in `src/etc/debugger_tester/common.py`. +Notably, LLDB's batch execution features execute commands without waiting for breakpoints to be reached, +making it generally unsuited for our purposes. +As such, `debugger_tester/lldb/lldb_batchmode.py` simulates GDB's batchmode behavior by manually +invoking the test script's commands via `lldb.SBDebugger` and `lldb.SBCommandInterpreter` objects. + ### Ser/De `TargetData` is converted to a dictionary with `dataclasses.asdict`, and is serialized with Python's @@ -108,7 +114,7 @@ The current deserialization logic should be resilient to changes in the schema, but requires that all fields contain ONLY types that can be directly serialized/deserialized by `json.dumps`. The acceptable types are those that make up -[`common.JsonType`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L17) +[`common.JsonType`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L17) Since the serialization/deserialization is decoupled from the debugger logic, we can easily switch to an alternative format if we find a better alternative to json. @@ -117,11 +123,11 @@ The conversion logic from the debugger's internal representation to our schema c `from_$DEBUGGER.py`. Once imported, `common` automatically deserializes any existing input data and [stores it in the -global variable `INPUT_DATA`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L523). +global variable `INPUT_DATA`](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L601). This data is what we test against. > [!NOTE] -> Special care was taken to prevent `lldb_batchmode` from importing `common` unless a `repr` command +> Special care was taken to prevent `debugger_tester` from importing `common` unless a `repr` command > was actually processed. This saves us from reading/writing input data for tests that don't need > it. @@ -140,18 +146,27 @@ to help in diagnosing issues that may occur due to Python or the debugger changi ### Entry point and `--bless` -Upon encountering a `repr` pseudo-command, `lldb_batchmode.main` dispatches to -`check_$DEBUGGER.check()`. +* GDB: Upon import, the `repr` command is registered via the Python API in +[`debugger_tester/gdb/gdb_commands.py](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/gdb/gdb_commands.py). +`ReprCommand.invoke` initiates the check logic with the given variable, and handles top-level error reporting. + +* LLDB: Upon encountering a `repr` pseudo-command, `lldb_batchmode.main` dispatches to `check_lldb.check()`. + +> [!Note] +> LLDB also supports registering +> [custom CLI commands via the Python API](https://lldb.llvm.org/use/tutorials/writing-custom-commands.html). +> In the future, LLDB's `repr` logic may be refactored to behave more similarly to GDB's. + If the `--bless` option was specified, the variable is converted from the in-memory representation to our equivalent schema class. This includes the variable's type, visualizers, children, the children's types, etc. Once inserted into `TargetData`, -the variable is tested against the data that was just saved to `TargetData`. +the debugger's variable object is sanity-tested against the data that was just added to `TargetData`. If no exception or errors occurred and the `--bless` option was specified, `INPUT_DATA` is written -to the appropriate file just before `lldb_batchmode` exits. -If errors occur, `INPUT_DATA` is simply discarded. +to the appropriate file just before `debugger_tester` exits. +If errors occur, the blessed data is simply discarded. Currently, the `repr` pseudo-command is checked for directly. GDB and LLDB both support creating custom CLI commands via Python code. @@ -170,7 +185,7 @@ to provide more useful error messages. For example, LLDB can be a bit coy when it comes to reporting errors that occur within synthetic/summary provider calls. This is especially true when running the command within another -command, as the tests do by calling `script import lldb_batchmode; lldb_batchmode.main()` and +command, as the tests do by calling `script import debugger_tester; debugger_tester.main()` and executing commands in that context. When we encounter an error, we can import the appropriate summary provider, pass the variable object @@ -186,7 +201,7 @@ We absolutely do not want people accidentally blessing bad data purely because the first error happened to be an expected change. Errors are printed directly to `stdout` to appear as visible output from the `repr` pseudo command. -There are [several error helper functions](https://github.com/rust-lang/rust/blob/e7b595554e664e6bd281c8cf881093d6c71bc0e1/src/etc/lldb_batchmode/common.py#L35-L51) +There are [several error helper functions](https://github.com/rust-lang/rust/blob/c26ce708de5d14682647895d2f3caf38f70b5aa6/src/etc/debugger_tester/common.py#L35-L51) to keep formatting consistent. > [!NOTE] @@ -198,7 +213,7 @@ to keep formatting consistent. If no errors occurred for a given variable, `$VAR_NAME ok` is printed to `stdout` for `compiletest` to match against. -Before `lldb_batchmode` exits, one last check is done to ensure that all the types and variables +Before `debugger_tester` exits, one last check is done to ensure that all the types and variables that were present in `INPUT_DATA` have been checked against. If this check fails, the script reports the untested types/variables and exits with an error code. diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 0928f27940885..661e07af7189c 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -41,15 +41,15 @@ LL | more code - Primary and secondary spans underlying the users' code. These spans can optionally contain one or more labels. - Primary spans should have enough text to describe the problem in such a - way that if it were the only thing being displayed (for example, in an - IDE) it would still make sense. - Because it is "spatially aware" (it - points at the code), it can generally be more succinct than the error message. - - If cluttered output can be foreseen in cases when multiple span labels - overlap, it is a good idea to tweak the output appropriately. + way that if it were the only thing being displayed (for example, + in an IDE) it would still make sense. + Because it is "spatially aware" (it points at the code), + it can generally be more succinct than the error message. + - If cluttered output can be foreseen in cases when multiple span labels overlap, + it is a good idea to tweak the output appropriately. For example, the `if/else arms have incompatible types` error uses different - spans depending on whether the arms are all in the same line, if one of - the arms is empty and if none of those cases applies. + spans depending on whether the arms are all in the same line, + if one of the arms is empty, and if none of those cases applies. - Sub-diagnostics. Any error can have multiple sub-diagnostics that look similar to the main part of the error. These are used for cases where the @@ -57,15 +57,15 @@ LL | more code If the order of the explanation can be "order free", leveraging secondary labels in the main diagnostic is preferred, as it is typically less verbose. -The text should be matter of fact and avoid capitalization and periods, unless -multiple sentences are _needed_: +The text should be matter of fact and avoid capitalization and periods, +unless multiple sentences are _needed_: ```txt error: the fobrulator needs to be krontrificated ``` -When code or an identifier must appear in a message or label, it should be -surrounded with backticks: +When code or an identifier must appear in a message or label, +it should be surrounded with backticks: ```txt error: the identifier `foo.bar` is invalid @@ -84,12 +84,12 @@ explanation would give more information than the error itself. A lot of the time it's better to put all the information in the emitted error itself. However, sometimes that would make the error verbose or there are too many possible -triggers to include useful information for all cases in the error, in which case -it's a good idea to add an explanation.[^estebank] +triggers to include useful information for all cases in the error, +in which case it's a good idea to add an explanation.[^estebank] As always, if you are not sure, just ask your reviewer! -If you decide to add a new error with an associated error code, please read -[this section][error-codes] for a guide and important details about the process. +If you decide to add a new error with an associated error code, +please read [this section][error-codes] for a guide and important details about the process. [^estebank]: This rule of thumb was suggested by **@estebank** [here][estebank-comment]. @@ -102,23 +102,23 @@ If you decide to add a new error with an associated error code, please read Some messages are emitted via [lints](#lints), where the user can control the level. Most diagnostics are hard-coded such that the user cannot control the level. -Usually it is obvious whether a diagnostic should be "fixed" or a lint, but -there are some grey areas. +Usually it is obvious whether a diagnostic should be "fixed" or a lint, +but there are some grey areas. Here are a few examples: - Borrow checker errors: these are fixed errors. The user cannot adjust the level of these diagnostics to silence the borrow checker. - Dead code: this is a lint. - While the user probably doesn't want dead code in - their crate, making this a hard error would make refactoring and development very painful. + While the user probably doesn't want dead code in their crate, + making this a hard error would make refactoring and development very painful. - [future-incompatible lints]: these are silenceable lints. It was decided that making them fixed errors would cause too much breakage, so warnings are instead emitted, and will eventually be turned into fixed (hard) errors. -Hard-coded warnings (those using methods like `span_warn`) should be avoided -for normal code, preferring to use lints instead. +Hard-coded warnings (those using methods like `span_warn`) should be avoided for normal code, +preferring to use lints instead. Some cases, such as warnings with CLI flags, will require the use of hard-coded warnings. See the `deny` [lint level](#diagnostic-levels) below for guidelines when to @@ -133,11 +133,11 @@ use an error-level lint instead of a fixed error. small – screen (which hasn't been cleaned for a while), cannot be understood by a normal programmer, who just came out of bed after a night partying, it's too complex. -- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase - letter and do not end with punctuation. +- `Error`, `Warning`, `Note`, + and `Help` messages start with a lowercase letter and do not end with punctuation. - Error messages should be succinct. - Users will see these error messages many - times, and more verbose descriptions can be viewed with the `--explain` flag. + Users will see these error messages many times, + and more verbose descriptions can be viewed with the `--explain` flag. That said, don't make it so terse that it's hard to understand. - The word "illegal" is illegal. Prefer "invalid" or a more specific word instead. @@ -145,8 +145,8 @@ use an error-level lint instead of a fixed error. [`rustc_errors::DiagCtxt`][DiagCtxt]'s `span_*` methods or a diagnostic struct's `#[primary_span]` to easily do this). Also `note` other spans that have contributed to the error if the span isn't too large. -- When emitting a message with span, try to reduce the span to the smallest - amount possible that still signifies the issue +- When emitting a message with span, + try to reduce the span to the smallest amount possible that still signifies the issue - Try not to emit multiple error messages for the same error. This may require detecting duplicates. - When the compiler has too little information for a specific error message, @@ -154,8 +154,8 @@ use an error-level lint instead of a fixed error. allow adding more information. For example, see [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these annotations when available! -- Keep in mind that Rust's learning curve is rather steep, and that the - compiler messages are an important learning tool. +- Keep in mind that Rust's learning curve is rather steep, + and that the compiler messages are an important learning tool. - When talking about the compiler, call it `the compiler`, not `Rust` or `rustc`. - Use the [Oxford comma](https://en.wikipedia.org/wiki/Serial_comma) when writing lists of items. - When mentioning attributes, use this form whenever possible: "the `inline` attribute". @@ -168,8 +168,8 @@ From [RFC 0344], lint names should be consistent, with the following guidelines: The basic rule is: the lint name should make sense when read as "allow *lint-name*" or "allow *lint-name* items". -For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, while "allow -`unsafe_block`" is ungrammatical (should be plural). +For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, +while "allow `unsafe_block`" is ungrammatical (should be plural). - Lint names should state the bad thing being checked for, e.g. `deprecated`, so that `#[allow(deprecated)]` (items) reads correctly. @@ -180,8 +180,8 @@ For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, whi This keeps lint names short. (Again, think "allow *lint-name* items".) -- If a lint applies to a specific grammatical class, mention that class and - use the plural form: use `unused_variables` rather than `unused_variable`. +- If a lint applies to a specific grammatical class, + mention that class and use the plural form: use `unused_variables` rather than `unused_variable`. This makes `#[allow(unused_variables)]` read correctly. - Lints that catch unnecessary, unused, or useless aspects of code should use @@ -200,12 +200,12 @@ Guidelines for different diagnostic levels: has decided to make a specific `warning` into an error. - `warning`: emitted when the compiler detects something odd about a program. - Care should be taken when adding warnings to avoid warning fatigue, and - avoid false-positives where there really isn't a problem with the code. + Care should be taken when adding warnings to avoid warning fatigue, + and avoid false-positives where there really isn't a problem with the code. Some examples of when it is appropriate to issue a warning: - - A situation where the user *should* take action, such as swap out a - deprecated item, or use a `Result`, but otherwise doesn't prevent compilation. + - A situation where the user *should* take action, such as swap out a deprecated item, + or use a `Result`, but otherwise doesn't prevent compilation. - Unnecessary syntax that can be removed without affecting the semantics of the code. For example, unused code, or unnecessary `unsafe`. - Code that is very likely to be incorrect, dangerous, or confusing, but the @@ -214,13 +214,13 @@ Guidelines for different diagnostic levels: `bindings_with_variant_name` (the user likely did not intend to create a binding in a pattern). - [Future-incompatible lints](#future-incompatible), where something was - accidentally or erroneously accepted in the past, but rejecting would - cause excessive breakage in the ecosystem. + accidentally or erroneously accepted in the past, + but rejecting would cause excessive breakage in the ecosystem. - Stylistic choices. For example, camel or snake case, or the `dyn` trait warning in the 2018 edition. These have a high bar to be added, and should only be used in exceptional circumstances. - Other stylistic choices should - either be allow-by-default lints, or part of other tools like Clippy or rustfmt. + Other stylistic choices should either be allow-by-default lints, + or part of other tools like Clippy or rustfmt. - `help`: emitted following an `error` or `warning` to give additional information to the user about how to solve their problem. @@ -247,8 +247,8 @@ Not to be confused with *lint levels*, whose guidelines are: Some examples: - A future-incompatible or edition-based lint that has graduated from the warning level. - - Something that has an extremely high confidence that is incorrect, but - still want an escape hatch to allow it to pass. + - Something that has an extremely high confidence that is incorrect, + but still want an escape hatch to allow it to pass. - `warn`: Equivalent to the `warning` diagnostic level. See `warning` above for guidelines. @@ -279,8 +279,8 @@ There are three main ways to find where a given error is emitted: constructed behind a relatively deep call-stack. Even then, it is a good way to get your bearings. - Invoking `rustc` with the nightly-only flag `-Z treat-err-as-bug=1` - will treat the first error being emitted as an Internal Compiler Error, which - allows you to get a stack trace at the point the error has been emitted. + will treat the first error being emitted as an Internal Compiler Error, + which allows you to get a stack trace at the point the error has been emitted. Change the `1` to something else if you wish to trigger on a later error. There are limitations with this approach: @@ -299,8 +299,8 @@ order things are happening. [`Span`][span] is the primary data structure in `rustc` used to represent a location in the code being compiled. -`Span`s are attached to most constructs in -HIR and MIR, allowing for more informative error reporting. +`Span`s are attached to most constructs in HIR and MIR, +allowing for more informative error reporting. [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html @@ -320,8 +320,8 @@ The [`rustc_errors`][errors] crate defines most of the utilities used for report Diagnostics can be implemented as types which implement the `Diagnostic` trait. This is preferred for new diagnostics as it enforces a separation between diagnostic emitting logic and the main code paths. -For less-complex diagnostics, the `Diagnostic` trait can be derived -- see [Diagnostic -structs][diagnostic-structs]. +For less-complex diagnostics, +the `Diagnostic` trait can be derived -- see [Diagnostic structs][diagnostic-structs]. Within the trait implementation, the APIs described below can be used as normal. [diagnostic-structs]: ./diagnostics/diagnostic-structs.md @@ -337,12 +337,11 @@ warnings, errors, fatal errors, suggestions, etc. In general, there are two classes of such methods: ones that emit an error directly and ones that allow finer control over what to emit. For example, -[`span_err`][spanerr] emits the given error message at the given `Span`, but -[`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. +[`span_err`][spanerr] emits the given error message at the given `Span`, +but [`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. Most of these methods will accept strings, but it is recommended that typed -identifiers for translatable diagnostics be used for new diagnostics (see -[Translation]). +identifiers for translatable diagnostics be used for new diagnostics (see [Translation]). [translation]: ./diagnostics/translation.md @@ -385,8 +384,8 @@ example-example-error = oh no! this is an error! ## Suggestions -In addition to telling the user exactly _why_ their code is wrong, it's -oftentimes furthermore possible to tell them how to fix it. +In addition to telling the user exactly _why_ their code is wrong, +it's oftentimes furthermore possible to tell them how to fix it. To this end, [`Diag`][diag] offers a structured suggestions API, which formats code suggestions pleasingly in the terminal, or (when the `--error-format json` flag @@ -398,8 +397,7 @@ Not all suggestions should be applied mechanically; they have a degree of confidence in the suggested code, from high (`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`). Be conservative when choosing the level. -Use the [`span_suggestion`][span_suggestion] method of `Diag` to -make a suggestion. +Use the [`span_suggestion`][span_suggestion] method of `Diag` to make a suggestion. The last argument provides a hint to tools whether the suggestion is mechanically applicable or not. Suggestions point to one or more spans with corresponding code that will @@ -515,8 +513,8 @@ Some of the passes are: - Example: [`keyword_idents`] checks for identifiers that will become keywords in future editions, but is sensitive to identifiers used in macros. -- Early lint pass: Works on [AST nodes] after [macro expansion] and name - resolution, just before [AST lowering]. +- Early lint pass: Works on [AST nodes] after [macro expansion] and name resolution, + just before [AST lowering]. These lints are for purely syntactical lints. - Example: The [`unused_parens`] lint checks for parenthesized-expressions in situations where they are not needed, like an `if` condition. @@ -534,11 +532,11 @@ Some of the passes are: - Example: The [`arithmetic_overflow`] lint is emitted when it detects a constant value that may overflow. -Most lints work well via the pass systems, and they have a fairly -straightforward interface and easy way to integrate (mostly just implementing +Most lints work well via the pass systems, +and they have a fairly straightforward interface and easy way to integrate (mostly just implementing a specific `check` function). -However, some lints are easier to write when -they live on a specific code path anywhere in the compiler. +However, +some lints are easier to write when they live on a specific code path anywhere in the compiler. For example, the [`unused_mut`] lint is implemented in the borrow checker as it requires some information and state in the borrow checker. @@ -589,8 +587,8 @@ One benefit is that it is close to the dependency root, so it can be much faster [`rustc_lint_defs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/index.html Every lint is implemented via a `struct` that implements the `LintPass` `trait` -(you can also implement one of the more specific lint pass traits, either -`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). +(you can also implement one of the more specific lint pass traits, +either `EarlyLintPass` or `LateLintPass`, depending on when is best for your lint to run). The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. @@ -700,24 +698,25 @@ declare_lint! { } ``` -### Future-incompatible lints +### future-incompatible lints The use of the term `future-incompatible` within the compiler has a slightly broader meaning than what rustc exposes to users of the compiler. -Inside rustc, future-incompatible lints are for signalling to the user that code they have -written may not compile in the future. +Inside rustc, +future-incompatible lints are for signalling to the user their code may not compile in the future. In general, future-incompatible code exists for two reasons: -* The user has written unsound code that the compiler mistakenly accepted. +* The code is unsound, and the compiler mistakenly accepted it. While it is within Rust's backwards compatibility guarantees to fix the soundness hole -(breaking the user's code), the lint is there to warn the user that this will happen -in some upcoming version of rustc *regardless of which edition the code uses*. This is the -meaning that rustc exclusively exposes to users as "future incompatible". -* The user has written code that will either no longer compiler *or* will change -meaning in an upcoming *edition*. These are often called "edition lints" and can be -typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) -that are used to lint against code that will break if the user updates the crate's edition. -See [migration lints](guides/editions.md#migration-lints) for more details. + (breaking the user's code), the lint is there to warn the user that this will happen + in some upcoming version of rustc *regardless of which edition the code uses*. + This is the meaning that rustc exclusively exposes to users as "future incompatible". +* The code will either no longer compile *or* will change + meaning in an upcoming *edition*. + These are often called "edition lints" and can be + typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) + that are used to lint against code that will break if the user updates the crate's edition. + See [migration lints](guides/editions.md#migration-lints) for more details. A future-incompatible lint should be declared with the `@future_incompatible` additional "field": @@ -735,8 +734,8 @@ declare_lint! { Notice the `reason` field which describes why the future incompatible change is happening. This will change the diagnostic message the user receives as well as determine which lint groups the lint is added to. -In the example above, the lint is an "edition lint" -(since its "reason" is `EditionError`), signifying to the user that the use of anonymous +In the example above, the lint is an "edition lint" (since its "reason" is `EditionError`), +signifying to the user that the use of anonymous parameters will no longer compile in Rust 2018 and beyond. Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible` @@ -745,16 +744,16 @@ an edition) or into the `future_incompatibility` lint group. [fi-lint-groupings]: https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237 -If you need a combination of options that's not supported by the -`declare_lint!` macro, you can always change the `declare_lint!` macro to support this. +If you need a combination of options that's not supported by the `declare_lint!` macro, +you can always change the `declare_lint!` macro to support this. ### Renaming or removing a lint If it is determined that a lint is either improperly named or no longer needed, -the lint must be registered for renaming or removal, which will trigger a warning if a user tries -to use the old lint name. -To declare a rename/remove, add a line with -[`store.register_renamed`] or [`store.register_removed`] to the code of the +the lint must be registered for renaming or removal, +which will trigger a warning if a user tries to use the old lint name. +To declare a rename/remove, +add a line with [`store.register_renamed`] or [`store.register_removed`] to the code of the [`rustc_lint::register_builtins`] function. ```rust,ignore @@ -785,15 +784,15 @@ add_lint_group!(sess, ``` This defines the `nonstandard_style` group which turns on the listed lints. -A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in -the source code, or by passing `-W nonstandard-style` on the command line. +A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in the source code, +or by passing `-W nonstandard-style` on the command line. Some lint groups are created automatically in `LintStore::register_lints`. For instance, any lint declared with `FutureIncompatibleInfo` where the reason is `FutureIncompatibilityReason::FutureReleaseError` (the default when -`@future_incompatible` is used in `declare_lint!`), will be added to -the `future_incompatible` lint group. +`@future_incompatible` is used in `declare_lint!`), +will be added to the `future_incompatible` lint group. Editions also have their own lint groups (e.g., `rust_2021_compatibility`) automatically generated for any lints signaling future-incompatible code that will break in the specified edition. @@ -813,15 +812,15 @@ The linting system automatically takes care of handling buffered lints later. [sessbl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.buffer_lint [parsebl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html#method.buffer_lint -Thus, to define a lint that runs early in the compilation, one defines a lint -like normal but invokes the lint with `buffer_lint`. +Thus, to define a lint that runs early in the compilation, +one defines a lint like normal but invokes the lint with `buffer_lint`. #### Linting even earlier in the compiler The parser (`rustc_ast`) is interesting in that it cannot have dependencies on any of the other `rustc*` crates. -In particular, it cannot depend on -`rustc_middle::lint` or `rustc_lint`, where all of the compiler linting infrastructure is defined. +In particular, it cannot depend on `rustc_middle::lint` or `rustc_lint`, +where all of the compiler linting infrastructure is defined. That's troublesome! To solve this, `rustc_ast` defines its own buffered lint type, which `ParseSess::buffer_lint` uses. @@ -841,20 +840,20 @@ $ rustc json_error_demo.rs --error-format json {"message":"For more information about this error, try `rustc --explain E0277`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0277`.\n"} ``` -Note that the output is a series of lines, each of which is a JSON -object, but the series of lines taken together is, unfortunately, not +Note that the output is a series of lines, each of which is a JSON object, +but the series of lines taken together is, unfortunately, not valid JSON, thwarting tools and tricks (such as [piping to `python3 -m json.tool`](https://docs.python.org/3/library/json.html#module-json.tool)) that require such. -(One speculates that this was intentional for LSP -performance purposes, so that each line/object can be sent as it is flushed?) +(One speculates that this was intentional for LSP performance purposes, +so that each line/object can be sent as it is flushed?) Also note the "rendered" field, which contains the "human" output as a string; this was introduced so that UI tests could both make use of -the structured JSON and see the "human" output (well, _sans_ colors) -without having to compile everything twice. +the structured JSON and see the "human" output (well, +_sans_ colors) without having to compile everything twice. -The "human" readable and the json format emitter can be found under -`rustc_errors`, both were moved from the `rustc_ast` crate to the +The "human" readable and the json format emitter can be found under `rustc_errors`, +both were moved from the `rustc_ast` crate to the [rustc_errors crate](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html). The JSON emitter defines [its own `Diagnostic` @@ -937,16 +936,16 @@ If you can, you should use that instead. ### Filtering -To allow more targeted error messages, it is possible to filter the -application of these fields with `on`. +To allow more targeted error messages, +it is possible to filter the application of these fields with `on`. You can filter on the following boolean flags: - `crate_local`: whether the code causing the trait bound to not be fulfilled is part of the user's crate. This is used to avoid suggesting code changes that would require modifying a dependency. - `direct`: whether this is a user-specified rather than derived obligation. - - `from_desugaring`: whether we are in some kind of desugaring, like `?` - or a `try` block for example. + - `from_desugaring`: whether we are in some kind of desugaring, + like `?` or a `try` block for example. This flag can also be matched on, see below. You can match on the following names and values, using `name = "value"`: @@ -955,8 +954,8 @@ You can match on the following names and values, using `name = "value"`: - `from_desugaring`: Match against a particular variant of the `DesugaringKind` enum. The desugaring is identified by its variant name, for example `"QuestionMark"` for `?` desugaring, or `"TryBlock"` for `try` blocks. - - `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"` - or `Rhs="i32"`. + - `Self` and any generic arguments of the trait, + like `Self = "alloc::string::String"` or `Rhs="i32"`. The compiler can provide several values to match on, for example: - the self_ty, pretty printed with and without type arguments resolved. diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index 9c54705e000fd..f6a11b435ad32 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -3,20 +3,20 @@ ## The `HostEffect` predicate [`HostEffectPredicate`]s are a kind of predicate from `[const] Tr` or `const Tr` bounds. -It has a trait reference, and a `constness` which could be `Maybe` or -`Const` depending on the bound. +It has a trait reference, +and a `constness` which could be `Maybe` or `Const`, depending on the bound. Because `[const] Tr`, or rather `Maybe` bounds -apply differently based on whichever contexts they are in, they have different -behavior than normal bounds. +apply differently based on whichever contexts they are in, +they have different behavior than normal bounds. Where normal trait bounds on a function such as `T: Tr` are collected within the [`clauses_of`] query to be proven when a -function is called and to be assumed within the function, bounds such as -`T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result +function is called and to be assumed within the function, +bounds such as `T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result from `clauses_of`, but also adds a `HostEffectPredicate` to the [`const_conditions`] query. On the other hand, `T: const Tr` bounds do not change meaning across contexts, -therefore they will result in `HostEffect(T: Tr, const)` being added to -`clauses_of`, and not `const_conditions`. +therefore they will result in `HostEffect(T: Tr, const)` being added to `clauses_of`, +and not `const_conditions`. [`HostEffectPredicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/predicate/struct.HostEffectPredicate.html [`clauses_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.clauses_of @@ -34,14 +34,15 @@ fn foo() where T: Default {} We must be able to prove that `T` implements `Default`. In a similar vein, `const_conditions` represents a set of predicates that need to be proven to use -an item *in const contexts*. If we adjust the example above to use `const` trait bounds: +an item *in const contexts*. +If we adjust the example above to use `const` trait bounds: ```rust const fn foo() where T: [const] Default {} ``` -Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` -query, suggesting that in order to call `foo` from const contexts, one must +Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` query, +suggesting that in order to call `foo` from const contexts, one must prove that `T` has a const implementation of `Default`. ## Enforcement of `const_conditions` @@ -51,8 +52,8 @@ prove that `T` has a const implementation of `Default`. Every call in HIR from a const context (which includes `const fn` and `const` items) will check that `const_conditions` of the function we are calling hold. This is done in [`FnCtxt::enforce_context_effects`]. -Note that we don't check -if the function is only referred to but not called, as the following code needs to compile: +Note that we don't check if the function is only referred to but not called, +as the following code needs to compile: ```rust const fn hi() -> T { @@ -61,8 +62,8 @@ const fn hi() -> T { const X: fn() -> u32 = hi::; ``` -For a trait `impl` to be well-formed, we must be able to prove the -`const_conditions` of the trait from the `impl`'s environment. +For a trait `impl` to be well-formed, +we must be able to prove the `const_conditions` of the trait from the `impl`'s environment. This is checked in [`wfcheck::check_impl`]. Here's an example: @@ -79,8 +80,8 @@ impl const Foo for () {} Methods of trait impls must not have stricter bounds than the method of the trait that they are implementing. -To check that the methods are compatible, a -hybrid environment is constructed with the predicates of the `impl` plus the +To check that the methods are compatible, +a hybrid environment is constructed with the predicates of the `impl` plus the predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: @@ -113,8 +114,8 @@ are revalidated again in [`Checker::revalidate_conditional_constness`]. ## `explicit_implied_const_bounds` on associated types and traits -Bounds on associated types, opaque types, and supertraits such as the following -have their bounds represented differently: +Bounds on associated types, opaque types, +and supertraits such as the following have their bounds represented differently: ```rust trait Foo: [const] PartialEq { @@ -132,8 +133,8 @@ bounds on functions), these bounds need to be proved at definition (at the impl, or when returning the opaque) but can be assumed for callers. The non-const equivalent of these bounds are called [`explicit_item_bounds`]. -These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR -typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and +These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR typeck, +[`evaluate_host_effect_from_item_bounds`] in the old solver and [`consider_additional_alias_assumptions`] in the new solver. [`explicit_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.explicit_item_bounds @@ -147,11 +148,11 @@ typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and In general, we can prove a `HostEffect` predicate when either of these conditions are met: * The predicate can be assumed from caller bounds; -* The type has a `const` `impl` for the trait, *and* that const conditions on - the impl holds, *and* that the `explicit_implied_const_bounds` on the trait holds; or +* The type has a `const` `impl` for the trait, *and* that const conditions on the impl holds, + *and* that the `explicit_implied_const_bounds` on the trait holds; or * The type has a built-in implementation for the trait in const contexts. - For example, `Fn` may be implemented by function items if their const conditions - are satisfied, or `Destruct` is implemented in const contexts if the type can + For example, `Fn` may be implemented by function items if their const conditions are satisfied, + or `Destruct` is implemented in const contexts if the type can be dropped at compile time. [old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html @@ -164,8 +165,8 @@ To be expanded later. ### The `#[rustc_non_const_trait_method]` attribute This is intended for internal (standard library) usage only. -With this attribute applied to a trait method, the compiler will not check the default body of this -method for ability to run in compile time. +With this attribute applied to a trait method, +the compiler will not check the default body of this method for ability to run in compile time. Users of the trait will also not be allowed to use this trait method in const contexts. This attribute is primarily used for constifying large traits such as `Iterator` without having to make all diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 26c7e2e02bd56..0e23be130c403 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -27,12 +27,12 @@ The following external projects are managed using some form of a `subtree`: * [compiler-builtins](https://github.com/rust-lang/compiler-builtins) * [stdarch](https://github.com/rust-lang/stdarch) -In contrast to `submodule` dependencies -(see below for those), the `subtree` dependencies are just regular files and directories which can -be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific +In contrast to `submodule` dependencies (see below for those), +the `subtree` dependencies are just regular files and directories which can be updated in-tree. +However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. -The exception is that when rustc changes are required to -implement a new tool feature or test, that should happen in one collective rustc PR. +The exception is that when rustc changes are required to implement a new tool feature or test, +that should happen in one collective rustc PR. Similarly, if your rustc changes break the build of some subtree dependency, you should include fixes for those in the rustc PR as well. @@ -42,13 +42,13 @@ you should include fixes for those in the rustc PR as well. * Using `git subtree` * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy)) * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh)) - * `rustfmt` * `rustc_codegen_gcc` ([sync guide](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md)) * Using the [josh](#synchronizing-a-josh-subtree) tool * `miri` * `rust-analyzer` * `rustc_codegen_cranelift` * `rustc-dev-guide` + * `rustfmt` * `compiler-builtins` * `stdarch` @@ -56,7 +56,7 @@ you should include fixes for those in the rustc PR as well. The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. -We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). +We provide a helper tool, [`rustc-josh-sync`][josh-sync], to help with the synchronization, described [below](#synchronizing-a-josh-subtree). ### Synchronizing a Josh subtree @@ -103,20 +103,20 @@ Periodically the changes made to subtree based dependencies need to be synchroni repository and the upstream tool repositories. Subtree synchronizations are typically handled by the respective tool maintainers. -Other users -are welcome to submit synchronization PRs, however, in order to do so you will need to modify -your local git installation and follow a very precise set of instructions. -These instructions are documented, along with several useful tips and tricks, in the -[syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. -The instructions are applicable for use with any subtree based tool, just be sure to -use the correct corresponding subtree directory and remote repository. +Other users are welcome to submit synchronization PRs. +However, in order to do so, +you will need to modify your local git installation and follow a very precise set of instructions. +These instructions are documented, along with several useful tips and tricks, +in the [syncing subtree changes][clippy-sync-docs] section in Clippy's Contributing guide. +The instructions are applicable for use with any subtree-based tool; +just be sure to use the correct corresponding subtree directory and remote repository. The synchronization process goes in two directions: `subtree push` and `subtree pull`. A `subtree push` takes all the changes that happened to the copy in this repo and creates commits on the remote repo that match the local changes. -Every local commit that touched the subtree causes a commit on the remote repo, but -is modified to move the files from the specified directory to the tool repo root. +Every local commit that touched the subtree causes a commit on the remote repo, +but is modified to move the files from the specified directory to the tool repo root. A `subtree pull` takes all changes since the last `subtree pull` from the tool repo and adds these commits to the rustc repo along with a merge commit that moves @@ -142,8 +142,8 @@ that this is happening because you suddenly get thousands of commits that want t ### Creating a new subtree dependency -If you want to create a new subtree dependency from an existing repository, call (from this -repository's root directory!) +If you want to create a new subtree dependency from an existing repository, +call (from this repository's root directory!) ``` git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git master @@ -152,9 +152,9 @@ git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git This will create a new commit, which you may not rebase under any circumstances! Delete the commit and redo the operation if you need to rebase. -Now you're done, the `src/tools/clippy` directory behaves as if Clippy were -part of the rustc monorepo, so no one but you (or others that synchronize -subtrees) actually needs to use `git subtree`. +Now you're done; +the `src/tools/clippy` directory behaves as if Clippy were part of the rustc monorepo, +so no one but you (or others that synchronize subtrees) actually needs to use `git subtree`. ## External dependencies (submodules) @@ -168,14 +168,14 @@ Usage of submodules is discussed more in the [Using Git chapter](git.md#git-subm Some of the submodules are allowed to be in a "broken" state where they either don't build or their tests don't pass, e.g. the documentation books like [The Rust Reference]. -Maintainers of these projects will be notified -when the project is in a broken state, and they should fix them as soon as possible. +Maintainers of these projects will be notified when the project is in a broken state, +and they should fix them as soon as possible. The current status is tracked on the [toolstate website]. More information may be found on the Forge [Toolstate chapter]. In practice, it is very rare for documentation to have broken toolstate. -Breakage is not allowed in the beta and stable channels, and must be addressed -before the PR is merged. +Breakage is not allowed in the beta and stable channels, +and must be addressed before the PR is merged. They are also not allowed to be broken on `main` in the week leading up to the beta cut. [git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index b5b5b20500f39..005dc0cac21d9 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -7,18 +7,18 @@ It is a radically simplified form of Rust that is used for certain flow-sensitive safety checks – notably the borrow checker! – and also for optimization and code generation. -If you'd like a very high-level introduction to MIR, as well as some -of the compiler concepts that it relies on (such as control-flow +If you'd like a very high-level introduction to MIR, +as well as some of the compiler concepts that it relies on (such as control-flow graphs and desugaring), you may enjoy the [rust-lang blog post that introduced MIR][blog]. [blog]: https://blog.rust-lang.org/2016/04/19/MIR.html ## Introduction to MIR -MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, but much of the code -that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], -[`compiler/rustc_mir_transform`][mirmanip_transform], and -[`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. +MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, +but much of the code that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], +[`compiler/rustc_mir_transform`][mirmanip_transform], +and [`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. [RFC 1211]: https://rust-lang.github.io/rfcs/1211-mir.html @@ -38,22 +38,22 @@ This section introduces the key concepts of MIR, summarized here: - **statements:** actions with one successor - **terminators:** actions with potentially multiple successors; always at the end of a block - (if you're not familiar with the term *basic block*, see the [background chapter][cfg]) -- **Locals:** Memory locations allocated on the stack (conceptually, at - least), such as function arguments, local variables, and temporaries. +- **Locals:** Memory locations allocated on the stack (conceptually, at least), + such as function arguments, local variables, and temporaries. These are identified by an index, written with a leading underscore, like `_1`. There is also a special "local" (`_0`) allocated to store the return value. - **Places:** expressions that identify a location in memory, like `_1` or `_1.f`. - **Rvalues:** expressions that produce a value. The "R" stands for the fact that these are the "right-hand side" of an assignment. - - **Operands:** the arguments to an rvalue, which can either be a - constant (like `22`) or a place (like `_1`). + - **Operands:** the arguments to an rvalue, + which can either be a constant (like `22`) or a place (like `_1`). You can get a feeling for how MIR is constructed by translating simple programs into MIR and reading the pretty printed output. -In fact, the playground makes this easy, since it supplies a MIR button that will -show you the MIR for your program. -Try putting this program into play -(or [clicking on this link][sample-play]), and then clicking the "MIR" button on the top: +In fact, the playground makes this easy, +since it supplies a MIR button that will show you the MIR for your program. +Try putting this program into play (or [clicking on this link][sample-play]), +and then clicking the "MIR" button on the top: [sample-play]: https://play.rust-lang.org/?gist=30074856e62e74e91f06abd19bd72ece&version=stable&edition=2021 @@ -83,8 +83,8 @@ We can use `rustc [filename].rs -Z mir-opt-level=0 --emit mir` to view unoptimiz This requires the nightly toolchain. -**Variable declarations.** If we drill in a bit, we'll see it begins -with a bunch of variable declarations. +**Variable declarations.** If we drill in a bit, +we'll see it begins with a bunch of variable declarations. They look like this: ```mir @@ -101,8 +101,8 @@ like `_0` or `_1`. We also intermingle the user's variables (e.g., `_1`) with temporary values (e.g., `_2` or `_3`). You can tell apart user-defined variables because they have debuginfo associated to them (see below). -**User variable debuginfo.** Below the variable declarations, we find the only -hint that `_1` represents a user variable: +**User variable debuginfo.** Below the variable declarations, +we find the only hint that `_1` represents a user variable: ```mir scope 1 { debug vec => _1; // in scope 1 at src/main.rs:2:9: 2:16 @@ -130,15 +130,15 @@ bb0: { } ``` -A basic block is defined by a series of **statements** and a final -**terminator**. In this case, there is one statement: +A basic block is defined by a series of **statements** and a final **terminator**. +In this case, there is one statement: ```mir StorageLive(_1); ``` -This statement indicates that the variable `_1` is "live", meaning -that it may be used later – this will persist until we encounter a +This statement indicates that the variable `_1` is "live", +meaning that it may be used later – this will persist until we encounter a `StorageDead(_1)` statement, which indicates that the variable `_1` is done being used. These "storage statements" are used by LLVM to allocate stack space. @@ -151,9 +151,9 @@ _1 = const >::new() -> bb2; Terminators are different from statements because they can have more than one successor – that is, control may flow to different places. Function calls like the call to `Vec::new` are always -terminators because of the possibility of unwinding, although in the -case of `Vec::new` we are able to see that indeed unwinding is not -possible, and hence we list only one successor block, `bb2`. +terminators because of the possibility of unwinding, +although in the case of `Vec::new` we are able to see that indeed unwinding is not possible, +and hence we list only one successor block, `bb2`. If we look ahead to `bb2`, we will see it looks like this: @@ -165,8 +165,8 @@ bb2: { } ``` -Here there are two statements: another `StorageLive`, introducing the `_3` -temporary, and then an assignment: +Here there are two statements: another `StorageLive`, introducing the `_3` temporary, +and then an assignment: ```mir _3 = &mut _1; @@ -179,8 +179,8 @@ Assignments in general have the form: ``` A place is an expression like `_3`, `_3.f` or `*_3` – it denotes a location in memory. -An **Rvalue** is an expression that creates a -value: in this case, the rvalue is a mutable borrow expression, which looks like `&mut `. +An **Rvalue** is an expression that creates a value: in this case, +the rvalue is a mutable borrow expression, which looks like `&mut `. So we can kind of define a grammar for rvalues like so: ```text @@ -194,21 +194,21 @@ So we can kind of define a grammar for rvalues like so: | move Place ``` -As you can see from this grammar, rvalues cannot be nested – they can -only reference places and constants. +As you can see from this grammar, +rvalues cannot be nested – they can only reference places and constants. Moreover, when you use a place, we indicate whether we are **copying it** (which requires that the place have a type `T` where `T: Copy`) or **moving it** (which works for a place of any type). -So, for example, if we had the expression `x -= a + b + c` in Rust, that would get compiled to two statements and a temporary: +So, for example, if we had the expression `x = a + b + c` in Rust, +that would get compiled to two statements and a temporary: ```mir TMP1 = a + b x = TMP1 + c ``` -([Try it and see][play-abc], though you may want to do release mode to skip -over the overflow checks.) +([Try it and see][play-abc], +though you may want to do release mode to skip over the overflow checks.) [play-abc]: https://play.rust-lang.org/?gist=1751196d63b2a71f8208119e59d8a5b6&version=stable @@ -225,8 +225,8 @@ but [you can read about those below](#promoted-constants)). - **Basic blocks**: The basic blocks are stored in the field [`Body::basic_blocks`][basicblocks]; this is a vector of [`BasicBlockData`] structures. - Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] - values, which are [newtype'd] indices into this vector. + Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] values, + which are [newtype'd] indices into this vector. - **Statements** are represented by the type [`Statement`]. - **Terminators** are represented by the [`Terminator`]. - **Locals** are represented by a [newtype'd] index type [`Local`]. @@ -240,8 +240,8 @@ but [you can read about those below](#promoted-constants)). These are represented by the [newtype'd] type [`ProjectionElem`]. So e.g. the place `_1.f` is a projection, with `f` being the "projection element" and `_1` being the base path. - `*_1` is also a projection, with the `*` being represented - by the [`ProjectionElem::Deref`] element. + `*_1` is also a projection, + with the `*` being represented by the [`ProjectionElem::Deref`] element. - **Rvalues** are represented by the enum [`Rvalue`]. - **Operands** are represented by the enum [`Operand`]. @@ -251,8 +251,8 @@ When code has reached the MIR stage, constants can generally come in two forms: *MIR constants* ([`mir::Constant`]) and *type system constants* ([`ty::Const`]). MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant; similarly, in `x + 2`, `2` is a MIR constant. -Type system constants are used in -the type system, in particular for array lengths but also for const generics. +Type system constants are used in the type system, +in particular for array lengths, but also for const generics. Generally, both kinds of constants can be "unevaluated" or "already evaluated". An unevaluated constant simply stores the `DefId` of what needs to be evaluated @@ -270,8 +270,8 @@ parameter is used as an operand. ### MIR constant values -In general, a MIR constant value (`mir::ConstValue`) was computed by evaluating -some constant the user wrote. +In general, +a MIR constant value (`mir::ConstValue`) was computed by evaluating some constant the user wrote. This [const evaluation](../const-eval.md) produces a very low-level representation of the result in terms of individual bytes. We call this an "indirect" constant (`mir::ConstValue::Indirect`) since the value @@ -280,9 +280,9 @@ is stored in-memory. However, storing everything in-memory would be awfully inefficient. Hence there are some other variants in `mir::ConstValue` that can represent certain simple and common values more efficiently. -In particular, everything that can be -directly written as a literal in Rust (integers, floats, chars, bools, but also -`"string literals"` and `b"byte string literals"`) has an optimized variant that +In particular, everything that can be directly written as a literal in Rust (integers, +floats, chars, bools, +but also `"string literals"` and `b"byte string literals"`) has an optimized variant that avoids the full overhead of the in-memory representation. ### ValTrees @@ -301,8 +301,8 @@ In other words, a specific value must only be representable in one specific way. For example, there is only one way to represent an array of two integers as a `ValTree`: `Branch([Leaf(first_int), Leaf(second_int)])`. Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a -`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` -(and is very complex to do, so it is unlikely anyone is tempted to do so). +`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` (and is very complex to do, +so it is unlikely anyone is tempted to do so). These rules also mean that some values are not representable. There can be no `union`s in type level constants, diff --git a/src/doc/rustc-dev-guide/src/profiling/with-perf.md b/src/doc/rustc-dev-guide/src/profiling/with-perf.md index b55afed47fbdc..1a3b986d8213b 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with-perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with-perf.md @@ -60,8 +60,8 @@ cargo install --locked addr2line --features="bin" ### Gathering a perf profile from a `perf.rust-lang.org` test Often we want to analyze a specific test from `perf.rust-lang.org`. -The easiest way to do that is to use the [rustc-perf] -benchmarking suite, this approach is described [here](with-rustc-perf.md). +The easiest way to do that is to use the [rustc-perf] benchmarking suite, +this approach is described [here](with-rustc-perf.md). Instead of using the benchmark suite CLI, you can also profile the benchmarks manually. First, you need to clone the [rustc-perf] repository: @@ -96,8 +96,8 @@ CARGO_INCREMENTAL=0 cargo + check Next: we want record the execution time for *just* the clap-rs crate, running cargo check. -I tend to use `cargo rustc` for this, since it -also allows me to add explicit flags, which we'll do later on. +I tend to use `cargo rustc` for this, since it also allows me to add explicit flags, +which we'll do later on. ```bash touch src/lib.rs @@ -106,8 +106,8 @@ CARGO_INCREMENTAL=0 perf record -F99 --call-graph dwarf cargo rustc --profile ch Note that final command: it's a doozy! It uses the `cargo rustc` command, which executes rustc with (potentially) additional options; -the `--profile check` and `--lib` options specify that we are doing a -`cargo check` execution, and that this is a library (not a binary). +the `--profile check` and `--lib` options specify that we are doing a `cargo check` execution, +and that this is a library (not a binary). At this point, we can use `perf` tooling to analyze the results. For example: @@ -121,14 +121,14 @@ In simple cases, that can be helpful. For more detailed examination, the [`perf-focus` tool][pf] can be helpful; it is covered below. **A note of caution.** Each of the rustc-perf tests is its own special snowflake. - In particular, some of them are not libraries, in which - case you would want to do `touch src/main.rs` and avoid passing `--lib`. + In particular, some of them are not libraries, + in which case you would want to do `touch src/main.rs` and avoid passing `--lib`. I'm not sure how best to tell which test is which to be honest. ### Gathering NLL data -If you want to profile an NLL run, you can just pass extra options to -the `cargo rustc` command, like so: +If you want to profile an NLL run, you can just pass extra options to the `cargo rustc` command, +like so: ```bash touch src/lib.rs @@ -152,8 +152,8 @@ To understand how it works, you have to know just a bit about perf. Basically, perf works by *sampling* your process on a regular basis (or whenever some event occurs). For each sample, perf gathers a backtrace. `perf focus` lets you write a regular expression that tests -which functions appear in that backtrace, and then tells you which -percentage of samples had a backtrace that met the regular expression. +which functions appear in that backtrace, +and then tells you which percentage of samples had a backtrace that met the regular expression. It's probably easiest to explain by walking through how I would analyze NLL performance. ### Installing `perf-focus` @@ -168,8 +168,7 @@ cargo install --locked perf-focus Let's say we've gathered the NLL data for a test. We'd like to know how much time it is spending in the MIR borrow-checker. -The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do -this command: +The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do this command: ```bash $ perf focus '{do_mir_borrowck}' @@ -179,22 +178,22 @@ Not Matches: 542 Percentage : 29% ``` -The `'{do_mir_borrowck}'` argument is called the **matcher**. It -specifies the test to be applied on the backtrace. +The `'{do_mir_borrowck}'` argument is called the **matcher**. +It specifies the test to be applied on the backtrace. In this case, the `{X}` indicates that there must be *some* function on the backtrace that meets the regular expression `X`. -In this case, that regex is just the name of the function we want -(in fact, it's a subset of the name; +In this case, that regex is just the name of the function we want (in fact, +it's a subset of the name; the full name includes a bunch of other stuff, like the module path). In this mode, perf-focus just prints out the percentage of samples where `do_mir_borrowck` was on the stack: in this case, 29%. -**A note about c++filt.** To get the data from `perf`, `perf focus` - currently executes `perf script` (perhaps there is a better way...). +**A note about c++filt.** To get the data from `perf`, + `perf focus` currently executes `perf script` (perhaps there is a better way...). I've sometimes found that `perf script` outputs C++ mangled names. This is annoying. You can tell by running `perf script | - head` yourself — if you see names like `5rustc6middle` instead of - `rustc::middle`, then you have the same problem. + head` yourself — if you see names like `5rustc6middle` instead of `rustc::middle`, + then you have the same problem. You can solve this by doing: ```bash @@ -203,10 +202,10 @@ perf script | c++filt | perf focus --from-stdin ... This will pipe the output from `perf script` through `c++filt` and should mostly convert those names into a more friendly format. -The `--from-stdin` flag to `perf focus` tells it to get its data from -stdin, rather than executing `perf focus`. -We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, or -just always use it — it's pretty harmless). +The `--from-stdin` flag to `perf focus` tells it to get its data from stdin, +rather than executing `perf focus`. +We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, +or just always use it — it's pretty harmless). ### Example: How much time does MIR borrowck spend solving traits? @@ -275,17 +274,16 @@ Usually "total" is the more interesting number, but not always. ### Relative percentages -By default, all in perf-focus are relative to the **total program -execution**. This is useful to help you keep perspective — often as -we drill down to find hot spots, we can lose sight of the fact that, +By default, all in perf-focus are relative to the **total program execution**. +This is useful to help you keep perspective — often as we drill down to find hot spots, +we can lose sight of the fact that, in terms of overall program execution, this "hot spot" is actually not important. It also ensures that percentages between different queries are easily compared against one another. -That said, sometimes it's useful to get relative percentages, so `perf -focus` offers a `--relative` option. +That said, sometimes it's useful to get relative percentages, +so `perf focus` offers a `--relative` option. In this case, the percentages are listed only for samples that match (vs all samples). -So for example we could get our percentages relative to the borrowck itself -like so: +So, for example, we could get our percentages relative to the borrowck itself like so: ```bash $ perf focus '{do_mir_borrowck}' --tree-callees --relative --tree-max-depth 1 --tree-min-percent 5 diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 471b445c14d5a..a4b9eef02f13a 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -9,17 +9,18 @@ Instead of entirely independent passes (parsing, type-checking, etc.), a set of function-like *queries* compute information about the input source. For example, -there is a query called `type_of` that, given the [`DefId`] of -some item, will compute the type of that item and return it to you. +there is a query called `type_of` that, given the [`DefId`] of some item, +will compute the type of that item and return it to you. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.DefId.html [Overview of the compiler]: overview.md#queries -Query execution is *memoized*. The first time you invoke a -query, it will go do the computation, but the next time, the result is returned from a hashtable. -Moreover, query execution fits nicely into -*incremental computation*; the idea is roughly that, when you invoke a -query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] +Query execution is *memoized*. +The first time you invoke a query, +it will go do the computation, but the next time, the result is returned from a hashtable. +Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, +when you invoke a query, +the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] When we execute a query, we also discover (at runtime!) what other queries it depends on. @@ -39,8 +40,8 @@ For example: - That query in turn would invoke something asking for the HIR. - This keeps going further and further back until we wind up doing the actual parsing. -Although this vision is not fully realized, large sections of the -compiler (for example, generating [MIR]) currently work exactly like this. +Although this vision is not fully realized, large sections of the compiler (for example, +generating [MIR]) currently work exactly like this. [^incr-comp-detail]: The [Incremental compilation in detail] chapter gives a more in-depth description of what queries are and how they work. @@ -65,22 +66,22 @@ let ty = tcx.type_of(some_def_id); So you may be wondering what happens when you invoke a query method. The answer is that, for each query, the compiler maintains a -cache – if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries +cache – if your query has already been executed, then, +the answer is simple: we clone the return value out of the cache and return it (therefore, +you should try to ensure that the return types of queries are cheaply cloneable; insert an `Rc` if necessary). ### Providers -If, however, the query is *not* in the cache, then the compiler will -call the corresponding **provider** function. +If, however, the query is *not* in the cache, +then the compiler will call the corresponding **provider** function. A provider is a function implemented in a specific module and **manually registered** into either the [`Providers`][providers_struct] struct (for local crate queries) or the [`ExternProviders`][extern_providers_struct] struct (for external crate queries) during compiler initialization. The macro system generates both structs, -which act as function tables for all query implementations, where each -field is a function pointer to the actual provider. +which act as function tables for all query implementations, +where each field is a function pointer to the actual provider. **Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations. They are **not** Rust traits, but plain structs with function pointer fields. @@ -112,11 +113,11 @@ Providers take two arguments: the `tcx` and the query key. They return the result of the query. N.B. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. -But in some cases there are crates that -provide queries for *both* local and external crates, in which case -they define both a `provide` and a `provide_extern` function, through +providers**. +Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], +which loads the information from the crate metadata. +But in some cases there are crates that provide queries for *both* local and external crates, +in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. [rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html diff --git a/src/doc/rustc-dev-guide/src/sanitizers.md b/src/doc/rustc-dev-guide/src/sanitizers.md index 65e1c0c705057..5d242b8ac5d4a 100644 --- a/src/doc/rustc-dev-guide/src/sanitizers.md +++ b/src/doc/rustc-dev-guide/src/sanitizers.md @@ -1,33 +1,33 @@ # Sanitizers support -The rustc compiler contains support for following sanitizers: +The Rust compiler contains support for following sanitizers: -* [AddressSanitizer][clang-asan] a faster memory error detector. - Can detect out-of-bounds access to heap, stack, and globals, use after free, use - after return, double free, invalid free, memory leaks. -* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides +* [AddressSanitizer][clang-asan], a faster memory error detector. + It can detect out-of-bounds access to heap, stack, and globals, use after free, use + after return, double free, invalid free, and memory leaks. +* [ControlFlowIntegrity][clang-cfi], LLVM Control Flow Integrity (CFI), provides forward-edge control flow protection. -* [Hardware-assisted AddressSanitizer][clang-hwasan] a tool similar to - AddressSanitizer but based on partial hardware assistance. -* [KernelControlFlowIntegrity][clang-kcfi] LLVM Kernel Control Flow Integrity - (KCFI) provides forward-edge control flow protection for operating systems kernels. -* [LeakSanitizer][clang-lsan] a run-time memory leak detector. -* [MemorySanitizer][clang-msan] a detector of uninitialized reads. -* [ThreadSanitizer][clang-tsan] a fast data race detector. +* [Hardware-assisted AddressSanitizer][clang-hwasan] is similar to + AddressSanitizer, but is based on partial hardware assistance. +* [KernelControlFlowIntegrity][clang-kcfi], LLVM Kernel Control Flow Integrity + (KCFI), provides forward-edge control flow protection for operating system kernels. +* [LeakSanitizer][clang-lsan], a run-time memory leak detector. +* [MemorySanitizer][clang-msan], a detector of uninitialized reads. +* [ThreadSanitizer][clang-tsan], a fast data race detector. ## How to use the sanitizers? -To enable a sanitizer compile with `-Z sanitizer=...` option, where value is one -of `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory` or `thread`. +To enable a sanitizer, compile with `-Z sanitizer=...` option, where value is one +of `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory`, or `thread`. For more details on how to use sanitizers, -please refer to the sanitizer flag in [The Unstable Book]. +refer to the sanitizer flag in [The Unstable Book]. [The Unstable Book]: https://doc.rust-lang.org/unstable-book -## How are sanitizers implemented in rustc? +## How sanitizers are implemented in rustc The implementation of sanitizers (except CFI) relies almost entirely on LLVM. -The rustc is an integration point for LLVM compile time instrumentation passes +The Rust compiler is an integration point for LLVM compile time instrumentation passes and runtime libraries. Highlight of the most important aspects of the implementation: @@ -42,7 +42,7 @@ Highlight of the most important aspects of the implementation: The runtimes are [placed into target libdir][sanitizer-copy]. * During LLVM code generation, the functions intended for instrumentation are - [marked][sanitizer-attribute] with appropriate LLVM attribute: + [marked][sanitizer-attribute] with an appropriate LLVM attribute: `SanitizeAddress`, `SanitizeHWAddress`, `SanitizeMemory`, or `SanitizeThread`. By default, all functions are instrumented, but this behaviour can be changed with `#[sanitize(xyz = "on|off|")]`. @@ -57,7 +57,7 @@ Highlight of the most important aspects of the implementation: passes][sanitizer-pass], different for each sanitizer. Instrumentation passes are invoked after optimization passes. -* When producing an executable, the sanitizer specific runtime library is +* When producing an executable, the sanitizer-specific runtime library is [linked in][sanitizer-link]. The libraries are searched for in the target libdir. First, the search is relative to the overridden system root, and subsequently, @@ -83,7 +83,7 @@ Sanitizers are validated by code generation tests in [`tests/ui/sanitizer/`][test-ui] directory. Testing sanitizer functionality requires the sanitizer runtimes (built when -`build.sanitizer = true` in `bootstrap.toml`) and target providing support for particular a sanitizer. +`build.sanitizer = true` in `bootstrap.toml`) and a target providing support for particular a sanitizer. When a sanitizer is unsupported on a given target, sanitizer tests will be ignored. This behaviour is controlled by compiletest `needs-sanitizer-*` directives. diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index ae819003e1f3e..0e2f29f698cba 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -1,10 +1,9 @@ # Using tracing to debug the compiler -The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information -at many points. -These are very useful to at least narrow down the location of -a bug if not to find it entirely, or just to orient yourself as to why the -compiler is doing a particular thing. +The compiler has a lot of [`debug!`] (or `trace!`) calls, +which print out logging information at many points. +These are very useful to at least narrow down the location of a bug if not to find it entirely, +or just to orient yourself as to why the compiler is doing a particular thing. [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html @@ -66,8 +65,8 @@ RUSTC_LOG=rustc_borrowck[do_mir_borrowck] ### I don't want all calls -If you are compiling libcore, you likely don't want *all* borrowck dumps, but only one -for a specific function. +If you are compiling libcore, you likely don't want *all* borrowck dumps, +but only one for a specific function. You can filter function calls by their arguments by regexing them. ``` @@ -75,8 +74,8 @@ RUSTC_LOG=[do_mir_borrowck{id=\.\*from_utf8_unchecked\.\*}] ``` will only give you the logs of borrowchecking `from_utf8_unchecked`. -Note that you will -still get a short message per ignored `do_mir_borrowck`, but none of the things inside those calls. +Note that you will still get a short message per ignored `do_mir_borrowck`, +but none of the things inside those calls. This helps you in looking through the calls that are happening and helps you adjust your regex if you mistyped it. @@ -105,40 +104,39 @@ You can find a list of queries and their arguments in ## Broad module level filters -You can also use filters similar to the `log` crate's filters, which will enable -everything within a specific module. +You can also use filters similar to the `log` crate's filters, +which will enable everything within a specific module. This is often too verbose and too unstructured, so it is recommended to use function level filters. Your log filter can be just `debug` to get all `debug!` output and higher (e.g., it will also include `info!`), or `path::to::module` to get *all* -output (which will include `trace!`) from a particular module, or -`path::to::module=debug` to get `debug!` output and higher from a particular module. +output (which will include `trace!`) from a particular module, +or `path::to::module=debug` to get `debug!` output and higher from a particular module. -For example, to get the `debug!` output and higher for a specific module, you -can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. +For example, to get the `debug!` output and higher for a specific module, +you can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. All `debug!` output will then appear in standard error. Note that you can use a partial path and the filter will still work. -For example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, you could use -`RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use +For example, if you want to see `info!` output from only `rustdoc::passes::collect_intra_doc_links`, +you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing Miri, use `MIRI_LOG` instead. You get the idea :) -See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to -see the full syntax you can use. -(Note: unlike the compiler, the [`tracing`] -crate and its examples use the `RUSTC_LOG` environment variable. +See the [`tracing`] crate's docs, +and specifically the docs for [`debug!`] to see the full syntax you can use. +(Note: unlike the compiler, +the [`tracing`] crate and its examples use the `RUSTC_LOG` environment variable. rustc, rustdoc, and other tools set custom environment variables.) -**Note that unless you use a very strict filter, the logger will emit a lot of -output, so use the most specific module(s) you can (comma-separated if -multiple)**. It's typically a good idea to pipe standard error to a file and +**Note that unless you use a very strict filter, the logger will emit a lot of output, +so use the most specific module(s) you can (comma-separated if multiple)**. +It's typically a good idea to pipe standard error to a file and look at the log output with a text editor. So, to put it together: @@ -180,14 +178,13 @@ $ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs ## Log colors -By default, rustc (and other tools, like rustdoc and Miri) will be smart about -when to use ANSI colors in the log output. +By default, rustc (and other tools, +like rustdoc and Miri) will be smart about when to use ANSI colors in the log output. If they are outputting to a terminal, -they will use colors, and if they are outputting to a file or being piped -somewhere else, they will not. -However, it's hard to read log output in your -terminal unless you have a very strict filter, so you may want to pipe the -output to a pager like `less`. +they will use colors, and if they are outputting to a file or being piped somewhere else, +they will not. +However, it's hard to read log output in your terminal unless you have a very strict filter, +so you may want to pipe the output to a pager like `less`. But then there won't be any colors, which makes it hard to pick out what you're looking for! You can override whether to have colors in log output with the `RUSTC_LOG_COLOR` @@ -201,18 +198,18 @@ So, if you want to enable colors when piping to `less`, use something similar to $ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R ``` -Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs -from rustc functions that Miri calls. +Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, +not logs from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from rustc. ## How to keep or remove `debug!` and `trace!` calls from the resulting binary While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, -calls to `debug!` and `trace!` are only included in the program if -`rust.debug-logging=true` is turned on in bootstrap.toml (it is -turned off by default), so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see -`INFO` logs, make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. +calls to `debug!` and `trace!` are only included in the program if you have +`rust.debug-logging = true` in bootstrap.toml (it is turned off by default), +so if you don't see `DEBUG` logs, +especially if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, +make sure that `rust.debug-logging` is turned on in your bootstrap.toml. ## Logging etiquette and conventions @@ -220,11 +217,11 @@ Because calls to `debug!` are removed by default, in most cases, don't worry about the performance of adding "unnecessary" calls to `debug!` and leaving them in code you commit - they won't slow down the performance of what we ship. -That said, there can also be excessive tracing calls, especially -when they are redundant with other calls nearby or in functions called from here. +That said, there can also be excessive tracing calls, +especially when they are redundant with other calls nearby or in functions called from here. There is no perfect balance to hit here, and it is left to the reviewer's -discretion to decide whether to let you leave `debug!` statements in, or whether to ask -you to remove them before merging. +discretion to decide whether to let you leave `debug!` statements in, +or whether to ask you to remove them before merging. It may be preferable to use `trace!` over `debug!` for very noisy logs. @@ -243,8 +240,8 @@ If in the module `rustc::foo` you have a statement debug!(x = ?random_operation(tcx)); ``` -Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, then -`random_operation()` will run. +Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, +then `random_operation()` will run. `RUSTC_LOG` filters that do not enable this debug statement will not execute `random_operation`. This means that you should not put anything too expensive or likely to crash diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index ef2ea37b7ca46..887dd822e6b33 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -1,8 +1,8 @@ # The `ty` module: representing types The `ty` module defines how the Rust compiler represents types internally. -It also defines the -*typing context* (`tcx` or `TyCtxt`), which is the central data structure in the compiler. +It also defines the *typing context* (`tcx` or `TyCtxt`), +which is the central data structure in the compiler. ## `ty::Ty` @@ -22,12 +22,13 @@ The distinction is important, so we will discuss it first before going into the The HIR in rustc can be thought of as the high-level intermediate representation. It is more or less the AST (see [this chapter](hir.md)) as it represents the -syntax that the user wrote, and is obtained after parsing and some *desugaring*. It has a -representation of types, but in reality it reflects more of what the user wrote, that is, what they -wrote so as to represent that type. +syntax that the user wrote, and is obtained after parsing and some *desugaring*. +It has a representation of types, +but in reality, it reflects more of what the user wrote, +so as to represent that type. -In contrast, `ty::Ty` represents the semantics of a type, that is, the *meaning* of what the user -wrote. +In contrast, `ty::Ty` represents the semantics of a type; +that is, the *meaning* of what the user wrote. For example, `rustc_hir::Ty` would record the fact that a user used the name `u32` twice in their program, but the `ty::Ty` would record the fact that both usages refer to the same type. @@ -46,16 +47,16 @@ That is, they have two different [`Span`s][span] (locations). **Example: `fn foo(x: &u32) -> &u32`** In addition, HIR might have information left out. -This type -`&u32` is incomplete, since in the full Rust type there is actually a lifetime, but we didn’t need +This type `&u32` is incomplete, +since in the full Rust type there is actually a lifetime, but we didn’t need to write those lifetimes. There are also some elision rules that insert information. The result may look like `fn foo<'a>(x: &'a u32) -> &'a u32`. In the HIR level, these things are not spelled out and you can say the picture is rather incomplete. However, at the `ty::Ty` level, these details are added and it is complete. -Moreover, we will have -exactly one `ty::Ty` for a given type, like `u32`, and that `ty::Ty` is used for all `u32`s in the +Moreover, we will have exactly one `ty::Ty` for a given type, +like `u32`, and that `ty::Ty` is used for all `u32`s in the whole program, not a specific usage, unlike `rustc_hir::Ty`. Here is a summary: @@ -74,8 +75,8 @@ Here is a summary: HIR is built directly from the AST, so it happens before any `ty::Ty` is produced. After HIR is built, some basic type inference and type checking is done. -During the type inference, we -figure out what the `ty::Ty` of everything is and we also check if the type of something is +During the type inference, +we figure out what the `ty::Ty` of everything is and we also check if the type of something is ambiguous. The `ty::Ty` is then used for type checking while making sure everything has the expected type. The [`hir_ty_lowering` module][hir_ty_lowering] is where the code responsible for @@ -102,8 +103,8 @@ Consider another example: `fn foo(x: T) -> u32`. Suppose that someone invokes `foo::(0)`. This means that `T` and `u32` (in this invocation) actually turns out to be the same type, so we would eventually end up with the same `ty::Ty` in the end, but we have distinct `rustc_hir::Ty`. -(This is a bit over-simplified, though, since during type checking, we would check the function -generically and would still have a `T` distinct from `u32`. +(This is a bit over-simplified, though, since during type checking, +we would check the function generically and would still have a `T` distinct from `u32`. Later, when doing code generation, we would always be handling "monomorphized" (fully substituted) versions of each function, and hence we would know what `T` represents (and specifically that it is `u32`).) @@ -125,8 +126,8 @@ Here the type `X` will vary depending on context, clearly. If you look at the `rustc_hir::Ty`, you will get back that `X` is an alias in both cases (though it will be mapped via name resolution to distinct aliases). -But if you look at the `ty::Ty` signature, it will be either `fn(u32) -> u32` -or `fn(i32) -> i32` (with type aliases fully expanded). +But if you look at the `ty::Ty` signature, +it will be either `fn(u32) -> u32` or `fn(i32) -> i32` (with type aliases fully expanded). ## `ty::Ty` implementation @@ -140,8 +141,7 @@ We always hide them within `Ty` and skip over it via `Deref` impls or methods. They are convenient hacks for efficiency and summarize information about the type that we may want to know, but they don’t come into the picture as much here. -Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like -type. +Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like type. This allows us to do cheap comparisons for equality, along with the other benefits of interning. [tykind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html @@ -169,9 +169,9 @@ You can also find various common types in the `tcx` itself by accessing its fiel ## Comparing types -Because types are interned, it is possible to compare them for equality efficiently using `==` -– however, this is almost never what you want to do unless you happen to be hashing and looking -for duplicates. +Because types are interned, it is possible to compare them for equality efficiently using `==`. +However, this is almost never what you want to do, +unless you happen to be hashing and looking for duplicates. This is because often in Rust there are multiple ways to represent the same type, particularly once inference is involved. @@ -182,11 +182,11 @@ diagnostics code). `==` on them will return `false` though, since they are different types. The simplest way to compare two types correctly requires an inference context (`infcx`). -If you have one, you can use `infcx.can_eq(param_env, ty1, ty2)` -to check whether the types can be made equal. +If you have one, +you can use `infcx.can_eq(param_env, ty1, ty2)` to check whether the types can be made equal. This is typically what you want to check during diagnostics, which is concerned with questions such -as whether two types can be assigned to each other, not whether they're represented identically in -the compiler's type-checking layer. +as whether two types can be assigned to each other, +not whether they're represented identically in the compiler's type-checking layer. When working with an inference context, you have to be careful to ensure that potential inference variables inside the types actually belong to that inference context. @@ -199,24 +199,24 @@ To compare them correctly, you have to normalize the types first. This is primarily a concern during HIR type checking and with all types from a `TyCtxt` query (for example from `tcx.type_of()`). -When a `FnCtxt` or an `ObligationCtxt` is available during type checking, `.normalize(ty)` -should be used on them to normalize the type. +When a `FnCtxt` or an `ObligationCtxt` is available during type checking, +`.normalize(ty)` should be used on them to normalize the type. After type checking, diagnostics code can use `tcx.normalize_erasing_regions(ty)`. There are also cases where using `==` on `Ty` is fine. -This is, for example, the case in late lints -or after monomorphization, since type checking has been completed, meaning all inference variables +This is, for example, the case in late lints or after monomorphization, +since type checking has been completed, meaning all inference variables are resolved and all regions have been erased. -In these cases, if you know that inference variables -or normalization won't be a concern, `#[allow]` or `#[expect]`ing the lint is recommended. +In these cases, if you know that inference variables or normalization won't be a concern, +`#[allow]` or `#[expect]`ing the lint is recommended. When diagnostics code does not have access to an inference context, it should be threaded through the function calls if one is available in some place (like during type checking). -If no inference context is available at all, then one can be created as described in -[type-inference]. -But this is only useful when the involved types (for example, if -they came from a query like `tcx.type_of()`) are actually substituted with fresh +If no inference context is available at all, +then one can be created as described in [type-inference]. +But this is only useful when the involved types (for example, +if they came from a query like `tcx.type_of()`) are actually substituted with fresh inference variables using [`fresh_args_for_item`]. This can be used to answer questions like "can `Vec` for any `T` be unified with `Vec`?". @@ -237,8 +237,8 @@ fn foo(x: Ty<'tcx>) { } ``` -The `kind` field is of type `TyKind<'tcx>`, which is an enum defining all of the different kinds of -types in the compiler. +The `kind` field is of type `TyKind<'tcx>`, +which is an enum defining all of the different kinds of types in the compiler. > N.B. inspecting the `kind` field on types during type inference can be risky, as there may be > inference variables and other things to consider, or sometimes types are not yet known and will @@ -247,8 +247,8 @@ types in the compiler. There are a lot of related types, and we’ll cover them in time (e.g regions/lifetimes, “substitutions”, etc). -There are many variants on the `TyKind` enum, which you can see by looking at its -[documentation][tykind]. +There are many variants on the `TyKind` enum, +which you can see by looking at its [documentation][tykind]. Here is a sampling: - [**Algebraic Data Types (ADTs)**][kindadt] An [*algebraic data type*][wikiadt] is a `struct`, @@ -264,8 +264,8 @@ Here is a sampling: - [**Array**][kindarray] Corresponds to `[T; n]`. - [**RawPtr**][kindrawptr] Corresponds to `*mut T` or `*const T`. - [**Ref**][kindref] `Ref` stands for safe references, `&'a mut T` or `&'a T`. - `Ref` has some - associated parts, like `Ty<'tcx>` which is the type that the reference references. + `Ref` has some associated parts, + like `Ty<'tcx>`, which is the type that the reference references. `Region<'tcx>` is the lifetime or region of the reference and `Mutability` if the reference is mutable or not. - [**Param**][kindparam] Represents a type parameter (e.g. the `T` in `Vec`). @@ -314,15 +314,15 @@ which case the error should've been reported when that error type was produced). It's important to maintain this invariant because the whole point of the `Error` type is to suppress other errors -- i.e., we don't report them. If we were to produce an `Error` type without actually -emitting an error to the user, then this could cause later errors to be suppressed, and the -compilation might inadvertently succeed! +emitting an error to the user, then this could cause later errors to be suppressed, +and the compilation might inadvertently succeed! Sometimes there is a third case. You believe that an error has been reported, but you believe it would've been reported earlier in the compilation, not locally. In that case, you can create a "delayed bug" with [`delayed_bug`] or [`span_delayed_bug`]. -This will make a note that you expect -compilation to yield an error -- if, however, compilation should succeed, then it will trigger a +This will make a note that you expect compilation to yield an error -- if, +however, compilation should succeed, then it will trigger a compiler bug report. [`delayed_bug`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.delayed_bug diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 18897fbb5b8f0..0f5adb8b983e2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -4,10 +4,9 @@ use clippy_utils::sugg::Sugg; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; -use rustc_hir_typeck::cast::check_cast; +use rustc_hir_typeck::cast::{CastKind, check_cast}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_middle::ty::cast::CastKind; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index 3235627e9ca5f..c9e59f6f7eaa7 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -75,15 +75,21 @@ //@ [AIX] compile-flags: --target powerpc64-ibm-aix //@ [AIX] needs-llvm-components: powerpc +// NOTE: in clang <= 23 the Complex is passed incorrectly. +// See https://github.com/llvm/llvm-project/issues/212109. +//@ revisions: MIPS64 MIPS64EL +//@ [MIPS64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@ [MIPS64] needs-llvm-components: mips +//@ [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@ [MIPS64EL] needs-llvm-components: mips + // FIXME: the below revisions are deliberately disabled for now. // revisions: POWERPC // [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu // [POWERPC] needs-llvm-components: powerpc -// revisions: MIPS64EL MIPS -// [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 -// [MIPS64EL] needs-llvm-components: mips +// revisions: MIPS // [MIPS] compile-flags: --target mips-unknown-linux-gnu // [MIPS] needs-llvm-components: mips @@ -143,7 +149,8 @@ pub extern "C" fn cplx_f32(x: Complex) -> Complex { // I686: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval([8 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) // LOONGARCH64: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) - // MIPS64EL: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // MIPS64: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // MIPS64EL: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) // MIPS: define{{.*}} { float, float } @cplx_f32([2 x i32] {{.*}}) // NVPTX: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) // POWERPC64: define{{.*}} { float, float } @cplx_f32({ float, float } %0) @@ -177,7 +184,8 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { // I686: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) // LOONGARCH64: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) - // MIPS64EL: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // MIPS64: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // MIPS64EL: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) // MIPS: define{{.*}} { double, double } @cplx_f64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) // POWERPC64: define{{.*}} { double, double } @cplx_f64({ double, double } %0) @@ -202,6 +210,8 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { pub extern "C" fn cplx_f128(x: Complex) -> Complex { // AARCH64: define{{.*}} [2 x fp128] {{.*}}) // I686: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) + // MIPS64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, i32 %0, { fp128, fp128 } %1) + // MIPS64EL: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, i32 %0, { fp128, fp128 } %1) // SPARC: define{{.*}} inreg { fp128, fp128 } @cplx_f128(ptr {{.*}} dereferenceable(32) {{.*}}) // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) @@ -226,7 +236,8 @@ pub extern "C" fn cplx_i8(x: Complex) -> Complex { // I686: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval([2 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} i32 @cplx_i8(i32{{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i8(i64{{.*}}) - // MIPS64EL: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) + // MIPS64: define{{.*}} i16 @cplx_i8(i16 inreg {{.*}}) + // MIPS64EL: define{{.*}} i16 @cplx_i8(i16 inreg {{.*}}) // MIPS: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) // NVPTX: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) // POWERPC64: define{{.*}} { i8, i8 } @cplx_i8({ i8, i8 } %0) @@ -260,7 +271,8 @@ pub extern "C" fn cplx_i16(x: Complex) -> Complex { // I686: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval([4 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i16(i64{{.*}}) - // MIPS64EL: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) + // MIPS64: define{{.*}} i32 @cplx_i16(i32 inreg {{.*}}) + // MIPS64EL: define{{.*}} i32 @cplx_i16(i32 inreg {{.*}}) // MIPS: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) // NVPTX: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) // POWERPC64: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) @@ -294,7 +306,8 @@ pub extern "C" fn cplx_i32(x: Complex) -> Complex { // I686: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval([8 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) // LOONGARCH64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) - // MIPS64EL: define{{.*}} { i32, i32 } @cplx_i32(i64 {{.*}}) + // MIPS64: define{{.*}} i64 @cplx_i32(i64 inreg {{.*}}) + // MIPS64EL: define{{.*}} i64 @cplx_i32(i64 inreg {{.*}}) // MIPS: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i32, i32 } @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) // POWERPC64: define{{.*}} { i32, i32 } @cplx_i32({ i32, i32 } %0) @@ -328,7 +341,8 @@ pub extern "C" fn cplx_i64(x: Complex) -> Complex { // I686: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) - // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // MIPS64: define{{.*}} { i64, i64 } @cplx_i64(i128 {{.*}}) + // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i128 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i64, i64 } @cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) // POWERPC64: define{{.*}} { i64, i64 } @cplx_i64({ i64, i64 } %0) @@ -367,7 +381,8 @@ pub extern "C" fn wrapper_cplx_i64( // I686: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) - // MIPS64EL: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) + // MIPS64: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i128 {{.*}}) + // MIPS64EL: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i128 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { i64, i64 } @wrapper_cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) // POWERPC64: define{{.*}} { i64, i64 } @wrapper_cplx_i64({ i64, i64 } %0) diff --git a/tests/crashes/156101.rs b/tests/crashes/156101.rs deleted file mode 100644 index c95361fab2ecc..0000000000000 --- a/tests/crashes/156101.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #156101 -fn main() { - format_args!(concat!("𐏿", "{f:?#}")); -} diff --git a/tests/run-make/metrics-dir-crate-hash/lib.rs b/tests/run-make/metrics-dir-crate-hash/lib.rs new file mode 100644 index 0000000000000..e0673f64605f5 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/lib.rs @@ -0,0 +1,4 @@ +#![feature(ascii_char)] // random lib feature +#![feature(test_unstable_lint)] // random lang feature + +pub fn documented() {} diff --git a/tests/run-make/metrics-dir-crate-hash/main.rs b/tests/run-make/metrics-dir-crate-hash/main.rs new file mode 100644 index 0000000000000..844b362c9f179 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/main.rs @@ -0,0 +1,6 @@ +#![feature(ascii_char)] // random lib feature +#![feature(test_unstable_lint)] // random lang feature + +fn main() { + println!("foobar"); +} diff --git a/tests/run-make/metrics-dir-crate-hash/rmake.rs b/tests/run-make/metrics-dir-crate-hash/rmake.rs new file mode 100644 index 0000000000000..90e0b16859c04 --- /dev/null +++ b/tests/run-make/metrics-dir-crate-hash/rmake.rs @@ -0,0 +1,51 @@ +// Verifies that when a crate hash is required solely for a metrics dir, that +// crate hash is successfully generated, either by the fallback mechanism or +// metadata generation. +// See https://github.com/rust-lang/rust/issues/163426. + +//@ ignore-cross-compile + +use std::path::{Path, PathBuf}; + +use run_make_support::rfs::create_dir_all; +use run_make_support::{ + cwd, filename_contains, has_extension, run_in_tmpdir, rustc, rustdoc, shallow_find_files, +}; + +fn find_feature_usage_metrics>(dir: P) -> Vec { + shallow_find_files(dir, |path| { + filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") + }) +} + +fn main() { + let metrics_dir = "metrics-rustdoc"; + create_dir_all(&metrics_dir); + rustdoc() + .input("lib.rs") + .out_dir("doc") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir)) + .run() + .assert_stderr_not_contains("internal compiler error"); + assert_eq!( + find_feature_usage_metrics(&metrics_dir).len(), + 1, + "rustdoc should dump exactly one metrics file" + ); + + let metrics_dir = "metrics-rustc"; + create_dir_all(&metrics_dir); + rustc() + .input("main.rs") + .crate_type("bin") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir)) + .run() + .assert_stderr_not_contains("internal compiler error"); + assert_eq!( + find_feature_usage_metrics(&metrics_dir).len(), + 1, + "rustc should dump exactly one metrics file" + ); +} diff --git a/tests/ui/associated-types/associated-types-eq-hr.stderr b/tests/ui/associated-types/associated-types-eq-hr.stderr index 40a84eb25d384..70596cbab1225 100644 --- a/tests/ui/associated-types/associated-types-eq-hr.stderr +++ b/tests/ui/associated-types/associated-types-eq-hr.stderr @@ -43,58 +43,93 @@ LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>, error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | +LL | fn tuple_one() + | --------- due to a where-clause on `tuple_one`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ------------- unsatisfied where-clause on `tuple_one` +... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:104:5 | +LL | fn tuple_two() + | --------- due to a where-clause on `tuple_two`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_two` +... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:104:5 | +LL | fn tuple_two() + | --------- due to a where-clause on `tuple_two`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, + | ----------------------------------------------------------- unsatisfied where-clause on `tuple_two` +... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -130,19 +165,31 @@ LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:116:5 | +LL | fn tuple_four() + | ---------- due to a where-clause on `tuple_four`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>, + | -------------------------------------------- unsatisfied where-clause on `tuple_four` +... LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:116:5 | +LL | fn tuple_four() + | ---------- due to a where-clause on `tuple_four`... +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>, + | -------------------------------------------- unsatisfied where-clause on `tuple_four` +... LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr index 3048cc1d9c1c3..e7f5413cdaaa0 100644 --- a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr +++ b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr @@ -7,10 +7,15 @@ LL | | std::future::ready(x).await LL | | } | |_- this async fn captures a value whose type is not `Send` ... +LL | fn is_send(_: T) {} + | ------- ---- unsatisfied where-clause on `is_send` + | | + | due to a where-clause on `is_send`... +... LL | is_send(outer()) - | ^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...`Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr index 5a5bba352c69b..01b99e203c426 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `FnOnce` is not general enough --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 | +LL | fn send(_: T) {} + | ---- ---- unsatisfied where-clause on `send` + | | + | due to a where-clause on `send`... +... LL | / send(async { LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await LL | | }); - | |______^ implementation of `FnOnce` is not general enough + | |______^ | - = note: `fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...`fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` error: implementation of `FnOnce` is not general enough --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 | +LL | fn send(_: T) {} + | ---- ---- unsatisfied where-clause on `send` + | | + | due to a where-clause on `send`... +... LL | / send(async { LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await LL | | }); - | |______^ implementation of `FnOnce` is not general enough + | |______^ | - = note: `fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... + = note: ...`fn(&'0 ()) -> Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr index 63e71cbc40c75..fd91fd659ac4d 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr @@ -1,6 +1,11 @@ error: implementation of `Robot` is not general enough --> $DIR/higher-ranked-auto-trait-12.rs:31:20 | +LL | fn this_is_send(value: T) -> T { + | ------------ ---- unsatisfied where-clause on `this_is_send` + | | + | due to a where-clause on `this_is_send`... +... LL | let _my_task = this_is_send(async move { | ____________________^ LL | | let _my_iter = IRobot { @@ -9,9 +14,9 @@ LL | | robot: source, LL | | }; LL | | yield_now().await; LL | | }); - | |______^ implementation of `Robot` is not general enough + | |______^ | - = note: `Box<(dyn Robot + Send + '0)>` must implement `Robot`, for any lifetime `'0`... + = note: ...`Box<(dyn Robot + Send + '0)>` must implement `Robot`, for any lifetime `'0`... = note: ...but `Robot` is actually implemented for the type `Box<(dyn Robot + Send + 'static)>` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr index f69218740dcca..abc8ba5e7afa3 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr @@ -1,39 +1,58 @@ error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr index cfbdaa8ad4beb..7c8edb40ac62f 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr @@ -1,60 +1,88 @@ error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Callable` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...`Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Getter` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: ...`Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Callable` is not general enough --> $DIR/higher-ranked-auto-trait-13.rs:65:5 | +LL | fn assert_send(_: impl Send + Sync) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... + = note: ...`Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index e8d1f585f0256..fa6dd575527f8 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 | +LL | fn require_send(_x: T) {} + | ------------ ---- unsatisfied where-clause on `require_send` + | | + | due to a where-clause on `require_send`... +... LL | require_send(future); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 | +LL | fn require_send(_x: T) {} + | ------------ ---- unsatisfied where-clause on `require_send` + | | + | due to a where-clause on `require_send`... +... LL | require_send(future); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... + = note: ...closure with signature `fn(&'0 _) -> Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr index dc6183a45cef5..69e356703c9f0 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr index dc6183a45cef5..69e356703c9f0 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr @@ -1,23 +1,33 @@ error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` error: implementation of `AsyncFnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-16.rs:18:5 | +LL | fn assert_send(_: T) {} + | ----------- ---- unsatisfied where-clause on `assert_send` + | | + | due to a where-clause on `assert_send`... +... LL | / assert_send(async { LL | | commit_if_ok(&mut ctxt, async |_| todo!()).await; LL | | }); - | |______^ implementation of `AsyncFnOnce` is not general enough + | |______^ | - = note: `{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... + = note: ...`{async closure@...}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr index 8fa3c7483c89d..ef743392cb014 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr @@ -4,9 +4,15 @@ error: implementation of `Send` is not general enough LL | / assert_send(async { LL | | call_me.call().await; LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | pub fn assert_send(_future: F) + | ----------- due to a where-clause on `assert_send`... +LL | where +LL | F: Future + Send, + | ---- unsatisfied where-clause on `assert_send` | - = note: `Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`... + = note: ...`Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr index 6b434ecca0109..be635809f1db7 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr @@ -10,9 +10,15 @@ LL | | if !hc.check().await { LL | | log_health_check_failure().await; LL | | } LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | fn spawn(future: F) -> JoinHandle + | ----- due to a where-clause on `spawn`... +LL | where +LL | F: Future + Send + 'static, + | ---- unsatisfied where-clause on `spawn` | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...`Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` error: implementation of `Send` is not general enough @@ -27,9 +33,15 @@ LL | | if !hc.check().await { LL | | log_health_check_failure().await; LL | | } LL | | }); - | |______^ implementation of `Send` is not general enough + | |______^ +... +LL | fn spawn(future: F) -> JoinHandle + | ----- due to a where-clause on `spawn`... +LL | where +LL | F: Future + Send + 'static, + | ---- unsatisfied where-clause on `spawn` | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...`Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 7b840d54ed038..b5ea0003b1d63 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -2,9 +2,14 @@ error: implementation of `LoadQuery` is not general enough --> $DIR/implementation-not-general-enough-ice-133252.rs:9:9 | LL | force_send(async_load(¬_static)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `LoadQuery` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn force_send(_: T) {} + | ---------- ---- unsatisfied where-clause on `force_send` + | | + | due to a where-clause on `force_send`... | - = note: `LoadQuery<'0>` would have to be implemented for the type `&u8`, for any lifetime `'0`... + = note: ...`LoadQuery<'0>` would have to be implemented for the type `&u8`, for any lifetime `'0`... = note: ...but `LoadQuery<'1>` is actually implemented for the type `&'1 u8`, for some specific lifetime `'1` error[E0597]: `not_static` does not live long enough diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr index cdaa16ac9e807..3de229af2a077 100644 --- a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.current.stderr @@ -1,14 +1,20 @@ error: implementation of `Foo` is not general enough --> $DIR/obligation-with-leaking-placeholders.rs:18:5 | +LL | fn needs_foo(_: T) + | --------- due to a where-clause on `needs_foo`... +LL | where +LL | for<'a> Wrap: Foo<'a>, + | ------- unsatisfied where-clause on `needs_foo` +... LL | / needs_foo(|x| { LL | | LL | | LL | | x.to_string(); LL | | }); - | |______^ implementation of `Foo` is not general enough + | |______^ | - = note: `Wrap<{closure@...}>` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...`Wrap<{closure@...}>` must implement `Foo<'0>`, for any lifetime `'0`... = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr index 51691c35f795b..b918a5c5179c8 100644 --- a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr @@ -1,10 +1,16 @@ error: implementation of `FnOnce` is not general enough --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | +LL | fn inner(buf: &mut [u8], func: F) -> usize + | ----- due to a where-clause on `inner`... +LL | where +LL | F: FnOnce(&mut [u8]) -> Result, + | ----------------------------------------- unsatisfied where-clause on `inner` +... LL | inner(buf, outer_closure) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,12 +20,17 @@ LL | let outer_closure = |buf: &mut [u8]| { error: implementation of `FnOnce` is not general enough --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | +LL | fn inner(buf: &mut [u8], func: F) -> usize + | ----- due to a where-clause on `inner`... +LL | where +LL | F: FnOnce(&mut [u8]) -> Result, + | -------------------- unsatisfied where-clause on `inner` +... LL | inner(buf, outer_closure) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | let outer_closure = |buf: &mut [u8]| { diff --git a/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs new file mode 100644 index 0000000000000..30434569dbe73 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.rs @@ -0,0 +1,34 @@ +// Test for handling of duplicated attributes within `cfg_attr`, in particular the suggestions of +// what to remove. + +#[inline] +#[inline] +//~^ WARN unused attribute +//~| WARN this was previously accepted +fn f1() {} + +#[deprecated] +#[deprecated] +//~^ ERROR multiple `deprecated` attributes +fn f2() {} + +#[inline] +#[cfg_attr(true, inline)] +//~^ WARN unused attribute +//~| WARN this was previously accepted +fn f3() {} + +#[deprecated] +#[cfg_attr(true, deprecated)] +//~^ ERROR multiple `deprecated` attributes +fn f4() {} + +#[inline] +#[deprecated] +#[cfg_attr(true, inline, deprecated)] +//~^ WARN unused attribute +//~| WARN this was previously accepted +//~| ERROR multiple `deprecated` attributes +fn f5() {} + +fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr new file mode 100644 index 0000000000000..c30bc26b22ce7 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg-attr-duplicate-attrs.stderr @@ -0,0 +1,78 @@ +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:11:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:10:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:22:18 + | +LL | #[cfg_attr(true, deprecated)] + | ^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:21:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +error: multiple `deprecated` attributes + --> $DIR/cfg-attr-duplicate-attrs.rs:28:26 + | +LL | #[cfg_attr(true, inline, deprecated)] + | ^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:27:1 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:5:1 + | +LL | #[inline] + | ^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: requested on the command line with `-W unused-attributes` + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:16:18 + | +LL | #[cfg_attr(true, inline)] + | ^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:15:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: unused attribute + --> $DIR/cfg-attr-duplicate-attrs.rs:28:18 + | +LL | #[cfg_attr(true, inline, deprecated)] + | ^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/cfg-attr-duplicate-attrs.rs:26:1 + | +LL | #[inline] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 3 previous errors; 3 warnings emitted + diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs index 907e1b966766f..508b449358964 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs @@ -46,6 +46,9 @@ struct S12; //~| WARN previously accepted struct S13; +#[cfg_attr(true, cfg_attr(true, 3))] //~ ERROR expected identifier, found `3` +struct S14; + #[cfg_attr(true, inline())] //~ ERROR malformed `inline` attribute input fn f1() {} diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr index e901460a4eb88..048affd1c4191 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -120,6 +120,19 @@ LL - #[cfg_attr(true)] LL + #[cfg_attr(predicate, attr1, attr2, ...)] | +error: expected identifier, found `3` + --> $DIR/cfg_attr-attr-syntax-validation.rs:49:33 + | +LL | #[cfg_attr(true, cfg_attr(true, 3))] + | ^ expected identifier + | + = note: for more information, visit +help: must be of the form + | +LL - #[cfg_attr(true, cfg_attr(true, 3))] +LL + #[cfg_attr(true, cfg_attr(predicate, attr1, attr2, ...))] + | + error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable --> $DIR/cfg_attr-attr-syntax-validation.rs:30:30 | @@ -157,7 +170,7 @@ LL | #[cfg_attr(true, link_section = "name")] | ++++++++ error[E0805]: malformed `inline` attribute input - --> $DIR/cfg_attr-attr-syntax-validation.rs:49:18 + --> $DIR/cfg_attr-attr-syntax-validation.rs:52:18 | LL | #[cfg_attr(true, inline())] | ^^^^^^-- @@ -185,7 +198,7 @@ LL | #[cfg_attr(true, link_section)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` -error: aborting due to 13 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted Some errors have detailed explanations: E0539, E0565, E0805. For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index 75293b2f4a873..566f71d89c28d 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr @@ -1,13 +1,18 @@ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 | +LL | fn assert_foo(f: T) {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | let generator = #[coroutine] move || { | ------- this coroutine captures a value whose type is not `Foo` ... LL | assert_foo(generator); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...`&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error[E0626]: borrow may still be in use when coroutine yields @@ -45,13 +50,18 @@ LL | let generator = #[coroutine] static move || { error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:51:5 | +LL | fn assert_foo(f: T) {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | let generator = #[coroutine] move || { | ------- this coroutine captures a value whose type is not `Foo` ... LL | assert_foo(generator); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...`Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` error: aborting due to 4 previous errors diff --git a/tests/ui/coroutine/resume-arg-late-bound.stderr b/tests/ui/coroutine/resume-arg-late-bound.stderr index 0a6fb8dfcbb6c..bc1f1d29edd61 100644 --- a/tests/ui/coroutine/resume-arg-late-bound.stderr +++ b/tests/ui/coroutine/resume-arg-late-bound.stderr @@ -1,10 +1,15 @@ error: implementation of `Coroutine` is not general enough --> $DIR/resume-arg-late-bound.rs:15:5 | +LL | fn test(a: impl for<'a> Coroutine<&'a mut bool>) {} + | ---- ------------------------------- unsatisfied where-clause on `test` + | | + | due to a where-clause on `test`... +... LL | test(gen); - | ^^^^^^^^^ implementation of `Coroutine` is not general enough + | ^^^^^^^^^ | - = note: `{coroutine@...}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... + = note: ...`{coroutine@...}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`... = note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs b/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs new file mode 100644 index 0000000000000..51504607d2b61 --- /dev/null +++ b/tests/ui/fmt/format-args-concat-multibyte-suggestion.rs @@ -0,0 +1,38 @@ +// Regression test for #156101. +// +// When the format string comes from `concat!`, the parser's inner offsets are relative to the +// expanded string, not to the source, so they must not be turned into spans in the source. +// Before the fix, suggestions built from those offsets went wrong in two ways: +// +// - If the span landed inside a multibyte character, rendering the suggestion caused an ICE. +// The `ReorderFormatParameter` and `AddMissingColon` cases below are padded so that the span +// falls inside `é` (2 bytes) or `𐏿` (4 bytes). +// - If the span landed on unrelated source text, `UsePositional` suggested a bogus argument +// copied from that text. +// +// After the fix, no suggestion is emitted for these format strings. + +fn main() { + // The original reproducer from the issue. + format_args!(concat!("𐏿", "{f:?#}")); + //~^ ERROR invalid format string + + // `Suggestion::ReorderFormatParameter` + format_args!(concat!("é", "aaa{:?#}"), 1); + //~^ ERROR invalid format string + format_args!(concat!("𐏿", "a{:?#}"), 1); + //~^ ERROR invalid format string + + // `Suggestion::AddMissingColon` + format_args!(concat!("é", "aaaa{x?}")); + //~^ ERROR invalid format string + format_args!(concat!("𐏿", "aa{x?}")); + //~^ ERROR invalid format string + + // `Suggestion::UsePositional`: these did not ICE, but before the fix they suggested a bogus + // argument taken from the `concat!` invocation instead of from the format string. + format_args!(concat!("{}{a.b}", "")); + //~^ ERROR invalid format string + format_args!(concat!("{}{a.0}", "")); + //~^ ERROR invalid format string +} diff --git a/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr b/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr new file mode 100644 index 0000000000000..5eb8a4848a612 --- /dev/null +++ b/tests/ui/fmt/format-args-concat-multibyte-suggestion.stderr @@ -0,0 +1,52 @@ +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:17:18 + | +LL | format_args!(concat!("𐏿", "{f:?#}")); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:21:18 + | +LL | format_args!(concat!("é", "aaa{:?#}"), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `#` + --> $DIR/format-args-concat-multibyte-suggestion.rs:23:18 + | +LL | format_args!(concat!("𐏿", "a{:?#}"), 1); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string + +error: invalid format string: expected `}`, found `?` + --> $DIR/format-args-concat-multibyte-suggestion.rs:27:18 + | +LL | format_args!(concat!("é", "aaaa{x?}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `:` before `?` to format with `Debug` in format string + | + = note: to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `?` + --> $DIR/format-args-concat-multibyte-suggestion.rs:29:18 + | +LL | format_args!(concat!("𐏿", "aa{x?}")); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `:` before `?` to format with `Debug` in format string + | + = note: to print `{`, you can escape it using `{{` + +error: invalid format string: field access isn't supported + --> $DIR/format-args-concat-multibyte-suggestion.rs:34:18 + | +LL | format_args!(concat!("{}{a.b}", "")); + | ^^^^^^^^^^^^^^^^^^^^^^ not supported in format string + | + = note: consider moving this expression to a local variable and then using the local here instead + +error: invalid format string: tuple index access isn't supported + --> $DIR/format-args-concat-multibyte-suggestion.rs:36:18 + | +LL | format_args!(concat!("{}{a.0}", "")); + | ^^^^^^^^^^^^^^^^^^^^^^ not supported in format string + | + = note: consider moving this expression to a local variable and then using the local here instead + +error: aborting due to 7 previous errors + diff --git a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr index 8ae308303b8a3..42aa33c0be186 100644 --- a/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr +++ b/tests/ui/generic-associated-types/gat-bounds-not-checked-with-right-substitutions.stderr @@ -1,11 +1,22 @@ error: implementation of `Lengthen` is not general enough --> $DIR/gat-bounds-not-checked-with-right-substitutions.rs:20:20 | +LL | type Gat<'a>: for<'b> Lengthen>; + | --- ------------------------------- unsatisfied where-clause on `Gat::Gat` + | | + | due to a where-clause on `Gat::Gat`... +... LL | type Gat<'a> = &'a str; - | ^^^^^^^ implementation of `Lengthen` is not general enough + | ^^^^^^^ | - = note: `Lengthen<&'0 str>` would have to be implemented for the type `&'a str`, for any lifetime `'0`... + = note: ...`Lengthen<&'0 str>` would have to be implemented for the type `&'a str`, for any lifetime `'0`... = note: ...but `Lengthen<&'1 str>` is actually implemented for the type `&'1 str`, for some specific lifetime `'1` +note: required by a bound in `Gat::Gat` + --> $DIR/gat-bounds-not-checked-with-right-substitutions.rs:12:19 + | +LL | trait Gat { +LL | type Gat<'a>: for<'b> Lengthen>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Gat::Gat` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr b/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr index 19a63fb6fb6a6..7c3fcf47e6a40 100644 --- a/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr +++ b/tests/ui/higher-ranked/hr-fn-ptr-trait-impl-mismatch-29061.stderr @@ -1,28 +1,43 @@ error: implementation of `HR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:25:5 | +LL | fn hr(_: T) {} + | -- -- unsatisfied where-clause on `hr` + | | + | due to a where-clause on `hr`... +... LL | hr(not_hr_func); - | ^^^^^^^^^^^^^^^ implementation of `HR` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: `HR` would have to be implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`... + = note: ...`HR` would have to be implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`... = note: ...but `HR` is actually implemented for the type `for<'a> fn(&'a ())` error: implementation of `NotHR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:27:5 | +LL | fn not_hr(_: T) {} + | ------ ----- unsatisfied where-clause on `not_hr` + | | + | due to a where-clause on `not_hr`... +... LL | not_hr(hr_func); - | ^^^^^^^^^^^^^^^ implementation of `NotHR` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: `NotHR` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`NotHR` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `NotHR` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: implementation of `NotHR` is not general enough --> $DIR/hr-fn-ptr-trait-impl-mismatch-29061.rs:29:5 | +LL | fn not_hr(_: T) {} + | ------ ----- unsatisfied where-clause on `not_hr` + | | + | due to a where-clause on `not_hr`... +... LL | not_hr(hr_func2); - | ^^^^^^^^^^^^^^^^ implementation of `NotHR` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: `NotHR` would have to be implemented for the type `for<'b> fn(&'b ())` + = note: ...`NotHR` would have to be implemented for the type `for<'b> fn(&'b ())` = note: ...but `NotHR` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: aborting due to 3 previous errors diff --git a/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr index 40ac1d9d041be..eaa82c3f77871 100644 --- a/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr +++ b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr @@ -1,13 +1,19 @@ error: implementation of `DistributedIteratorMulti` is not general enough --> $DIR/hrtb-associated-type-leak-check-55731.rs:49:5 | +LL | fn multi(_reducer: I) + | ----- due to a where-clause on `multi`... +LL | where +LL | I: for<'a> DistributedIteratorMulti<&'a ()>, + | ---------------------------------------- unsatisfied where-clause on `multi` +... LL | / multi(Map { LL | | i: Cloned(PhantomData), LL | | f: X, LL | | }); - | |______^ implementation of `DistributedIteratorMulti` is not general enough + | |______^ | - = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... + = note: ...`DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr index c8d88b6243c4f..afed0bca3fffe 100644 --- a/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr +++ b/tests/ui/higher-ranked/hrtb-fn-ptr-impl-not-general-enough-57936.stderr @@ -14,10 +14,15 @@ LL | trait X { error: implementation of `X` is not general enough --> $DIR/hrtb-fn-ptr-impl-not-general-enough-57936.rs:26:5 | +LL | fn indirect() { + | -------- - unsatisfied where-clause on `indirect` + | | + | due to a where-clause on `indirect`... +... LL | indirect::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `X` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: `X` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`X` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr index 69c58c5919e11..830ed0638a80d 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr @@ -1,19 +1,29 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:27:10 | +LL | fn want_foo2() + | --------- due to a where-clause on `want_foo2`... +LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> + | -------------------------------------- unsatisfied where-clause on `want_foo2` +... LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `Foo` is not general enough --> $DIR/hrtb-conflate-regions.rs:27:10 | +LL | fn want_foo2() + | --------- due to a where-clause on `want_foo2`... +LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> + | -------------------------------------- unsatisfied where-clause on `want_foo2` +... LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...`SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr index 9697a270b8aa0..28ae64dff3e47 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-contravariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(&'b u32)>, + | -------------------------- unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(&'b u32)>` + = note: ...`()` must implement `Trait fn(&'b u32)>` = note: ...but it actually implements `Trait`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr index 385de795b18f0..4b9d7e1d7109e 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-covariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-covariant.rs:33:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(fn(&'b u32))>, + | ------------------------------ unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(fn(&'b u32))>` + = note: ...`()` must implement `Trait fn(fn(&'b u32))>` = note: ...but it actually implements `Trait`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr index cf64c2acdbe9c..45ff3ef758713 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-exists-forall-trait-invariant.stderr @@ -1,10 +1,16 @@ error: implementation of `Trait` is not general enough --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | +LL | fn foo() + | --- due to a where-clause on `foo`... +LL | where +LL | T: Trait fn(Cell<&'b u32>)>, + | -------------------------------- unsatisfied where-clause on `foo` +... LL | foo::<()>(); - | ^^^^^^^^^^^ implementation of `Trait` is not general enough + | ^^^^^^^^^^^ | - = note: `()` must implement `Trait fn(Cell<&'b u32>)>` + = note: ...`()` must implement `Trait fn(Cell<&'b u32>)>` = note: ...but it actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr index 697e85dc8c394..6ba3d119ccb94 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr @@ -1,10 +1,15 @@ error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:24:5 | +LL | fn want_hrtb() + | --------- due to a where-clause on `want_hrtb`... +LL | where T : for<'a> Foo<&'a isize> + | ---------------------- unsatisfied where-clause on `want_hrtb` +... LL | want_hrtb::() - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... + = note: ...`StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... = note: ...but it actually implements `Foo<&'static isize>` error: lifetime may not live long enough diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 327c0faa48287..db22eeb46aef0 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr @@ -56,10 +56,16 @@ LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 | +LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) + | ---------------- due to a where-clause on `foo_hrtb_bar_not`... +LL | where +LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, + | ---------------------- unsatisfied where-clause on `foo_hrtb_bar_not` +... LL | foo_hrtb_bar_not(&mut t); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... + = note: ...`T` must implement `Bar<&'0 isize>`, for any lifetime `'0`... = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1` warning: function cannot return without recursing diff --git a/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr index c50e79dd4cc48..e1d900f20ce3b 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-46989.stderr @@ -1,10 +1,15 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-46989.rs:38:5 | +LL | fn assert_foo() {} + | ---------- --- unsatisfied where-clause on `assert_foo` + | | + | due to a where-clause on `assert_foo`... +... LL | assert_foo::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a i32)` + = note: ...`Foo` would have to be implemented for the type `for<'a> fn(&'a i32)` = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index f8f64dcc545bc..f7b72ec65db3f 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr @@ -1,15 +1,14 @@ error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | / pub fn crash(v: &V) -LL | | where -LL | | for<'a> &'a V: Trait + 'static, - | |____________________-----__________- due to a where-clause on `crash`... - | | - | doesn't satisfy where-clause -LL | { -LL | v.t(|| {}); - | ^^^^^^^^^^ +LL | pub fn crash(v: &V) + | ----- due to a where-clause on `crash`... +LL | where +LL | for<'a> &'a V: Trait + 'static, + | ----- unsatisfied where-clause on `crash` +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` @@ -17,15 +16,14 @@ LL | v.t(|| {}); error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | / pub fn crash(v: &V) -LL | | where -LL | | for<'a> &'a V: Trait + 'static, - | |____________________-----__________- due to a where-clause on `crash`... - | | - | doesn't satisfy where-clause -LL | { -LL | v.t(|| {}); - | ^^^^^^^^^^ +LL | pub fn crash(v: &V) + | ----- due to a where-clause on `crash`... +LL | where +LL | for<'a> &'a V: Trait + 'static, + | ----- unsatisfied where-clause on `crash` +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 3c6aab12bf137..fa524168e12e7 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -1,10 +1,16 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | --------------------------------------- unsatisfied where-clause on `foo` +... LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,12 +20,17 @@ LL | foo(bar, "string", |s: &&str| s.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | ---- unsatisfied where-clause on `foo` +... LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | foo(bar, "string", |s: &&str| s.len() == 5); @@ -28,10 +39,16 @@ LL | foo(bar, "string", |s: &&str| s.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | --------------------------------------- unsatisfied where-clause on `foo` +... LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,12 +58,17 @@ LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 | +LL | fn foo( + | --- due to a where-clause on `foo`... +... +LL | F2: FnOnce(&::Output) -> bool + | ---- unsatisfied where-clause on `foo` +... LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index db623761b268e..18960ff575a2a 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` help: consider adding explicit type annotations to the closure's arguments | @@ -14,10 +19,15 @@ LL | let f = | _: &u32 , y: &u32 , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding explicit type annotations to the closure's arguments @@ -28,10 +38,15 @@ LL | let f = | _: &u32 , y: &u32 , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,10 +56,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -54,10 +74,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -68,10 +93,15 @@ LL | let f = | x: &u32, y: _ , z: u32 | (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 | +LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {} + | ----- ----------------------- unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 9993de99b9e48..7029eeafef0eb 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187-2.rs:8:5 | +LL | fn take_foo(_: impl Foo) {} + | -------- --- unsatisfied where-clause on `take_foo` + | | + | due to a where-clause on `take_foo`... +... LL | take_foo(|a| a); - | ^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | take_foo(|a: &i32| a); error: implementation of `Fn` is not general enough --> $DIR/issue-79187-2.rs:8:5 | +LL | fn take_foo(_: impl Foo) {} + | -------- --- unsatisfied where-clause on `take_foo` + | | + | due to a where-clause on `take_foo`... +... LL | take_foo(|a| a); - | ^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index e08400481e470..3dbb6054a7ad3 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ----- ------------ unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | let f = |_: &u32| (); error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ----- ------------ unsatisfied where-clause on `thing` + | | + | due to a where-clause on `thing`... +... LL | thing(f); - | ^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^ | - = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr index 4dada6ff014ad..3a293cc4b2516 100644 --- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -45,19 +45,27 @@ LL | fn g(data: &[T]) { error: implementation of `Fn` is not general enough --> $DIR/issue_74400.rs:12:5 | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | - ----------- unsatisfied where-clause on `f` + | | + | due to a where-clause on `f`... +... LL | f(data, identity) - | ^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `Fn<(&'1 T,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `Fn<(&'1 T,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 T,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough --> $DIR/issue_74400.rs:12:5 | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | - due to a where-clause on `f`... - unsatisfied where-clause on `f` +... LL | f(data, identity) - | ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `FnOnce<(&'1 T,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 T,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr index ab52f3d3ee43e..856aba98d1c4c 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -66,19 +66,29 @@ LL | fn baz(_: F) {} error: implementation of `Fn` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | --- ------------- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); - | ^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^ | - = note: `fn(*mut &'2 u32)` must implement `Fn<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...`fn(*mut &'2 u32)` must implement `Fn<(*mut &'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(*mut &'2 u32,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | --- ------------- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); - | ^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^ | - = note: `fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... + = note: ...`fn(*mut &'2 u32)` must implement `FnOnce<(*mut &'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(*mut &'2 u32,)>`, for some specific lifetime `'2` error: aborting due to 6 previous errors diff --git a/tests/ui/mismatched_types/closure-mismatch.current.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr index 82e3e4b0f78f2..0dbefa4b2aa19 100644 --- a/tests/ui/mismatched_types/closure-mismatch.current.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:12:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|_| ()); - | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | baz(|_: &()| ()); error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:12:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|_| ()); - | ^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -27,10 +37,15 @@ LL | baz(|_: &()| ()); error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:16:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|x| ()); - | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -40,10 +55,15 @@ LL | baz(|x: &()| ()); error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:16:5 | +LL | fn baz(_: T) {} + | --- --- unsatisfied where-clause on `baz` + | | + | due to a where-clause on `baz`... +... LL | baz(|x| ()); - | ^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index 45dd1557dd027..60f155eb45eb1 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -2,9 +2,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... | - = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` help: consider adding an explicit type annotation to the closure's argument | @@ -15,9 +20,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... | - = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -69,11 +79,17 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + --> $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: due to a where-clause on `Rc`... + ::: $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: unsatisfied where-clause on `Rc` + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -83,11 +99,17 @@ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + --> $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: due to a where-clause on `Rc`... + ::: $SRC_DIR/alloc/src/rcs/rc.rs:LL:COL + | + = note: unsatisfied where-clause on `Rc` + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -97,11 +119,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) @@ -111,11 +137,15 @@ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 | LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough - | - = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct B(Rc); + | - - unsatisfied where-clause on `B` + | | + | due to a where-clause on `B`... + | + = note: ...closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) diff --git a/tests/ui/nll/issue-54302-cases.stderr b/tests/ui/nll/issue-54302-cases.stderr index 6e8b69c4beebb..4c5535258f624 100644 --- a/tests/ui/nll/issue-54302-cases.stderr +++ b/tests/ui/nll/issue-54302-cases.stderr @@ -1,37 +1,49 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:63:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...`Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... + = note: ...`Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... + = note: ...`Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 | +LL | fn ref_foo(&self) -> &'static T; + | ------- due to a where-clause on `RefFoo::ref_foo`... +... LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `RefFoo::ref_foo` | - = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... + = note: ...`Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1` error: aborting due to 4 previous errors diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index d8922ef80e813..f0f407afd7601 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | fn accept(_: C) -> Handshake> { + | ------ ----------- unsatisfied where-clause on `accept` + | | + | due to a where-clause on `accept`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -14,10 +19,15 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | fn accept(_: C) -> Handshake> { + | ------ ----------- unsatisfied where-clause on `accept` + | | + | due to a where-clause on `accept`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument @@ -28,12 +38,16 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | struct Handshake { + | --------- ---- unsatisfied where-clause on `Handshake` + | | + | due to a where-clause on `Handshake`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument | LL | let callback = |_: &()| {}; @@ -42,10 +56,15 @@ LL | let callback = |_: &()| {}; error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 | +LL | struct Handshake { + | --------- ---- unsatisfied where-clause on `Handshake` + | | + | due to a where-clause on `Handshake`... +... LL | accept(callback); - | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^ | - = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider adding an explicit type annotation to the closure's argument diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 46e4fbea0d952..2e164c9b3abb7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -28,9 +28,14 @@ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- -------------- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,9 +46,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- --- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 46e4fbea0d952..2e164c9b3abb7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -28,9 +28,14 @@ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `Fn` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- -------------- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | @@ -41,9 +46,14 @@ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:14:5 | LL | bad(&b); - | ^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^ +... +LL | fn bad &()>(_: F) {} + | --- --- unsatisfied where-clause on `bad` + | | + | due to a where-clause on `bad`... | - = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... + = note: ...closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` help: consider adding an explicit type annotation to the closure's argument | diff --git a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr index 804071a3e6f77..ced5c4b8058b0 100644 --- a/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr +++ b/tests/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr @@ -1,21 +1,26 @@ error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 | +LL | fn make_f() -> Self::F; + | ------ due to a where-clause on `Y::make_f`... +... LL | let _x = ::make_f(); - | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough + | ^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `Y::make_f` | - = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 | +LL | trait Y { + | - due to a where-clause on `Y`... +... LL | let _x = ::make_f(); - | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough + | ^^^^^^^^^^^^^^^^^^^ unsatisfied where-clause on `Y` | - = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` + = note: ...`Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Y` is not general enough --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 @@ -25,7 +30,6 @@ LL | let _x = ::make_f(); | = note: `Y` would have to be implemented for the type `for<'a> fn(&'a ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 3 previous errors diff --git a/tests/ui/no_std/no-std-no-start-binary.stderr b/tests/ui/no_std/no-std-no-start-binary.stderr index dd06c234da294..bc6ded80ff8fe 100644 --- a/tests/ui/no_std/no-std-no-start-binary.stderr +++ b/tests/ui/no_std/no-std-no-start-binary.stderr @@ -1,6 +1,6 @@ error: using `fn main` requires the standard library | - = help: use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` + = help: use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[unsafe(no_mangle)]` error: aborting due to 1 previous error diff --git a/tests/ui/reborrow/reborrow-drop.rs b/tests/ui/reborrow/reborrow-drop.rs new file mode 100644 index 0000000000000..bc88bb79b9b4b --- /dev/null +++ b/tests/ui/reborrow/reborrow-drop.rs @@ -0,0 +1,14 @@ +//@ compile-flags: --crate-type=lib + +#![feature(reborrow)] + +use std::marker::Reborrow; + +struct MyMut<'a>(&'a mut ()); + +impl Reborrow for MyMut<'_> {} +//~^ ERROR the trait `Reborrow` cannot be implemented for this type; the type has a destructor [E0184] + +impl Drop for MyMut<'_> { + fn drop(&mut self) {} +} diff --git a/tests/ui/reborrow/reborrow-drop.stderr b/tests/ui/reborrow/reborrow-drop.stderr new file mode 100644 index 0000000000000..d35b36530d588 --- /dev/null +++ b/tests/ui/reborrow/reborrow-drop.stderr @@ -0,0 +1,15 @@ +error[E0184]: the trait `Reborrow` cannot be implemented for this type; the type has a destructor + --> $DIR/reborrow-drop.rs:9:1 + | +LL | impl Reborrow for MyMut<'_> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Reborrow` not allowed on types with destructors + | +note: destructor declared here + --> $DIR/reborrow-drop.rs:13:5 + | +LL | fn drop(&mut self) {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0184`. diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr index 9853be2a7f8e0..3573ee48db57c 100644 --- a/tests/ui/sized-hierarchy/overflow.current.stderr +++ b/tests/ui/sized-hierarchy/overflow.current.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `Element: MetaSized` - --> $DIR/overflow.rs:17:16 + --> $DIR/overflow.rs:15:16 | LL | struct Element(> as ParseTokens>::Output); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required for `Box` to implement `ParseTokens` - --> $DIR/overflow.rs:13:31 + --> $DIR/overflow.rs:11:31 | LL | impl ParseTokens for Box { | ------ ^^^^^^^^^^^ ^^^^^^ @@ -15,25 +15,25 @@ LL | impl ParseTokens for Box { = note: required for `Box>` to implement `ParseTokens` error[E0275]: overflow evaluating the requirement `Box: ParseTokens` - --> $DIR/overflow.rs:19:22 + --> $DIR/overflow.rs:18:22 | LL | impl ParseTokens for Element { | ^^^^^^^ | note: required for `Box>` to implement `ParseTokens` - --> $DIR/overflow.rs:13:31 + --> $DIR/overflow.rs:11:31 | LL | impl ParseTokens for Box { | ----------- ^^^^^^^^^^^ ^^^^^^ | | | unsatisfied trait bound introduced here note: required because it appears within the type `Element` - --> $DIR/overflow.rs:17:8 + --> $DIR/overflow.rs:15:8 | LL | struct Element(> as ParseTokens>::Output); | ^^^^^^^ note: required by a bound in `ParseTokens` - --> $DIR/overflow.rs:10:1 + --> $DIR/overflow.rs:8:1 | LL | / trait ParseTokens { LL | | type Output; diff --git a/tests/ui/sized-hierarchy/overflow.next.stderr b/tests/ui/sized-hierarchy/overflow.next.stderr new file mode 100644 index 0000000000000..69842a298f87f --- /dev/null +++ b/tests/ui/sized-hierarchy/overflow.next.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `> as ParseTokens>::Output == _` + --> $DIR/overflow.rs:15:16 + | +LL | struct Element(> as ParseTokens>::Output); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating whether `> as ParseTokens>::Output` is well-formed + --> $DIR/overflow.rs:15:16 + | +LL | struct Element(> as ParseTokens>::Output); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `Element: MetaSized` + --> $DIR/overflow.rs:18:22 + | +LL | impl ParseTokens for Element { + | ^^^^^^^ + | +note: required by a bound in `ParseTokens` + --> $DIR/overflow.rs:8:1 + | +LL | / trait ParseTokens { +LL | | type Output; +LL | | } + | |_^ required by this bound in `ParseTokens` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs index 31c2ca8a49171..f69f56ef898e2 100644 --- a/tests/ui/sized-hierarchy/overflow.rs +++ b/tests/ui/sized-hierarchy/overflow.rs @@ -1,8 +1,6 @@ //@ compile-flags: --crate-type=lib //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] check-fail -//@[next] check-pass //@[next] compile-flags: -Znext-solver use std::marker::PhantomData; @@ -15,8 +13,9 @@ impl ParseTokens for Box { } struct Element(> as ParseTokens>::Output); -//[current]~^ ERROR: overflow +//~^ ERROR: overflow +//[next]~| ERROR: overflow impl ParseTokens for Element { -//[current]~^ ERROR: overflow +//~^ ERROR: overflow type Output = (); } diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr index 89b8b53c3f4d9..d6cd080cbfd0b 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.current.stderr @@ -1,18 +1,18 @@ error[E0275]: overflow evaluating the requirement `u32: SendIndir>` - --> $DIR/only-one-coinductive-step-needed-trait.rs:24:5 + --> $DIR/only-one-coinductive-step-needed-trait.rs:25:5 | LL | is_send::>(); | ^^^^^^^^^^^^^^^^^^^^^ | note: required for `Foo` to implement `Send` - --> $DIR/only-one-coinductive-step-needed-trait.rs:17:35 + --> $DIR/only-one-coinductive-step-needed-trait.rs:18:35 | LL | unsafe impl>> Send for Foo {} | ----------------- ^^^^ ^^^^^^ | | | unsatisfied trait bound introduced here note: required by a bound in `is_send` - --> $DIR/only-one-coinductive-step-needed-trait.rs:22:15 + --> $DIR/only-one-coinductive-step-needed-trait.rs:23:15 | LL | fn is_send() {} | ^^^^ required by this bound in `is_send` diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr new file mode 100644 index 0000000000000..40ae37e495204 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.next.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `Foo: Send` + --> $DIR/only-one-coinductive-step-needed-trait.rs:25:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by a bound in `is_send` + --> $DIR/only-one-coinductive-step-needed-trait.rs:23:15 + | +LL | fn is_send() {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs index 294156869284a..a8d23129fb87c 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed-trait.rs @@ -1,7 +1,6 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass // #136824 changed cycles to be coinductive if they have at least // one productive step, causing this test to pass with the new solver. @@ -12,6 +11,8 @@ // - `Foo: Send` cycle // // The old solver treats this cycle as inductive due to the `T: SendIndir` step. +// We later changed the new solver to temporarily be closer to the old solver +// again, so this now errors with both solvers. struct Foo(T); unsafe impl>> Send for Foo {} @@ -23,4 +24,5 @@ fn is_send() {} fn main() { is_send::>(); //[current]~^ ERROR overflow evaluating the requirement `u32: SendIndir>` + //[next]~^^ ERROR overflow evaluating the requirement `Foo: Send` } diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr index ec21987805869..1d7916f32b1db 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.current.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `Foo: SendIndir` - --> $DIR/only-one-coinductive-step-needed.rs:17:15 + --> $DIR/only-one-coinductive-step-needed.rs:18:15 | LL | struct Foo( as Trait>::Assoc); | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: required for `Foo` to implement `Trait` - --> $DIR/only-one-coinductive-step-needed.rs:26:20 + --> $DIR/only-one-coinductive-step-needed.rs:29:20 | LL | impl Trait for T { | --------- ^^^^^ ^ diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr new file mode 100644 index 0000000000000..071945d760345 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.next.stderr @@ -0,0 +1,43 @@ +error[E0275]: overflow evaluating the requirement ` as Trait>::Assoc == _` + --> $DIR/only-one-coinductive-step-needed.rs:18:15 + | +LL | struct Foo( as Trait>::Assoc); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating whether ` as Trait>::Assoc` is well-formed + --> $DIR/only-one-coinductive-step-needed.rs:18:15 + | +LL | struct Foo( as Trait>::Assoc); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `Foo: Send` + --> $DIR/only-one-coinductive-step-needed.rs:36:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by a bound in `is_send` + --> $DIR/only-one-coinductive-step-needed.rs:33:15 + | +LL | fn is_send() {} + | ^^^^ required by this bound in `is_send` + +error[E0275]: overflow evaluating the requirement `Foo: Sized` + --> $DIR/only-one-coinductive-step-needed.rs:36:15 + | +LL | is_send::>(); + | ^^^^^^^^ + | +note: required by an implicit `Sized` bound in `is_send` + --> $DIR/only-one-coinductive-step-needed.rs:33:12 + | +LL | fn is_send() {} + | ^ required by the implicit `Sized` requirement on this type parameter in `is_send` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn is_send() {} + | ++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs index e41f7d7f3ceb3..9a13c0e945339 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/only-one-coinductive-step-needed.rs @@ -1,7 +1,6 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass // #136824 changed cycles to be coinductive if they have at least // one productive step, causing this test to pass with the new solver. @@ -12,10 +11,14 @@ // - `Foo: SendIndir`, via impl requires // - `Foo: Send` cycle // -// The old solver treats this cycle as inductive due to the `Foo: SendIndir` step. +// The old solver treats this cycle as inductive due to the `Foo: SendIndir` step. We've +// since changed the new solver to more closely match the old one here, also +// resulting in an inductive cycle for now. struct Foo( as Trait>::Assoc); -//[current]~^ ERROR overflow evaluating the requirement `Foo: SendIndir` +//[current]~^ ERROR: overflow evaluating the requirement `Foo: SendIndir` +//[next]~^^ ERROR: overflow evaluating the requirement ` as Trait>::Assoc == _` +//[next]~| ERROR: overflow evaluating whether ` as Trait>::Assoc` is well-formed trait SendIndir {} impl SendIndir for T {} @@ -31,4 +34,6 @@ fn is_send() {} fn main() { is_send::>(); + //[next]~^ ERROR: overflow evaluating the requirement `Foo: Send` + //[next]~| ERROR: overflow evaluating the requirement `Foo: Sized` } diff --git a/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr new file mode 100644 index 0000000000000..477b0ba993104 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.current.stderr @@ -0,0 +1,26 @@ +error[E0275]: overflow evaluating the requirement `Foo<'_>: Send` + --> $DIR/cycle-requires-resolving-regions.rs:31:5 + | +LL | require::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_requires_resolving_regions`) +note: required for `Foo<'_>` to implement `Send` + --> $DIR/cycle-requires-resolving-regions.rs:23:17 + | +LL | unsafe impl<'a> Send for Foo<'a> + | ^^^^ ^^^^^^^ +LL | where +LL | Foo<'a>: Send, + | ---- unsatisfied trait bound introduced here + = note: 128 redundant requirements hidden + = note: required for `Foo<'static>` to implement `Send` +note: required by a bound in `require` + --> $DIR/cycle-requires-resolving-regions.rs:28:15 + | +LL | fn require() {} + | ^^^^ required by this bound in `require` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs new file mode 100644 index 0000000000000..2e1eaff4b9479 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-requires-resolving-regions.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +// A test showcasing a behavior change in cycle detection between +// the old and new solver. The old solver detects cycles in both +// fulfill and in evaluate. The cycle detection in fulfillment +// does not resolve regions. Each occurance of the `Foo<'a>: Send` +// impl creates a fresh inference variable even if it is later +// constrainted to `'static`. This means we never detect a cycle. +// +// This is not an issue with builtin auto-trait impls as they don't +// create impl args instead, simply using the generic arguments of +// the self type directly. +// +// The new solver properly resolves regions. The old solver does resolve +// regions in `project`, so there we do detect cycles even if there are +// fresh region variables. + +struct Foo<'a>(&'a ()); + +unsafe impl<'a> Send for Foo<'a> +where + Foo<'a>: Send, +{} + +fn require() {} + +fn main() { + require::>(); + //[current]~^ ERROR: overflow evaluating the requirement `Foo<'_>: Send` +} diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr index f0bb77cfe4c8c..2703d276e41f7 100644 --- a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr +++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr @@ -6,6 +6,11 @@ LL | fn main() -> Thing { Thing } | = note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`... = note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` +note: required for `Thing` to implement `Termination` + --> $DIR/main-termination-lifetime-issue-148421.rs:13:6 + | +LL | impl Termination for Thing where for<'a> &'a (): IsStatic { + | ^^^^^^^^^^^ ^^^^^ -------- unsatisfied trait bound introduced here error: aborting due to 1 previous error diff --git a/tests/ui/unboxed-closures/issue-30906.stderr b/tests/ui/unboxed-closures/issue-30906.stderr index 0815ae1fb5a2b..fa61b3af02cf0 100644 --- a/tests/ui/unboxed-closures/issue-30906.stderr +++ b/tests/ui/unboxed-closures/issue-30906.stderr @@ -1,10 +1,15 @@ error: implementation of `FnOnce` is not general enough --> $DIR/issue-30906.rs:18:5 | +LL | fn test FnOnce<(&'x str,)>>(_: F) {} + | ---- -------------------------- unsatisfied where-clause on `test` + | | + | due to a where-clause on `test`... +... LL | test(Compose(f, |_| {})); - | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... + = note: ...`fn(&'2 str) -> T` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2` error: aborting due to 1 previous error diff --git a/tests/ui/where-clauses/where-for-self-2.stderr b/tests/ui/where-clauses/where-for-self-2.stderr index f479210772194..378616d9aca57 100644 --- a/tests/ui/where-clauses/where-for-self-2.stderr +++ b/tests/ui/where-clauses/where-for-self-2.stderr @@ -1,10 +1,16 @@ error: implementation of `Bar` is not general enough --> $DIR/where-for-self-2.rs:23:5 | +LL | fn foo(x: &T) + | --- due to a where-clause on `foo`... +LL | where +LL | for<'a> &'a T: Bar, + | --- unsatisfied where-clause on `foo` +... LL | foo(&X); - | ^^^^^^^ implementation of `Bar` is not general enough + | ^^^^^^^ | - = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`... + = note: ...`&'0 u32` must implement `Bar`, for any lifetime `'0`... = note: ...but `Bar` is actually implemented for the type `&'static u32` error: aborting due to 1 previous error diff --git a/triagebot.toml b/triagebot.toml index 611f7724f5cae..77acf0edda0a6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -707,6 +707,16 @@ message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all f message_on_close = "Issue #{number} has been closed. Thanks for participating!" message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*." +[notify-zulip."I-libs-nominated"] +zulip_stream = 639962 # #t-libs/nominated +topic = "#{number}: {title}" +message_on_add = """\ +[#{number} "{title}"](https://github.com/rust-lang/rust/pull/{number}) has been nominated for discussion. +""" +message_on_remove = """\ +#{number} is no longer nominated. +""" + # ------------------------------------------------------------------------------ # Zulip notifications