diff options
210 files changed, 2313 insertions, 1734 deletions
diff --git a/RELEASES.md b/RELEASES.md index ac72a1d885c..40ddba6dbc5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -68,15 +68,15 @@ Stabilized APIs - [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E) - [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E) - [`Rc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit) -- [`Rc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) +- [`Rc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) - [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice) - [`Rc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1) - [`Arc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit) -- [`Arc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) +- [`Arc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) - [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice) - [`Arc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1) - [`Box<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit) -- [`Box<T>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) +- [`Box<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) - [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice) - [`Box<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1) - [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 02cb6f188a7..8e4f4c8e71a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity { } /// The polarity of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundPolarity { /// `Type: Trait` @@ -2719,7 +2719,7 @@ impl BoundPolarity { } /// The constness of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundConstness { /// `Type: Trait` diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 88cdb2ec363..6585a7de245 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::LoongArch64 ); - if !is_stable && !self.tcx.features().asm_experimental_arch { + if !is_stable && !self.tcx.features().asm_experimental_arch() { feature_err( &self.tcx.sess, sym::asm_experimental_arch, @@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp }); } - if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { + if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() { feature_err( &self.tcx.sess, sym::asm_unwind, @@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Label { block } => { - if !self.tcx.features().asm_goto { + if !self.tcx.features().asm_goto() { feature_err( sess, sym::asm_goto, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ae1e1b3f8a2..a1a16d0ca26 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -575,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { // Either `body.is_none()` or `is_never_pattern` here. if !is_never_pattern { - if self.tcx.features().never_patterns { + if self.tcx.features().never_patterns() { // If the feature is off we already emitted the error after parsing. let suggestion = span.shrink_to_hi(); self.dcx().emit_err(MatchArmWithNoBody { span, suggestion }); @@ -717,7 +717,7 @@ impl<'hir> LoweringContext<'_, 'hir> { outer_hir_id: HirId, inner_hir_id: HirId, ) { - if self.tcx.features().async_fn_track_caller + if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) { @@ -1572,7 +1572,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); } Some(hir::CoroutineKind::Coroutine(_)) => { - if !self.tcx.features().coroutines { + if !self.tcx.features().coroutines() { rustc_session::parse::feature_err( &self.tcx.sess, sym::coroutines, @@ -1584,7 +1584,7 @@ impl<'hir> LoweringContext<'_, 'hir> { false } None => { - if !self.tcx.features().coroutines { + if !self.tcx.features().coroutines() { rustc_session::parse::feature_err( &self.tcx.sess, sym::coroutines, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7416a1e39eb..c43106c6e5f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1512,7 +1512,7 @@ impl<'hir> LoweringContext<'_, 'hir> { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param && !self.tcx.features().more_maybe_bounds { + if !is_param && !self.tcx.features().more_maybe_bounds() { self.tcx .sess .create_feature_err( @@ -1530,7 +1530,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let host_param_parts = if let Const::Yes(span) = constness // if this comes from implementing a `const` trait, we must force constness to be appended // to the impl item, no matter whether effects is enabled. - && (self.tcx.features().effects || force_append_constness) + && (self.tcx.features().effects() || force_append_constness) { let span = self.lower_span(span); let param_node_id = self.next_node_id(); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4d8d22e09d9..7cd0cd1ebcd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -193,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), - allow_gen_future: if tcx.features().async_fn_track_caller { + allow_gen_future: if tcx.features().async_fn_track_caller() { [sym::gen_future, sym::closure_track_caller].into() } else { [sym::gen_future].into() @@ -1035,7 +1035,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span, }) }; - if !self.tcx.features().return_type_notation + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -1160,7 +1160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), ast::GenericArg::Type(ty) => { match &ty.kind { - TyKind::Infer if self.tcx.features().generic_arg_infer => { + TyKind::Infer if self.tcx.features().generic_arg_infer() => { return GenericArg::Infer(hir::InferArg { hir_id: self.lower_node_id(ty.id), span: self.lower_span(ty.span), @@ -1500,7 +1500,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // is enabled. We don't check the span of the edition, since this is done // on a per-opaque basis to account for nested opaques. let always_capture_in_scope = match origin { - _ if self.tcx.features().lifetime_capture_rules_2024 => true, + _ if self.tcx.features().lifetime_capture_rules_2024() => true, hir::OpaqueTyOrigin::TyAlias { .. } => true, hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), hir::OpaqueTyOrigin::AsyncFn { .. } => { @@ -1519,7 +1519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if !self.tcx.features().precise_capturing_in_traits + if !self.tcx.features().precise_capturing_in_traits() && let Some(span) = bounds.iter().find_map(|bound| match *bound { ast::GenericBound::Use(_, span) => Some(span), _ => None, @@ -1956,7 +1956,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::GenericBound::Trait(hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)), hir_ref_id: self.next_id(), @@ -2270,7 +2270,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> { match c.value.kind { ExprKind::Underscore => { - if self.tcx.features().generic_arg_infer { + if self.tcx.features().generic_arg_infer() { hir::ArrayLen::Infer(hir::InferArg { hir_id: self.lower_node_id(c.id), span: self.lower_span(c.value.span), @@ -2445,22 +2445,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifiers( &mut self, modifiers: TraitBoundModifiers, - ) -> hir::TraitBoundModifier { - // Invalid modifier combinations will cause an error during AST validation. - // Arbitrarily pick a placeholder for them to make compilation proceed. - match (modifiers.constness, modifiers.polarity) { - (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, - (BoundConstness::Never, BoundPolarity::Negative(_)) => { - if self.tcx.features().negative_bounds { - hir::TraitBoundModifier::Negative - } else { - hir::TraitBoundModifier::None - } - } - (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, - (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, - } + ) -> hir::TraitBoundModifiers { + hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } } // Helper methods for building HIR. @@ -2626,7 +2612,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { let principal = hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index e60488fdc8c..258655de486 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -268,7 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span, }) }; - if !self.tcx.features().return_type_notation + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -496,7 +496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { - if self.tcx.features().impl_trait_in_fn_trait_return { + if self.tcx.features().impl_trait_in_fn_trait_return() { self.lower_ty(ty, itctx) } else { self.lower_ty( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 20a4f2120dc..bf6ebfb160b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -295,7 +295,8 @@ impl<'a> AstValidator<'a> { return; }; - let make_impl_const_sugg = if self.features.const_trait_impl + let const_trait_impl = self.features.const_trait_impl(); + let make_impl_const_sugg = if const_trait_impl && let TraitOrTraitImpl::TraitImpl { constness: Const::No, polarity: ImplPolarity::Positive, @@ -308,13 +309,12 @@ impl<'a> AstValidator<'a> { None }; - let make_trait_const_sugg = if self.features.const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness: None } = parent - { - Some(span.shrink_to_lo()) - } else { - None - }; + let make_trait_const_sugg = + if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent { + Some(span.shrink_to_lo()) + } else { + None + }; let parent_constness = parent.constness(); self.dcx().emit_err(errors::TraitFnConst { @@ -1145,7 +1145,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.check_type_no_bounds(bounds, "this context"); - if self.features.lazy_type_alias { + if self.features.lazy_type_alias() { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { self.dcx().emit_err(err); } @@ -1286,7 +1286,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( @@ -1299,7 +1299,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 94fcfabc32c..348a602fd59 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -15,13 +15,13 @@ use crate::errors; /// The common case. macro_rules! gate { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); } }}; ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { // FIXME: make this translatable #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] @@ -43,7 +43,7 @@ macro_rules! gate_alt { /// The case involving a multispan. macro_rules! gate_multi { ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ - if !$visitor.features.$feature { + if !$visitor.features.$feature() { let spans: Vec<_> = $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); if !spans.is_empty() { @@ -56,7 +56,7 @@ macro_rules! gate_multi { /// The legacy case. macro_rules! gate_legacy { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { feature_warn(&$visitor.sess, sym::$feature, $span, $explain); } }}; @@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> { // FIXME(non_lifetime_binders): Const bound params are pretty broken. // Let's keep users from using this feature accidentally. - if self.features.non_lifetime_binders { + if self.features.non_lifetime_binders() { let const_param_spans: Vec<_> = params .iter() .filter_map(|param| match param.kind { @@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } // Emit errors for non-staged-api crates. - if !self.features.staged_api { + if !self.features.staged_api() { if attr.has_name(sym::unstable) || attr.has_name(sym::stable) || attr.has_name(sym::rustc_const_unstable) @@ -470,7 +470,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // Limit `min_specialization` to only specializing functions. gate_alt!( &self, - self.features.specialization || (is_fn && self.features.min_specialization), + self.features.specialization() || (is_fn && self.features.min_specialization()), sym::specialization, i.span, "specialization is unstable" @@ -548,7 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); - if !visitor.features.never_patterns { + if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { for &span in spans { if span.allows_unstable(sym::never_patterns) { @@ -572,7 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } } - if !visitor.features.negative_bounds { + if !visitor.features.negative_bounds() { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { sess.dcx().emit_err(errors::NegativeBoundUnsupported { span }); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index bbb17497684..e412417a9e9 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -622,7 +622,7 @@ pub fn eval_condition( &(( if *b { kw::True } else { kw::False }, sym::cfg_boolean_literals, - |features: &Features| features.cfg_boolean_literals, + |features: &Features| features.cfg_boolean_literals(), )), cfg.span(), sess, @@ -711,7 +711,7 @@ pub fn eval_condition( } sym::target => { if let Some(features) = features - && !features.cfg_target_compact + && !features.cfg_target_compact() { feature_err( sess, @@ -831,7 +831,7 @@ pub fn find_deprecation( attrs: &[Attribute], ) -> Option<(Deprecation, Span)> { let mut depr: Option<(Deprecation, Span)> = None; - let is_rustc = features.staged_api; + let is_rustc = features.staged_api(); 'outer: for attr in attrs { if !attr.has_name(sym::deprecated) { @@ -891,7 +891,7 @@ pub fn find_deprecation( } } sym::suggestion => { - if !features.deprecated_suggestion { + if !features.deprecated_suggestion() { sess.dcx().emit_err( session_diagnostics::DeprecatedItemSuggestion { span: mi.span, @@ -909,7 +909,7 @@ pub fn find_deprecation( sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { span: meta.span(), item: pprust::path_to_string(&mi.path), - expected: if features.deprecated_suggestion { + expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { &["since", "note"] diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7b60a632c30..a544d88e832 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1035,7 +1035,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn unsized_feature_enabled(&self) -> bool { let features = self.tcx().features(); - features.unsized_locals || features.unsized_fn_params + features.unsized_locals() || features.unsized_fn_params() } /// Equate the inferred type and the annotated type for user type annotations diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 71449350985..599b180f879 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -69,7 +69,7 @@ pub(crate) fn expand_assert<'cx>( // If `generic_assert` is enabled, generates rich captured outputs // // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949 - else if cx.ecfg.features.generic_assert { + else if cx.ecfg.features.generic_assert() { context::Context::new(cx, call_site_span).build(cond_expr, panic_path()) } // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..." diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d536419ab3c..a5bd3adbcdd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -137,7 +137,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let inner = attr.meta_item_list(); match inner.as_deref() { Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg { + if !tcx.features().used_with_arg() { feature_err( &tcx.sess, sym::used_with_arg, @@ -149,7 +149,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; } Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg { + if !tcx.features().used_with_arg() { feature_err( &tcx.sess, sym::used_with_arg, @@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } if is_closure - && !tcx.features().closure_track_caller + && !tcx.features().closure_track_caller() && !attr.span.allows_unstable(sym::closure_track_caller) { feature_err( @@ -268,7 +268,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // // This exception needs to be kept in sync with allowing // `#[target_feature]` on `main` and `start`. - } else if !tcx.features().target_feature_11 { + } else if !tcx.features().target_feature_11() { feature_err( &tcx.sess, sym::target_feature_11, @@ -584,7 +584,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // its parent function, which effectively inherits the features anyway. Boxing this closure // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.features().target_feature_11 + if tcx.features().target_feature_11() && tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index dfe8fd616e4..0845bcc5749 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -5,7 +5,6 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -61,30 +60,9 @@ pub(crate) fn from_target_feature( return None; }; - // Only allow features whose feature gates have been enabled. + // Only allow target features whose feature gates have been enabled. let allowed = match feature_gate.as_ref().copied() { - Some(sym::arm_target_feature) => rust_features.arm_target_feature, - Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, - Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, - Some(sym::mips_target_feature) => rust_features.mips_target_feature, - Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, - Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, - Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, - Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, - Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, - Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, - Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, - Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, - Some(sym::csky_target_feature) => rust_features.csky_target_feature, - Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, - Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, - Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, - Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86, - Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, - Some(sym::xop_target_feature) => rust_features.xop_target_feature, - Some(sym::s390x_target_feature) => rust_features.s390x_target_feature, - Some(name) => bug!("unknown target feature gate {}", name), + Some(name) => rust_features.enabled(name), None => true, }; if !allowed { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 73344508a9d..288798bf0c2 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -611,7 +611,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // the trait into the concrete method, and uses that for const stability // checks. // FIXME(effects) we might consider moving const stability checks to typeck as well. - if tcx.features().effects { + if tcx.features().effects() { is_trait = true; if let Ok(Some(instance)) = @@ -631,7 +631,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { args: fn_args, span: *fn_span, call_source, - feature: Some(if tcx.features().const_trait_impl { + feature: Some(if tcx.features().const_trait_impl() { sym::effects } else { sym::const_trait_impl diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 15ac4cedcc3..3720418d4f0 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -61,7 +61,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn is_const_stable_const_fn(&self) -> bool { self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api + && self.tcx.features().staged_api() && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) } diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs index f98234ce7f3..d04d7b273f0 100644 --- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs @@ -24,7 +24,7 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { ); } - ccx.tcx.features().const_precise_live_drops + ccx.tcx.features().const_precise_live_drops() } /// Look for live drops in a const context. diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 7cb013fdbd8..85b030c1a48 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -9,8 +9,6 @@ //! Thomas Lengauer and Robert Endre Tarjan. //! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf> -use std::cmp::Ordering; - use rustc_index::{Idx, IndexSlice, IndexVec}; use super::ControlFlowGraph; @@ -64,9 +62,6 @@ fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool { } fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> { - // compute the post order index (rank) for each node - let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); - // We allocate capacity for the full set of nodes, because most of the time // most of the nodes *are* reachable. let mut parent: IndexVec<PreorderIndex, PreorderIndex> = @@ -83,12 +78,10 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> { pre_order_to_real.push(graph.start_node()); parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now. real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO); - let mut post_order_idx = 0; // Traverse the graph, collecting a number of things: // // * Preorder mapping (to it, and back to the actual ordering) - // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product) // * Parents for each vertex in the preorder tree // // These are all done here rather than through one of the 'standard' @@ -104,8 +97,6 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> { continue 'recurse; } } - post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx; - post_order_idx += 1; stack.pop(); } @@ -282,7 +273,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> { let time = compute_access_time(start_node, &immediate_dominators); - Inner { post_order_rank, immediate_dominators, time } + Inner { immediate_dominators, time } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -348,7 +339,6 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] struct Inner<N: Idx> { - post_order_rank: IndexVec<N, usize>, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator // of each dominator. @@ -379,17 +369,6 @@ impl<Node: Idx> Dominators<Node> { } } - /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator - /// relationship, the dominator will always precede the dominated. (The relative ordering - /// of two unrelated nodes will also be consistent, but otherwise the order has no - /// meaning.) This method cannot be used to determine if either Node dominates the other. - pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering { - match &self.kind { - Kind::Path => lhs.index().cmp(&rhs.index()), - Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]), - } - } - /// Returns true if `a` dominates `b`. /// /// # Panics diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f0cfe133a49..bed500c3032 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,5 +1,6 @@ use std::default::Default; use std::iter; +use std::path::Component::Prefix; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -1293,7 +1294,12 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe base_path.push(path); Ok(base_path) } else { - Ok(path) + // This ensures that Windows verbatim paths are fixed if mixed path separators are used, + // which can happen when `concat!` is used to join paths. + match path.components().next() { + Some(Prefix(prefix)) if prefix.kind().is_verbatim() => Ok(path.components().collect()), + _ => Ok(path), + } } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index a6b7291ee8f..5bd9e2fbcb9 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,7 +11,8 @@ use rustc_ast::{ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ - ACCEPTED_FEATURES, AttributeSafety, Features, REMOVED_FEATURES, UNSTABLE_FEATURES, + ACCEPTED_LANG_FEATURES, AttributeSafety, Features, REMOVED_LANG_FEATURES, + UNSTABLE_LANG_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; @@ -77,7 +78,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - }; // If the enabled feature has been removed, issue an error. - if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) { + if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) { sess.dcx().emit_err(FeatureRemoved { span: mi.span(), reason: f.reason.map(|reason| FeatureRemovedReason { reason }), @@ -86,9 +87,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } // If the enabled feature is stable, record it. - if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { let since = Some(Symbol::intern(f.since)); - features.set_enabled_lang_feature(name, mi.span(), since, None); + features.set_enabled_lang_feature(name, mi.span(), since); continue; } @@ -103,7 +104,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } // If the enabled feature is unstable, record it. - if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { + if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { // When the ICE comes from core, alloc or std (approximation of the standard // library), there's a chance that the person hitting the ICE may be using // -Zbuild-std or similar with an untested target. The bug is probably in the @@ -114,7 +115,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } - features.set_enabled_lang_feature(name, mi.span(), None, Some(f)); + features.set_enabled_lang_feature(name, mi.span(), None); continue; } @@ -395,7 +396,7 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) + if self.features.is_some_and(|features| !features.stmt_expr_attributes()) && !attr.span.allows_unstable(sym::stmt_expr_attributes) { let mut err = feature_err( diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index a872b12e744..5ffafcaa542 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -867,7 +867,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::FieldDef(..) | Annotatable::Variant(..) => panic!("unexpected annotatable"), }; - if self.cx.ecfg.features.proc_macro_hygiene { + if self.cx.ecfg.features.proc_macro_hygiene() { return; } feature_err( @@ -905,7 +905,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - if !self.cx.ecfg.features.proc_macro_hygiene { + if !self.cx.ecfg.features.proc_macro_hygiene() { annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess }); } } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index e518b27e419..1345f06d5ac 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -121,14 +121,14 @@ pub(super) fn parse( /// Asks for the `macro_metavar_expr` feature if it is not enabled fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) { - if !features.macro_metavar_expr { + if !features.macro_metavar_expr() { let msg = "meta-variable expressions are unstable"; feature_err(sess, sym::macro_metavar_expr, span, msg).emit(); } } fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) { - if !features.macro_metavar_expr_concat { + if !features.macro_metavar_expr_concat() { let msg = "the `concat` meta-variable expression is unstable"; feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit(); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 53445804694..4f71bdaca1b 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -9,7 +9,7 @@ macro_rules! declare_features { $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr), )+) => { /// Formerly unstable features that have now been accepted (stabilized). - pub const ACCEPTED_FEATURES: &[Feature] = &[ + pub const ACCEPTED_LANG_FEATURES: &[Feature] = &[ $(Feature { name: sym::$feature, since: $ver, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 477760a4597..753195bf691 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -12,33 +12,31 @@ use crate::{Features, Stability}; type GateFn = fn(&Features) -> bool; -macro_rules! cfg_fn { - ($field: ident) => { - (|features| features.$field) as GateFn - }; -} - pub type GatedCfg = (Symbol, Symbol, GateFn); /// `cfg(...)`'s that are feature gated. const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) - (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), - (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)), - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks), + (sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks), + (sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local), ( sym::target_has_atomic_equal_alignment, sym::cfg_target_has_atomic_equal_alignment, - cfg_fn!(cfg_target_has_atomic_equal_alignment), - ), - (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), - (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), - (sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)), - (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)), - (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)), + Features::cfg_target_has_atomic_equal_alignment, + ), + ( + sym::target_has_atomic_load_store, + sym::cfg_target_has_atomic, + Features::cfg_target_has_atomic, + ), + (sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize), + (sym::version, sym::cfg_version, Features::cfg_version), + (sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model), + (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), + (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), // this is consistent with naming of the compiler flag it's for - (sym::fmt_debug, sym::fmt_debug, cfg_fn!(fmt_debug)), + (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. @@ -220,7 +218,7 @@ macro_rules! gated { safety: AttributeSafety::Unsafe, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), } }; (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { @@ -231,7 +229,7 @@ macro_rules! gated { safety: AttributeSafety::Unsafe, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), } }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { @@ -242,7 +240,7 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), } }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { @@ -253,7 +251,7 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), } }; } @@ -282,7 +280,7 @@ macro_rules! rustc_attr { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), + gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs), } }; } @@ -935,7 +933,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ Stability::Unstable, sym::rustc_attrs, "diagnostic items compiler internal support for linting", - cfg_fn!(rustc_attrs), + Features::rustc_attrs, ), }, gated!( @@ -1193,7 +1191,7 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool { match sym { sym::on_unimplemented => true, - sym::do_not_recommend => features.do_not_recommend, + sym::do_not_recommend => features.do_not_recommend(), _ => false, } } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 8f4c0b0ac95..216793485e5 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -94,13 +94,13 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> { // Search in all the feature lists. - if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) { - return f.feature.issue; + if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) { + return f.issue; } - if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) { + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) { return f.issue; } - if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) { + if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) { return f.feature.issue; } panic!("feature `{feature}` is not declared anywhere"); @@ -127,12 +127,12 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u } } -pub use accepted::ACCEPTED_FEATURES; +pub use accepted::ACCEPTED_LANG_FEATURES; pub use builtin_attrs::{ AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType, BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr, }; -pub use removed::REMOVED_FEATURES; -pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES}; +pub use removed::REMOVED_LANG_FEATURES; +pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES}; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index d797fee000d..fe3a67fd667 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -14,7 +14,7 @@ macro_rules! declare_features { $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr), )+) => { /// Formerly unstable features that have now been removed. - pub const REMOVED_FEATURES: &[RemovedFeature] = &[ + pub const REMOVED_LANG_FEATURES: &[RemovedFeature] = &[ $(RemovedFeature { feature: Feature { name: sym::$feature, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 0606f2914c3..8f4c208f1fb 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -6,11 +6,6 @@ use rustc_span::symbol::{Symbol, sym}; use super::{Feature, to_nonzero}; -pub struct UnstableFeature { - pub feature: Feature, - set_enabled: fn(&mut Features), -} - #[derive(PartialEq)] enum FeatureStatus { Default, @@ -30,110 +25,73 @@ macro_rules! status_to_enum { }; } +/// A set of features to be used by later passes. +/// +/// There are two ways to check if a language feature `foo` is enabled: +/// - Directly with the `foo` method, e.g. `if tcx.features().foo() { ... }`. +/// - With the `enabled` method, e.g. `if tcx.features.enabled(sym::foo) { ... }`. +/// +/// The former is preferred. `enabled` should only be used when the feature symbol is not a +/// constant, e.g. a parameter, or when the feature is a library feature. +#[derive(Clone, Default, Debug)] +pub struct Features { + /// `#![feature]` attrs for language features, for error reporting. + enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, + /// `#![feature]` attrs for non-language (library) features. + enabled_lib_features: Vec<(Symbol, Span)>, + /// `enabled_lang_features` + `enabled_lib_features`. + enabled_features: FxHashSet<Symbol>, +} + +impl Features { + pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) { + self.enabled_lang_features.push((name, span, since)); + self.enabled_features.insert(name); + } + + pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { + self.enabled_lib_features.push((name, span)); + self.enabled_features.insert(name); + } + + pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> { + &self.enabled_lang_features + } + + pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { + &self.enabled_lib_features + } + + pub fn enabled_features(&self) -> &FxHashSet<Symbol> { + &self.enabled_features + } + + /// Is the given feature enabled (via `#[feature(...)]`)? + pub fn enabled(&self, feature: Symbol) -> bool { + self.enabled_features.contains(&feature) + } +} + macro_rules! declare_features { ($( $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr), )+) => { /// Unstable language features that are being implemented or being /// considered for acceptance (stabilization) or removal. - pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[ - $(UnstableFeature { - feature: Feature { - name: sym::$feature, - since: $ver, - issue: to_nonzero($issue), - }, - // Sets this feature's corresponding bool within `features`. - set_enabled: |features| features.$feature = true, + pub const UNSTABLE_LANG_FEATURES: &[Feature] = &[ + $(Feature { + name: sym::$feature, + since: $ver, + issue: to_nonzero($issue), }),+ ]; - const NUM_FEATURES: usize = UNSTABLE_FEATURES.len(); - - /// A set of features to be used by later passes. - #[derive(Clone, Default, Debug)] - pub struct Features { - /// `#![feature]` attrs for language features, for error reporting. - enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, - /// `#![feature]` attrs for non-language (library) features. - enabled_lib_features: Vec<(Symbol, Span)>, - /// `enabled_lang_features` + `enabled_lib_features`. - enabled_features: FxHashSet<Symbol>, - /// State of individual features (unstable lang features only). - /// This is `true` if and only if the corresponding feature is listed in `enabled_lang_features`. - $( - $(#[doc = $doc])* - pub $feature: bool - ),+ - } - impl Features { - pub fn set_enabled_lang_feature( - &mut self, - name: Symbol, - span: Span, - since: Option<Symbol>, - feature: Option<&UnstableFeature>, - ) { - self.enabled_lang_features.push((name, span, since)); - self.enabled_features.insert(name); - if let Some(feature) = feature { - assert_eq!(feature.feature.name, name); - (feature.set_enabled)(self); - } else { - // Ensure we don't skip a `set_enabled` call. - debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none()); - } - } - - pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { - self.enabled_lib_features.push((name, span)); - self.enabled_features.insert(name); - // Ensure we don't skip a `set_enabled` call. - debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none()); - } - - /// This is intended for hashing the set of enabled language features. - /// - /// The expectation is that this produces much smaller code than other alternatives. - /// - /// Note that the total feature count is pretty small, so this is not a huge array. - #[inline] - pub fn all_lang_features(&self) -> [u8; NUM_FEATURES] { - [$(self.$feature as u8),+] - } - - pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> { - &self.enabled_lang_features - } - - pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { - &self.enabled_lib_features - } - - pub fn enabled_features(&self) -> &FxHashSet<Symbol> { - &self.enabled_features - } - - /// Is the given feature enabled (via `#[feature(...)]`)? - pub fn enabled(&self, feature: Symbol) -> bool { - let e = self.enabled_features.contains(&feature); - if cfg!(debug_assertions) { - // Ensure this matches `self.$feature`, if that exists. - let e2 = match feature { - $( sym::$feature => Some(self.$feature), )* - _ => None, - }; - if let Some(e2) = e2 { - assert_eq!( - e, e2, - "mismatch in feature state for `{feature}`: \ - `enabled_features` says {e} but `self.{feature}` says {e2}" - ); - } + $( + pub fn $feature(&self) -> bool { + self.enabled_features.contains(&sym::$feature) } - e - } + )* /// Some features are known to be incomplete and using them is likely to have /// unanticipated results, such as compiler crashes. We warn the user about these diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 009c6c4aea5..45be04c6db9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -6,8 +6,8 @@ use rustc_ast::{ LitKind, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ - BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability, - Mutability, UnOp, + BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; @@ -502,19 +502,16 @@ pub enum GenericArgsParentheses { ParenSugar, } -/// A modifier on a trait bound. +/// The modifiers on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum TraitBoundModifier { - /// `Type: Trait` - None, - /// `Type: !Trait` - Negative, - /// `Type: ?Trait` - Maybe, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - MaybeConst, +pub struct TraitBoundModifiers { + pub constness: BoundConstness, + pub polarity: BoundPolarity, +} + +impl TraitBoundModifiers { + pub const NONE: Self = + TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -3180,7 +3177,7 @@ pub struct PolyTraitRef<'hir> { /// The constness and polarity of the trait ref. /// /// The `async` modifier is lowered directly into a different trait for now. - pub modifiers: TraitBoundModifier, + pub modifiers: TraitBoundModifiers, /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, @@ -4085,7 +4082,7 @@ mod size_asserts { static_assert_size!(ForeignItem<'_>, 88); static_assert_size!(ForeignItemKind<'_>, 56); static_assert_size!(GenericArg<'_>, 16); - static_assert_size!(GenericBound<'_>, 48); + static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); static_assert_size!(ImplItem<'_>, 88); diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 9a2c38e51e2..77df0cb7ef9 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> { // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated // type bounds. - if !tcx.features().effects { + if !tcx.features().effects() { return; } match predicate_filter { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 2aeeb9450ce..97f3f1c8ef2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1166,7 +1166,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return; } - if adt.is_union() && !tcx.features().transparent_unions { + if adt.is_union() && !tcx.features().transparent_unions() { feature_err( &tcx.sess, sym::transparent_unions, @@ -1301,7 +1301,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { let repr_type_ty = def.repr().discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { + if !tcx.features().repr128() { feature_err( &tcx.sess, sym::repr128, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 75956165e87..fc5ec31cda8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -43,14 +43,13 @@ mod refine; /// - `impl_m`: type of the method we are checking /// - `trait_m`: the method in the trait /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation +#[instrument(level = "debug", skip(tcx))] pub(super) fn compare_impl_method<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) { - debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); - let _: Result<_, ErrorGuaranteed> = try { check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?; @@ -167,8 +166,6 @@ fn compare_method_predicate_entailment<'tcx>( trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let trait_to_impl_args = impl_trait_ref.args; - // This node-id should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). // @@ -183,27 +180,17 @@ fn compare_method_predicate_entailment<'tcx>( kind: impl_m.kind, }); - // Create mapping from impl to placeholder. - let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); - - // Create mapping from trait to placeholder. - let trait_to_placeholder_args = - impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args); - debug!("compare_impl_method: trait_to_placeholder_args={:?}", trait_to_placeholder_args); + // Create mapping from trait method to impl method. + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto( + tcx, + impl_m.container_id(tcx), + impl_trait_ref.args, + ); + debug!(?trait_to_impl_args); let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let trait_m_predicates = tcx.predicates_of(trait_m.def_id); - // Create obligations for each predicate declared by the impl - // definition in the context of the trait's parameter - // environment. We can't just use `impl_env.caller_bounds`, - // however, because we want to replace all late-bound regions with - // region variables. - let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - - debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); - // This is the only tricky bit of the new way we check implementation methods // We need to build a set of predicates where only the method-level bounds // are from the trait and we assume all other bounds from the implementation @@ -211,25 +198,25 @@ fn compare_method_predicate_entailment<'tcx>( // // We then register the obligations from the impl_m and check to see // if all constraints hold. - hybrid_preds.predicates.extend( - trait_m_predicates - .instantiate_own(tcx, trait_to_placeholder_args) - .map(|(predicate, _)| predicate), + let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( + trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate), ); - // Construct trait parameter environment and then shift it into the placeholder viewpoint. - // The key step here is to update the caller_bounds's predicates to be - // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + debug!(caller_bounds=?param_env.caller_bounds()); let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(infcx); - debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); - - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args); + // Create obligations for each predicate declared by the impl + // definition in the context of the hybrid param-env. This makes + // sure that the impl's method's where clauses are not more + // restrictive than the trait's method (and the impl itself). + let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity(); for (predicate, span) in impl_m_own_bounds { let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); @@ -256,7 +243,6 @@ fn compare_method_predicate_entailment<'tcx>( // any associated types appearing in the fn arguments or return // type. - // Compute placeholder form of impl and trait method tys. let mut wf_tys = FxIndexSet::default(); let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( @@ -267,9 +253,9 @@ fn compare_method_predicate_entailment<'tcx>( let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); - debug!("compare_impl_method: impl_fty={:?}", impl_sig); + debug!(?impl_sig); - let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args); + let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); // Next, add all inputs and output as well-formed tys. Importantly, @@ -280,9 +266,7 @@ fn compare_method_predicate_entailment<'tcx>( // We also have to add the normalized trait signature // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig)); - - debug!("compare_impl_method: trait_fty={:?}", trait_fty); + debug!(?trait_sig); // FIXME: We'd want to keep more accurate spans than "the method signature" when // processing the comparison between the trait and impl fn, but we sadly lose them @@ -455,8 +439,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // just so we don't ICE during instantiation later. check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; - let trait_to_impl_args = impl_trait_ref.args; - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = @@ -466,18 +448,18 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( kind: impl_m.kind, }); - // Create mapping from impl to placeholder. - let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); - - // Create mapping from trait to placeholder. - let trait_to_placeholder_args = - impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args); + // Create mapping from trait to impl (i.e. impl trait header + impl method identity args). + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto( + tcx, + impl_m.container_id(tcx), + impl_trait_ref.args, + ); let hybrid_preds = tcx .predicates_of(impl_m.container_id(tcx)) .instantiate_identity(tcx) .into_iter() - .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args)) + .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args)) .map(|(clause, _)| clause); let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( @@ -511,7 +493,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( .instantiate_binder_with_fresh_vars( return_span, infer::HigherRankedType, - tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args), + tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args), ) .fold_with(&mut collector); @@ -705,7 +687,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // Also, we only need to account for a difference in trait and impl args, // since we previously enforce that the trait method and impl method have the // same generics. - let num_trait_args = trait_to_impl_args.len(); + let num_trait_args = impl_trait_ref.args.len(); let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len(); let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions { tcx, @@ -1041,12 +1023,7 @@ fn check_region_bounds_on_impl_item<'tcx>( let trait_generics = tcx.generics_of(trait_m.def_id); let trait_params = trait_generics.own_counts().lifetimes; - debug!( - "check_region_bounds_on_impl_item: \ - trait_generics={:?} \ - impl_generics={:?}", - trait_generics, impl_generics - ); + debug!(?trait_generics, ?impl_generics); // Must have same number of early-bound lifetime parameters. // Unfortunately, if the user screws up the bounds, then this @@ -1710,8 +1687,7 @@ pub(super) fn compare_impl_const_raw( let trait_const_item = tcx.associated_item(trait_const_item_def); let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity(); - - debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref); + debug!(?impl_trait_ref); compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; @@ -1722,6 +1698,7 @@ pub(super) fn compare_impl_const_raw( /// The equivalent of [compare_method_predicate_entailment], but for associated constants /// instead of associated functions. // FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`. +#[instrument(level = "debug", skip(tcx))] fn compare_const_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ct: ty::AssocItem, @@ -1736,13 +1713,14 @@ fn compare_const_predicate_entailment<'tcx>( // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id); - let trait_to_impl_args = - impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args); + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id).rebase_onto( + tcx, + impl_ct.container_id(tcx), + impl_trait_ref.args, + ); // Create a parameter environment that represents the implementation's - // method. - // Compute placeholder form of impl and trait const tys. + // associated const. let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity(); let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args); @@ -1759,14 +1737,14 @@ fn compare_const_predicate_entailment<'tcx>( // The predicates declared by the impl definition, the trait and the // associated const in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - hybrid_preds.predicates.extend( + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( trait_ct_predicates .instantiate_own(tcx, trait_to_impl_args) .map(|(predicate, _)| predicate), ); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, param_env, @@ -1776,7 +1754,7 @@ fn compare_const_predicate_entailment<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); + let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity(); for (predicate, span) in impl_ct_own_bounds { let cause = ObligationCause::misc(span, impl_ct_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -1787,20 +1765,15 @@ fn compare_const_predicate_entailment<'tcx>( // There is no "body" here, so just pass dummy id. let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + debug!(?impl_ty); let trait_ty = ocx.normalize(&cause, param_env, trait_ty); - - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + debug!(?trait_ty); let err = ocx.sup(&cause, param_env, trait_ty, impl_ty); if let Err(terr) = err { - debug!( - "checking associated const for compatibility: impl ty {:?}, trait ty {:?}", - impl_ty, trait_ty - ); + debug!(?impl_ty, ?trait_ty); // Locate the Span containing just the type of the offending impl let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); @@ -1845,14 +1818,13 @@ fn compare_const_predicate_entailment<'tcx>( ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env) } +#[instrument(level = "debug", skip(tcx))] pub(super) fn compare_impl_ty<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: ty::AssocItem, trait_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) { - debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); - let _: Result<(), ErrorGuaranteed> = try { compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; @@ -1864,20 +1836,23 @@ pub(super) fn compare_impl_ty<'tcx>( /// The equivalent of [compare_method_predicate_entailment], but for associated types /// instead of associated functions. +#[instrument(level = "debug", skip(tcx))] fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: ty::AssocItem, trait_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); - let trait_to_impl_args = - impl_args.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.args); + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto( + tcx, + impl_ty.container_id(tcx), + impl_trait_ref.args, + ); let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id); let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); - let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args); + let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity(); if impl_ty_own_bounds.len() == 0 { // Nothing to check. return Ok(()); @@ -1887,29 +1862,29 @@ fn compare_type_predicate_entailment<'tcx>( // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_def_id = impl_ty.def_id.expect_local(); - debug!("compare_type_predicate_entailment: trait_to_impl_args={:?}", trait_to_impl_args); + debug!(?trait_to_impl_args); // The predicates declared by the impl definition, the trait and the // associated type in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - hybrid_preds.predicates.extend( + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( trait_ty_predicates .instantiate_own(tcx, trait_to_impl_args) .map(|(predicate, _)| predicate), ); - - debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); + debug!(?hybrid_preds); let impl_ty_span = tcx.def_span(impl_ty_def_id); let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + debug!(caller_bounds=?param_env.caller_bounds()); + let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - for (predicate, span) in impl_ty_own_bounds { let cause = ObligationCause::misc(span, impl_ty_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -2009,11 +1984,11 @@ pub(super) fn check_type_bounds<'tcx>( .explicit_item_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(concrete_ty_bound, span)| { - debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); + debug!(?concrete_ty_bound); traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) }) .collect(); - debug!("check_type_bounds: item_bounds={:?}", obligations); + debug!(item_bounds=?obligations); // Normalize predicates with the assumption that the GAT may always normalize // to its definition type. This should be the param-env we use to *prove* the @@ -2032,7 +2007,7 @@ pub(super) fn check_type_bounds<'tcx>( } else { ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate) }; - debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + debug!(?normalized_predicate); obligation.predicate = normalized_predicate; ocx.register_obligation(obligation); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 1a5f4659812..312fb16c93a 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -167,7 +167,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } } if let Some(tail_expr) = blk.expr { - if visitor.tcx.features().shorter_tail_lifetimes + if visitor.tcx.features().shorter_tail_lifetimes() && blk.span.edition().at_least_rust_2024() { visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); @@ -466,7 +466,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() + { ScopeData::IfThenRescope } else { ScopeData::IfThen @@ -481,7 +482,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() + { ScopeData::IfThenRescope } else { ScopeData::IfThen diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f788456d4e9..3170c0ac990 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -110,7 +110,7 @@ where let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; - if !tcx.features().trivial_bounds { + if !tcx.features().trivial_bounds() { wfcx.check_false_global_bounds() } f(&mut wfcx)?; @@ -921,7 +921,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); - if tcx.features().unsized_const_params { + if tcx.features().unsized_const_params() { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { wfcx.register_bound( ObligationCause::new( @@ -935,7 +935,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ); Ok(()) }) - } else if tcx.features().adt_const_params { + } else if tcx.features().adt_const_params() { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { wfcx.register_bound( ObligationCause::new( @@ -1698,9 +1698,9 @@ fn check_method_receiver<'tcx>( return Ok(()); } - let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers { + let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers() { Some(ArbitrarySelfTypesLevel::WithPointers) - } else if tcx.features().arbitrary_self_types { + } else if tcx.features().arbitrary_self_types() { Some(ArbitrarySelfTypesLevel::Basic) } else { None diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb3c088afb..2afc2aec1ba 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -77,7 +77,7 @@ impl<'tcx> InherentCollect<'tcx> { return Ok(()); } - if self.tcx.features().rustc_attrs { + if self.tcx.features().rustc_attrs() { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { @@ -115,7 +115,7 @@ impl<'tcx> InherentCollect<'tcx> { ) -> Result<(), ErrorGuaranteed> { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.hir().rustc_coherence_is_core() { - if self.tcx.features().rustc_attrs { + if self.tcx.features().rustc_attrs() { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index eea5a16ac6f..3aad4bafeb5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls { + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() { feature_err( &tcx.sess, sym::freeze_impls, @@ -86,8 +86,8 @@ fn enforce_trait_manually_implementable( if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind { - if !tcx.features().specialization - && !tcx.features().min_specialization + if !tcx.features().specialization() + && !tcx.features().min_specialization() && !impl_header_span.allows_unstable(sym::specialization) && !impl_header_span.allows_unstable(sym::min_specialization) { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f63e2d40e39..acc21d0994b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1129,7 +1129,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { }; let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); - if paren_sugar && !tcx.features().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures() { tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span }); } @@ -1696,7 +1696,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw - if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi { + if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi() { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { let snip = tcx diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 14b6b17ed18..348b2260d26 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -109,7 +109,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // We do not allow generic parameters in anon consts if we are inside // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. None - } else if tcx.features().generic_const_exprs { + } else if tcx.features().generic_const_exprs() { let parent_node = tcx.parent_hir_node(hir_id); debug!(?parent_node); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 9bd8c70dcfe..097a1fbc393 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -308,7 +308,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); } @@ -524,7 +524,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } else { if matches!(def_kind, DefKind::AnonConst) - && tcx.features().generic_const_exprs + && tcx.features().generic_const_exprs() && let Some(defaulted_param_def_id) = tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id)) { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cb7f0901c7e..95e07244a6b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1161,7 +1161,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() - && !self.tcx.features().anonymous_lifetime_in_impl_trait + && !self.tcx.features().anonymous_lifetime_in_impl_trait() { let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err( &self.tcx.sess, @@ -2239,7 +2239,7 @@ fn deny_non_region_late_bound( format!("late-bound {what} parameter not allowed on {where_}"), ); - let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first); + let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first); first = false; *arg = ResolvedArg::Error(guar); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 470bcaeded1..84161ec7648 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -699,7 +699,7 @@ fn infer_placeholder_type<'tcx>( } fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { - if !tcx.features().inherent_associated_types { + if !tcx.features().inherent_associated_types() { use rustc_session::parse::feature_err; use rustc_span::symbol::sym; feature_err( @@ -714,7 +714,7 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { use hir::intravisit::Visitor; - if tcx.features().lazy_type_alias { + if tcx.features().lazy_type_alias() { return true; } struct HasTait; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 4721a3a0cf5..2b0e1350108 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -45,23 +45,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir::GenericBound::Trait(ptr) = hir_bound else { continue; }; - match ptr.modifiers { - hir::TraitBoundModifier::Maybe => unbounds.push(ptr), - hir::TraitBoundModifier::Negative => { + match ptr.modifiers.polarity { + hir::BoundPolarity::Maybe(_) => unbounds.push(ptr), + hir::BoundPolarity::Negative(_) => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_negative_sized_bound = true; } } - hir::TraitBoundModifier::None => { + hir::BoundPolarity::Positive => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_positive_sized_bound = true; } } - _ => {} } } }; @@ -89,7 +88,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; if seen_repeat { self.dcx().emit_err(err); - } else if !tcx.features().more_maybe_bounds { + } else if !tcx.features().more_maybe_bounds() { self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit(); }; } @@ -169,20 +168,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let (constness, polarity) = match poly_trait_ref.modifiers { - hir::TraitBoundModifier::Const => { - (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive) - } - hir::TraitBoundModifier::MaybeConst => ( - Some(ty::BoundConstness::ConstIfConst), - ty::PredicatePolarity::Positive, - ), - hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive), - hir::TraitBoundModifier::Negative => { - (None, ty::PredicatePolarity::Negative) - } - hir::TraitBoundModifier::Maybe => continue, + let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; + // FIXME: We could pass these directly into `lower_poly_trait_ref` + // so that we could use these spans in diagnostics within that function... + let constness = match constness { + hir::BoundConstness::Never => None, + hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const), + hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst), }; + let polarity = match polarity { + rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, + rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, + rustc_ast::BoundPolarity::Maybe(_) => continue, + }; + let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index a1ee120e855..2cee7c77aa5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -40,8 +40,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in hir_trait_bounds.iter().rev() { - // FIXME: This doesn't handle `? const`. - if trait_bound.modifiers == hir::TraitBoundModifier::Maybe { + if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { continue; } if let GenericArgCountResult { @@ -259,7 +258,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } }) .collect(); - let args = tcx.mk_args(&args); let span = i.bottom().1; let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { @@ -292,7 +290,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .emit(); } - ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } + ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args) }) }); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 01768c89cca..dd0f250a8e2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -63,7 +63,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: &'_ hir::PathSegment<'_>, is_impl: bool, ) { - if self.tcx().features().unboxed_closures { + if self.tcx().features().unboxed_closures() { return; } @@ -343,7 +343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && let Some(hir_ty) = constraint.ty() && let ty = self.lower_ty(hir_ty) && (ty.is_enum() || ty.references_error()) - && tcx.features().associated_const_equality + && tcx.features().associated_const_equality() { Some(errors::AssocKindMismatchWrapInBracesSugg { lo: hir_ty.span.shrink_to_lo(), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fe0cd572609..a73a2f925cd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1241,7 +1241,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle // errors (#108491) which mask the feature-gate error, needlessly confusing users // who use IATs by accident (#113265). - if !tcx.features().inherent_associated_types { + if !tcx.features().inherent_associated_types() { return Ok(None); } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 7f183324f04..d9c70c3cee6 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -57,7 +57,7 @@ pub(crate) fn check_impl_wf( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - let min_specialization = tcx.features().min_specialization; + let min_specialization = tcx.features().min_specialization(); let mut res = Ok(()); debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. }); res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id)); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 71ee77f8f61..3ad35163191 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -116,7 +116,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi return; } - let extended_abi_support = tcx.features().extended_varargs_abi_support; + let extended_abi_support = tcx.features().extended_varargs_abi_support(); let conventions = match (extended_abi_support, abi.supports_varargs()) { // User enabled additional ABI support for varargs and function ABI matches those ones. (true, true) => return, @@ -155,7 +155,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { // FIXME(effects): remove once effects is implemented in old trait solver // or if the next solver is stabilized. - if tcx.features().effects && !tcx.next_trait_solver_globally() { + if tcx.features().effects() && !tcx.next_trait_solver_globally() { tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); } @@ -172,7 +172,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); }); - if tcx.features().rustc_attrs { + if tcx.features().rustc_attrs() { tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); collect::dump::opaque_hidden_types(tcx); diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index e3cdb1bf5f7..c43917649de 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -23,7 +23,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau let crate_map = tcx.inferred_outlives_crate(()); crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) } - DefKind::AnonConst if tcx.features().generic_const_exprs => { + DefKind::AnonConst if tcx.features().generic_const_exprs() => { let id = tcx.local_def_id_to_hir_id(item_def_id); if tcx.hir().opt_const_param_default_param_def_id(id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9ebfd4f15ab..3ba9c76bcee 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -16,7 +16,6 @@ use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TraitBoundModifier, }; use rustc_span::FileName; use rustc_span::source_map::SourceMap; @@ -676,9 +675,16 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { - // FIXME: This isn't correct! - if t.modifiers == TraitBoundModifier::Maybe { - self.word("?"); + let hir::TraitBoundModifiers { constness, polarity } = t.modifiers; + match constness { + hir::BoundConstness::Never => {} + hir::BoundConstness::Always(_) => self.word("const"), + hir::BoundConstness::Maybe(_) => self.word("~const"), + } + match polarity { + hir::BoundPolarity::Positive => {} + hir::BoundPolarity::Negative(_) => self.word("!"), + hir::BoundPolarity::Maybe(_) => self.word("?"), } self.print_formal_generic_params(t.bound_generic_params); self.print_trait_ref(&t.trait_ref); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 8fa6ab8503d..f7306063c16 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -721,7 +721,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { use rustc_middle::ty::cast::IntTy::*; if self.cast_ty.is_dyn_star() { - if fcx.tcx.features().dyn_star { + if fcx.tcx.features().dyn_star() { span_bug!(self.span, "should be handled by `coerce`"); } else { // Report "casting is invalid" rather than "non-primitive cast" diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 406d668e7a5..de80ccf790c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -223,11 +223,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Ref(r_b, _, mutbl_b) => { return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); } - ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { + ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star() => { return self.coerce_dyn_star(a, b, predicates, region); } ty::Adt(pin, _) - if self.tcx.features().pin_ergonomics + if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { return self.coerce_pin(a, b); @@ -698,7 +698,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } if let Some((sub, sup)) = has_trait_upcasting_coercion - && !self.tcx().features().trait_upcasting + && !self.tcx().features().trait_upcasting() { // Renders better when we erase regions, since they're not really the point here. let (sub, sup) = self.tcx.erase_regions((sub, sup)); @@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { err.emit(); } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() { feature_err( &self.tcx.sess, sym::unsized_tuple_coercion, @@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_region: ty::Region<'tcx>, ) -> CoerceResult<'tcx> { - if !self.tcx.features().dyn_star { + if !self.tcx.features().dyn_star() { return Err(TypeError::Mismatch); } @@ -1695,7 +1695,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { blk_id, expression, ); - if !fcx.tcx.features().unsized_locals { + if !fcx.tcx.features().unsized_locals() { unsized_return = self.is_return_ty_definitely_unsized(fcx); } } @@ -1709,7 +1709,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { return_expr_id, expression, ); - if !fcx.tcx.features().unsized_locals { + if !fcx.tcx.features().unsized_locals() { unsized_return = self.is_return_ty_definitely_unsized(fcx); } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f4d7b59e9c8..da231acbb0f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -10,7 +10,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -734,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be known if explicitly specified via turbofish). self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } - if !tcx.features().unsized_fn_params { + if !tcx.features().unsized_fn_params() { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. // i.e., we don't want to allow @@ -1995,7 +1996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(base_expr) = base_expr { // FIXME: We are currently creating two branches here in order to maintain // consistency. But they should be merged as much as possible. - let fru_tys = if self.tcx.features().type_changing_struct_update { + let fru_tys = if self.tcx.features().type_changing_struct_update() { if adt.is_struct() { // Make some fresh generic parameters for our ADT type. let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); @@ -2763,12 +2764,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_ident.span, "field not available in `impl Future`, but it is available in its `Output`", ); - err.span_suggestion_verbose( - base.span.shrink_to_hi(), - "consider `await`ing on the `Future` and access the field of its `Output`", - ".await", - Applicability::MaybeIncorrect, - ); + match self.tcx.coroutine_kind(self.body_id) { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider `await`ing on the `Future` to access the field", + ".await", + Applicability::MaybeIncorrect, + ); + } + _ => { + let mut span: MultiSpan = base.span.into(); + span.push_span_label(self.tcx.def_span(self.body_id), "this is not `async`"); + err.span_note( + span, + "this implements `Future` and its output type has the field, \ + but the future cannot be awaited in a synchronous function", + ); + } + } } fn ban_nonexisting_field( @@ -3538,7 +3552,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, _def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); - if !self.tcx.features().offset_of_enum { + if !self.tcx.features().offset_of_enum() { rustc_session::parse::feature_err( &self.tcx.sess, sym::offset_of_enum, @@ -3628,7 +3642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let field_ty = self.field_ty(expr.span, field, args); - if self.tcx.features().offset_of_slice { + if self.tcx.features().offset_of_slice() { self.require_type_has_static_alignment( field_ty, expr.span, @@ -3661,7 +3675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && field.name == sym::integer(index) { if let Some(&field_ty) = tys.get(index) { - if self.tcx.features().offset_of_slice { + if self.tcx.features().offset_of_slice() { self.require_type_has_static_alignment( field_ty, expr.span, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2bc84d1ac67..d2d311ef565 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1486,7 +1486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return ty::Const::new_error(self.tcx, guar); } } - } else if self.tcx.features().generic_const_exprs { + } else if self.tcx.features().generic_const_exprs() { ct.normalize_internal(self.tcx, self.param_env) } else { ct diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e60bd1a312a..4123feebb40 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -404,7 +404,7 @@ fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { } // `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff - if tcx.features().never_type_fallback { + if tcx.features().never_type_fallback() { return DivergingFallbackBehavior::ContextDependent; } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 5ae8d2230f8..f427b0b805e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let var_ty = self.assign(p.span, p.hir_id, None); if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat { - if !self.fcx.tcx.features().unsized_fn_params { + if !self.fcx.tcx.features().unsized_fn_params() { self.fcx.require_type_is_sized( var_ty, ty_span, @@ -158,7 +158,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ), ); } - } else if !self.fcx.tcx.features().unsized_locals { + } else if !self.fcx.tcx.features().unsized_locals() { self.fcx.require_type_is_sized( var_ty, p.span, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 85ee0a5cf7d..85e11ff6745 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -161,7 +161,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig); - check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params); + check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { let expected_type = infer_type_if_missing(&fcx, node); let expected_type = expected_type.unwrap_or_else(fallback); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 1d7b3433fe5..f4685725dd3 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -536,7 +536,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // FIXME(arbitrary_self_types): We probably should limit the // situations where this can occur by adding additional restrictions // to the feature, like the self type can't reference method args. - if self.tcx.features().arbitrary_self_types { + if self.tcx.features().arbitrary_self_types() { self.err_ctxt() .report_mismatched_types(&cause, method_self_ty, self_ty, terr) .emit(); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1be711887d9..b60fa8bbfa1 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mode, })); } else if bad_ty.reached_raw_pointer - && !self.tcx.features().arbitrary_self_types_pointers + && !self.tcx.features().arbitrary_self_types_pointers() && !self.tcx.sess.at_least_rust_2018() { // this case used to be allowed by the compiler, @@ -429,8 +429,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty.value); let guar = match *ty.kind() { ty::Infer(ty::TyVar(_)) => { - let raw_ptr_call = - bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types; + let raw_ptr_call = bad_ty.reached_raw_pointer + && !self.tcx.features().arbitrary_self_types(); let mut err = self.err_ctxt().emit_inference_failure_err( self.body_id, span, @@ -1146,7 +1146,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } ty::Adt(def, args) - if self.tcx.features().pin_ergonomics + if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { // make sure this is a pinned reference (and not a `Pin<Box>` or something) @@ -1195,7 +1195,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<PickResult<'tcx>> { - if !self.tcx.features().pin_ergonomics { + if !self.tcx.features().pin_ergonomics() { return None; } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e961752b24c..cba6586f01d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -442,7 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let features = self.tcx.features(); - if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { + if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural() + { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { max_ref_mutbl = MutblCap::Not; @@ -490,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if self.tcx.features().string_deref_patterns + if self.tcx.features().string_deref_patterns() && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { let tcx = self.tcx; @@ -675,10 +676,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { if pat.span.at_least_rust_2024() - && (self.tcx.features().ref_pat_eat_one_layer_2024 - || self.tcx.features().ref_pat_eat_one_layer_2024_structural) + && (self.tcx.features().ref_pat_eat_one_layer_2024() + || self.tcx.features().ref_pat_eat_one_layer_2024_structural()) { - if !self.tcx.features().mut_ref { + if !self.tcx.features().mut_ref() { feature_err( &self.tcx.sess, sym::mut_ref, @@ -2152,8 +2153,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let features = tcx.features(); - let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; - let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; + let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024(); + let ref_pat_eat_one_layer_2024_structural = + features.ref_pat_eat_one_layer_2024_structural(); let no_ref_mut_behind_and = ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 63cf483aa22..9e8a314bc4a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -488,7 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!(?closure_hir_id, ?args, ?final_upvar_tys); - if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params { + if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() { for capture in self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id) { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d3d092be222..391e640f8bc 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -830,7 +830,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased); // Normalize consts in writeback, because GCE doesn't normalize eagerly. - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { value = value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index a006786aa75..1f46155abc8 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -68,7 +68,7 @@ pub(crate) fn assert_dep_graph(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index d25fe4219b5..2075d4214c1 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -140,7 +140,7 @@ pub(crate) fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { } // can't add `#[rustc_clean]` etc without opting into this feature - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 63a8a949e96..9923f05df3c 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { && let hir::IsAsync::Async(async_span) = sig.header.asyncness { // RTN can be used to bound `async fn` in traits in a better way than "always" - if cx.tcx.features().return_type_notation { + if cx.tcx.features().return_type_notation() { return; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 125fe9b3f16..71c667b2cd6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1235,7 +1235,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { def_id: LocalDefId, ) { if fn_kind.asyncness().is_async() - && !cx.tcx.features().async_fn_track_caller + && !cx.tcx.features().async_fn_track_caller() // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { @@ -1424,7 +1424,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) - && cx.tcx.features().generic_const_exprs + && cx.tcx.features().generic_const_exprs() { return; } @@ -1538,7 +1538,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { use rustc_middle::ty::ClauseKind; - if cx.tcx.features().trivial_bounds { + if cx.tcx.features().trivial_bounds() { let predicates = cx.tcx.predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 58fd11fcc29..bdfcc2c0a10 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -243,7 +243,7 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope { + if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() { return; } if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index d029ad93407..cc40b67ab27 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -263,8 +263,8 @@ where && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); - let new_capture_rules = - opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024; + let new_capture_rules = opaque_span.at_least_rust_2024() + || self.tcx.features().lifetime_capture_rules_2024(); if !new_capture_rules && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) { diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs index 44a36142ed4..04f769bf551 100644 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { _: Span, def_id: rustc_span::def_id::LocalDefId, ) { - if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes { + if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes() { Self::check_fn_or_closure(cx, fn_kind, body, def_id); } } diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 5a3666dcbd4..b793ec6a493 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -114,10 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; for bound in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) - // FIXME: ?Drop is not a thing. - && bound.modifiers != hir::TraitBoundModifier::Maybe - { + if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 39fa23766b5..641d1d8e798 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -170,7 +170,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let mut upstream_in_dylibs = FxHashSet::default(); - if tcx.features().rustc_private { + if tcx.features().rustc_private() { // We need this to prevent users of `rustc_driver` from linking dynamically to `std` // which does not work as `std` is also statically linked into `rustc_driver`. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c7953d50406..1e6bc413118 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -265,7 +265,7 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::RawDylib } "link-arg" => { - if !features.link_arg_attribute { + if !features.link_arg_attribute() { feature_err( sess, sym::link_arg_attribute, @@ -314,7 +314,7 @@ impl<'tcx> Collector<'tcx> { .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; }; - if !features.link_cfg { + if !features.link_cfg() { feature_err( sess, sym::link_cfg, @@ -384,7 +384,7 @@ impl<'tcx> Collector<'tcx> { }; macro report_unstable_modifier($feature: ident) { - if !features.$feature { + if !features.$feature() { // FIXME: make this translatable #[expect(rustc::untranslatable_diagnostic)] feature_err( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index afe03531861..ec678c7515b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1765,7 +1765,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_stability(def_id) { record!(self.tables.lookup_stability[def_id] <- stab) } @@ -1776,7 +1776,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_const_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_const_stability(def_id) { record!(self.tables.lookup_const_stability[def_id] <- stab) } @@ -1787,7 +1787,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_default_body_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { record!(self.tables.lookup_default_body_stability[def_id] <- stab) } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 59bc55269a3..2ecf1d0bcf8 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -116,7 +116,7 @@ impl<'tcx> TyCtxt<'tcx> { // @lcnr believes that successfully evaluating even though there are // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. - if !self.features().generic_const_exprs && ct.args.has_non_region_param() { + if !self.features().generic_const_exprs() && ct.args.has_non_region_param() { let def_kind = self.def_kind(instance.def_id()); assert!( matches!( diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 26dcae001e0..515aabbe2fc 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -61,7 +61,7 @@ pub enum OverlapMode { impl OverlapMode { pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode { - let with_negative_coherence = tcx.features().with_negative_coherence; + let with_negative_coherence = tcx.features().with_negative_coherence(); let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence); if with_negative_coherence { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index eb715be22b1..5ab85a69ce6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -109,6 +109,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> { + tcx.debug_assert_args_compatible(uv.def, uv.args); Const::new(tcx, ty::ConstKind::Unevaluated(uv)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 210b115ae37..b682524ae39 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -279,6 +279,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.debug_assert_args_compatible(def_id, args); } + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. Since we're missing a `Self` type, stick on + /// a dummy self type and forward to `debug_assert_args_compatible`. + fn debug_assert_existential_args_compatible( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) { + // FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible` + // to avoid needing to reintern the set of args... + if cfg!(debug_assertions) { + self.debug_assert_args_compatible( + def_id, + self.mk_args_from_iter( + [self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()), + ), + ); + } + } + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output where I: Iterator<Item = T>, @@ -690,15 +710,15 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety { impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features { fn generic_const_exprs(self) -> bool { - self.generic_const_exprs + self.generic_const_exprs() } fn coroutine_clone(self) -> bool { - self.coroutine_clone + self.coroutine_clone() } fn associated_const_equality(self) -> bool { - self.associated_const_equality + self.associated_const_equality() } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4f408ee1574..8bd2ae9128f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -193,7 +193,7 @@ fn suggest_changing_unsized_bound( .enumerate() .filter(|(_, bound)| { if let hir::GenericBound::Trait(poly) = bound - && poly.modifiers == hir::TraitBoundModifier::Maybe + && let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity && poly.trait_ref.trait_def_id() == def_id { true diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index b02eff3bfd6..c49824bb418 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -35,9 +35,6 @@ impl<'tcx> TypeError<'tcx> { TypeError::CyclicTy(_) => "cyclic type of infinite size".into(), TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(), TypeError::Mismatch => "types differ".into(), - TypeError::ConstnessMismatch(values) => { - format!("expected {} bound, found {} bound", values.expected, values.found).into() - } TypeError::PolarityMismatch(values) => { format!("expected {} polarity, found {} polarity", values.expected, values.found) .into() diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 660686f4aa2..63534a3d017 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -395,7 +395,9 @@ impl<'tcx> GenericPredicates<'tcx> { EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) } - pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> { + pub fn instantiate_own_identity( + self, + ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator { EarlyBinder::bind(self.predicates).iter_identity_copied() } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dbf88e643c5..7e65df6b27c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -398,7 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } - ty::Array(inner, len) if tcx.features().transmute_generic_consts => { + ty::Array(inner, len) if tcx.features().transmute_generic_consts() => { let len_eval = len.try_to_target_usize(tcx); if len_eval == Some(0) { return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b5495fa282b..10c3522eb0e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1208,7 +1208,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } - if self.tcx().features().return_type_notation + if self.tcx().features().return_type_notation() && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id) && let ty::Alias(_, alias_ty) = diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4c7bcb1bf2e..504a3c8a6d8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -1,7 +1,5 @@ use std::iter; -use rustc_hir as hir; -use rustc_target::spec::abi; pub use rustc_type_ir::relate::*; use crate::ty::error::{ExpectedFound, TypeError}; @@ -121,26 +119,6 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate< } } -impl<'tcx> Relate<TyCtxt<'tcx>> for hir::Safety { - fn relate<R: TypeRelation<TyCtxt<'tcx>>>( - _relation: &mut R, - a: hir::Safety, - b: hir::Safety, - ) -> RelateResult<'tcx, hir::Safety> { - if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<TyCtxt<'tcx>> for abi::Abi { - fn relate<R: TypeRelation<TyCtxt<'tcx>>>( - _relation: &mut R, - a: abi::Abi, - b: abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) } - } -} - impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> { fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cd9ff9b60d8..4872d8c89eb 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -264,8 +264,6 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { ::rustc_hir::def_id::DefId, - ::rustc_hir::Safety, - ::rustc_target::spec::abi::Abi, crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, @@ -276,6 +274,11 @@ TrivialTypeTraversalAndLiftImpls! { rustc_target::abi::Size, } +TrivialLiftImpls! { + ::rustc_hir::Safety, + ::rustc_target::spec::abi::Abi, +} + /////////////////////////////////////////////////////////////////////////// // Lift implementations diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 74de378c4d7..d8362ccc0a9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -750,7 +750,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit } + if tcx.features().never_type_fallback() { tcx.types.never } else { tcx.types.unit } } // lang and diagnostic tys diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9a3049f3be6..06cbb6c9f1d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -877,8 +877,8 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(effects): This is suspicious and should probably not be done, // especially now that we enforce host effects and then properly handle // effect vars during fallback. - let mut host_always_on = - !self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; + let mut host_always_on = !self.features().effects() + || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; // Compute the constness required by the context. let const_context = self.hir().body_const_context(def_id); @@ -1826,8 +1826,8 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// cause an ICE that we otherwise may want to prevent. pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> { if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic) - && tcx.features().intrinsics) - || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs) + && tcx.features().intrinsics()) + || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs()) { Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 1e67e759aa2..112eac32264 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = this.tcx; - if tcx.features().unsized_fn_params { + if tcx.features().unsized_fn_params() { let ty = expr.ty; let param_env = this.param_env; diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7170aebee7d..37cedd8cf5c 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let ty::Adt(def, _) = ty.kind() && tcx.is_lang_item(def.did(), LangItem::String) { - if !tcx.features().string_deref_patterns { + if !tcx.features().string_deref_patterns() { span_bug!( test.span, "matching on `String` went through without enabling string_deref_patterns" diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 5995d60e7e0..5faefe2f25f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -777,7 +777,7 @@ impl<'tcx> Cx<'tcx> { if_then_scope: region::Scope { id: then.hir_id.local_id, data: { - if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope { + if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() { region::ScopeData::IfThenRescope } else { region::ScopeData::IfThen diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index ae77bce6bb1..8498df59ce6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1126,7 +1126,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( .map(|witness| cx.print_witness_pat(witness)) .collect::<Vec<String>>() .join(" | "); - if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { + if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns() { // Arms with a never pattern don't take a body. pattern } else { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 0a413d68020..cd291058977 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1497,7 +1497,7 @@ fn check_field_tys_sized<'tcx>( ) { // No need to check if unsized_locals/unsized_fn_params is disabled, // since we will error during typeck. - if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params { + if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() { return; } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index d839f46cfbd..930fa129ef2 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -21,6 +21,10 @@ pub(crate) struct CoverageGraph { pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, dominators: Option<Dominators<BasicCoverageBlock>>, + /// Allows nodes to be compared in some total order such that _if_ + /// `a` dominates `b`, then `a < b`. If neither node dominates the other, + /// their relative order is consistent but arbitrary. + dominator_order_rank: IndexVec<BasicCoverageBlock, u32>, } impl CoverageGraph { @@ -54,10 +58,27 @@ impl CoverageGraph { } } - let mut this = Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None }; + let num_nodes = bcbs.len(); + let mut this = Self { + bcbs, + bb_to_bcb, + successors, + predecessors, + dominators: None, + dominator_order_rank: IndexVec::from_elem_n(0, num_nodes), + }; + assert_eq!(num_nodes, this.num_nodes()); this.dominators = Some(dominators::dominators(&this)); + // The dominator rank of each node is just its index in a reverse-postorder traversal. + let reverse_post_order = graph::iterate::reverse_post_order(&this, this.start_node()); + // The coverage graph is created by traversal, so all nodes are reachable. + assert_eq!(reverse_post_order.len(), this.num_nodes()); + for (rank, bcb) in (0u32..).zip(reverse_post_order) { + this.dominator_order_rank[bcb] = rank; + } + // The coverage graph's entry-point node (bcb0) always starts with bb0, // which never has predecessors. Any other blocks merged into bcb0 can't // have multiple (coverage-relevant) predecessors, so bcb0 always has @@ -162,7 +183,7 @@ impl CoverageGraph { a: BasicCoverageBlock, b: BasicCoverageBlock, ) -> Ordering { - self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) + self.dominator_order_rank[a].cmp(&self.dominator_order_rank[b]) } /// Returns the source of this node's sole in-edge, if it has exactly one. diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index daf868559bc..79c62372df0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -288,7 +288,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), evaluated: IndexVec::with_capacity(num_values), next_opaque: Some(1), - feature_unsized_locals: tcx.features().unsized_locals, + feature_unsized_locals: tcx.features().unsized_locals(), ssa, dominators, reused_locals: BitSet::new_empty(local_decls.len()), diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 71ce0cce772..e2fd0dd2a25 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -170,7 +170,7 @@ where // // We don't do so for `NormalizesTo` goals as we erased the expected term and // bailing with overflow here would prevent us from detecting a type-mismatch, - // causing a coherence error in diesel, see #131969. We still bail with verflow + // causing a coherence error in diesel, see #131969. We still bail with overflow // when later returning from the parent AliasRelate goal. if !self.is_normalizes_to_goal { let num_non_region_vars = 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 cbefc826fb7..250174e033e 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 @@ -291,7 +291,7 @@ where search_graph, nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values, input), + inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values), }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 85474bf37b4..1607fbb1b6a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -13,7 +13,7 @@ use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::{ - CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput, + CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryResult, inspect, }; @@ -119,6 +119,9 @@ impl<I: Interner> WipCanonicalGoalEvaluation<I> { } } +/// This only exists during proof tree building and does not have +/// a corresponding struct in `inspect`. We need this to track a +/// bunch of metadata about the current evaluation. #[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipCanonicalGoalEvaluationStep<I: Interner> { /// Unlike `EvalCtxt::var_values`, we append a new @@ -128,7 +131,6 @@ struct WipCanonicalGoalEvaluationStep<I: Interner> { /// This is necessary as we otherwise don't unify these /// vars when instantiating multiple `CanonicalState`. var_values: Vec<I::GenericArg>, - instantiated_goal: QueryInput<I, I::Predicate>, probe_depth: usize, evaluation: WipProbe<I>, } @@ -145,16 +147,12 @@ impl<I: Interner> WipCanonicalGoalEvaluationStep<I> { current } - fn finalize(self) -> inspect::CanonicalGoalEvaluationStep<I> { + fn finalize(self) -> inspect::Probe<I> { let evaluation = self.evaluation.finalize(); match evaluation.kind { - inspect::ProbeKind::Root { .. } => (), + inspect::ProbeKind::Root { .. } => evaluation, _ => unreachable!("unexpected root evaluation: {evaluation:?}"), } - inspect::CanonicalGoalEvaluationStep { - instantiated_goal: self.instantiated_goal, - evaluation, - } } } @@ -328,11 +326,9 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> { pub(crate) fn new_goal_evaluation_step( &mut self, var_values: ty::CanonicalVarValues<I>, - instantiated_goal: QueryInput<I, I::Predicate>, ) -> ProofTreeBuilder<D> { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), - instantiated_goal, evaluation: WipProbe { initial_num_var_values: var_values.len(), steps: vec![], diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 899a7b84100..3f98236595b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -245,6 +245,19 @@ passes_doc_test_unknown_include = unknown `doc` attribute `{$path}` .suggestion = use `doc = include_str!` instead +passes_doc_test_unknown_passes = + unknown `doc` attribute `{$path}` + .note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> + .label = no longer functions + .help = you may want to use `doc(document_private_items)` + .no_op_note = `doc({$path})` is now a no-op + +passes_doc_test_unknown_plugins = + unknown `doc` attribute `{$path}` + .note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622> + .label = no longer functions + .no_op_note = `doc({$path})` is now a no-op + passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index d0cc123c41a..b1267562f7b 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -12,7 +12,7 @@ use super::layout_test::ensure_wf; use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { // if the `rustc_attrs` feature is not enabled, don't bother testing ABI return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8b30546d5cc..86442844823 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1183,19 +1183,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::masked => self.check_doc_masked(attr, meta, hir_id, target), - // no_default_passes: deprecated - // passes: deprecated - // plugins: removed, but rustdoc warns about it itself - sym::cfg - | sym::hidden - | sym::no_default_passes - | sym::notable_trait - | sym::passes - | sym::plugins => {} + sym::cfg | sym::hidden | sym::notable_trait => {} sym::rust_logo => { if self.check_attr_crate_level(attr, meta, hir_id) - && !self.tcx.features().rustdoc_internals + && !self.tcx.features().rustdoc_internals() { feature_err( &self.tcx.sess, @@ -1240,6 +1232,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sugg: (attr.meta().unwrap().span, applicability), }, ); + } else if i_meta.has_name(sym::passes) + || i_meta.has_name(sym::no_default_passes) + { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownPasses { path, span: i_meta.span }, + ); + } else if i_meta.has_name(sym::plugins) { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownPlugins { path, span: i_meta.span }, + ); } else { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1766,7 +1774,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } sym::align => { if let (Target::Fn | Target::Method(MethodKind::Inherent), false) = - (target, self.tcx.features().fn_align) + (target, self.tcx.features().fn_align()) { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index ca13ca11673..f5ece513956 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -105,7 +105,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { + if !tcx.features().staged_api() || tcx.has_attr(def_id, sym::rustc_const_unstable) { return true; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f01ddbd47ef..042e50d890e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -324,6 +324,27 @@ pub(crate) struct DocTestUnknownSpotlight { } #[derive(LintDiagnostic)] +#[diag(passes_doc_test_unknown_passes)] +#[note] +#[help] +#[note(passes_no_op_note)] +pub(crate) struct DocTestUnknownPasses { + pub path: String, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(passes_doc_test_unknown_plugins)] +#[note] +#[note(passes_no_op_note)] +pub(crate) struct DocTestUnknownPlugins { + pub path: String, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] #[diag(passes_doc_test_unknown_include)] pub(crate) struct DocTestUnknownInclude { pub path: String, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 3aef88e771f..93729a7f6df 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -18,7 +18,7 @@ use crate::errors::{ }; pub fn test_layout(tcx: TyCtxt<'_>) { - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { // if the `rustc_attrs` feature is not enabled, don't bother testing layout return; } diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 91ba2fa7548..8a360c017ad 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -144,7 +144,7 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures { // If `staged_api` is not enabled then we aren't allowed to define lib // features; there is no point collecting them. - if !tcx.features().staged_api { + if !tcx.features().staged_api() { return LibFeatures::default(); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 056318fbcb7..0ec151ceb45 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -322,7 +322,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(ty); // Manually visit to actually see the trait's `DefId`. Type visitors won't see it if let Some(trait_ref) = dyn_ty.principal() { - let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder(); + let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder(); self.visit_def_id(def_id, "", &""); self.visit(args); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 80ac2741c38..a176b2bb1ad 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,7 +10,7 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::ACCEPTED_FEATURES; +use rustc_feature::ACCEPTED_LANG_FEATURES; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -144,7 +144,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if !self.tcx.features().staged_api { + if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { @@ -248,7 +248,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } if let Stability { level: Unstable { .. }, feature } = stab { - if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { self.tcx .dcx() .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); @@ -261,7 +261,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab { - if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span item_sp, @@ -541,7 +541,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { - if !self.tcx.features().staged_api { + if !self.tcx.features().staged_api() { return; } @@ -734,7 +734,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // items. hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => { let features = self.tcx.features(); - if features.staged_api { + if features.staged_api() { let attrs = self.tcx.hir().attrs(item.hir_id()); let stab = attr::find_stability(self.tcx.sess, attrs, item.span); let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); @@ -762,7 +762,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable // needs to have an error emitted. - if features.const_trait_impl + if features.const_trait_impl() && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id()) && const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) { @@ -926,7 +926,7 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let is_staged_api = - tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; + tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); if is_staged_api { let effective_visibilities = &tcx.effective_visibilities(()); let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 70a9319d666..0e132b27fb4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -891,7 +891,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap(); s } - Never if self.tcx.features().never_patterns => "!".to_string(), + Never if self.tcx.features().never_patterns() => "!".to_string(), Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(), Missing { .. } => bug!( "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, @@ -915,7 +915,7 @@ fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool { | Constructor::NonExhaustive | Constructor::Hidden | Constructor::PrivateUninhabited => true, - Constructor::Never if !tcx.features().never_patterns => true, + Constructor::Never if !tcx.features().never_patterns() => true, _ => false, } } @@ -929,7 +929,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { type PatData = &'p Pat<'tcx>; fn is_exhaustive_patterns_feature_on(&self) -> bool { - self.tcx.features().exhaustive_patterns + self.tcx.features().exhaustive_patterns() } fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index f67c4cb922c..7827975d3ca 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -32,8 +32,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -246,10 +246,10 @@ where ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { - ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() } + ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty()) } }; - let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref; + let ty::ExistentialTraitRef { def_id, .. } = trait_ref; try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); } } diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 78c37688d34..29a28b10a06 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -115,9 +115,9 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features { self.enabled_lang_features().hash_stable(hcx, hasher); self.enabled_lib_features().hash_stable(hcx, hasher); - self.all_lang_features()[..].hash_stable(hcx, hasher); - for feature in rustc_feature::UNSTABLE_FEATURES.iter() { - feature.feature.name.hash_stable(hcx, hasher); + // FIXME: why do we hash something that is a compile-time constant? + for feature in rustc_feature::UNSTABLE_LANG_FEATURES.iter() { + feature.name.hash_stable(hcx, hasher); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8ae77902bce..b80e0e196ca 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -606,7 +606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { Some(binding) => { if matches!(ident.name, sym::f16) - && !this.tcx.features().f16 + && !this.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) && finalize.is_some() && innermost_result.is_none() @@ -620,7 +620,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit(); } if matches!(ident.name, sym::f128) - && !this.tcx.features().f128 + && !this.tcx.features().f128() && !ident.span.allows_unstable(sym::f128) && finalize.is_some() && innermost_result.is_none() diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 98db36b12be..033cd7d5870 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2683,7 +2683,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item( - if self.r.tcx.features().generic_const_items { + if self.r.tcx.features().generic_const_items() { HasGenericParams::Yes(generics.span) } else { HasGenericParams::No @@ -2888,7 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { RibKind::Normal => { // FIXME(non_lifetime_binders): Stop special-casing // const params to error out here. - if self.r.tcx.features().non_lifetime_binders + if self.r.tcx.features().non_lifetime_binders() && matches!(param.kind, GenericParamKind::Type { .. }) { Res::Def(def_kind, def_id.to_def_id()) @@ -4411,10 +4411,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let tcx = self.r.tcx(); let gate_err_sym_msg = match prim { - PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => { + PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => { Some((sym::f16, "the type `f16` is unstable")) } - PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => { + PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => { Some((sym::f128, "the type `f128` is unstable")) } _ => None, @@ -4565,7 +4565,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { - if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg { + if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg { ConstantHasGenerics::Yes } else { ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 50fbdcaf9dc..f0632a21091 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1198,7 +1198,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the // benefits of including them here outweighs the small number of false positives. Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) - if self.r.tcx.features().adt_const_params => + if self.r.tcx.features().adt_const_params() => { Applicability::MaybeIncorrect } @@ -2773,7 +2773,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Avoid suggesting placing lifetime parameters on constant items unless the relevant // feature is enabled. Suggest the parent item as a possible location if applicable. if let LifetimeBinderKind::ConstItem = kind - && !self.r.tcx().features().generic_const_items + && !self.r.tcx().features().generic_const_items() { continue; } @@ -2934,7 +2934,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .emit(); } NoConstantGenericsReason::NonTrivialConstArg => { - assert!(!self.r.tcx.features().generic_const_exprs); + assert!(!self.r.tcx.features().generic_const_exprs()); self.r .dcx() .create_err(errors::ParamInNonTrivialAnonConst { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5e38fb5b6c5..a9ebffea8a1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -661,7 +661,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We are trying to avoid reporting this error if other related errors were reported. - if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes { + if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() { let is_macro = match res { Res::Def(..) => true, Res::NonMacroAttr(..) => false, @@ -690,7 +690,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && namespace.ident.name == sym::diagnostic && !(attribute.ident.name == sym::on_unimplemented || (attribute.ident.name == sym::do_not_recommend - && self.tcx.features().do_not_recommend)) + && self.tcx.features().do_not_recommend())) { let distance = edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 83dcceeaa84..cba79a02f8b 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -245,11 +245,15 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc alias_ty.to_ty(tcx), ); debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: assoc_ty.def_id, - args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, - term: resolved.into(), - }) + ty::ExistentialPredicate::Projection( + ty::ExistentialProjection::erase_self_ty( + tcx, + ty::ProjectionPredicate { + projection_term: alias_ty.into(), + term: resolved.into(), + }, + ), + ) }) }) }) @@ -318,10 +322,11 @@ pub(crate) fn transform_instance<'tcx>( .lang_items() .drop_trait() .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); - let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args( + tcx, def_id, - args: List::empty(), - }); + ty::List::empty(), + )); let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e9c3b3ffc1d..7be7db1fd3d 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -380,11 +380,12 @@ impl RustcInternal for ExistentialProjection { type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialProjection { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - term: self.term.internal(tables, tcx), - } + rustc_ty::ExistentialProjection::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + self.term.internal(tables, tcx), + ) } } @@ -403,10 +404,11 @@ impl RustcInternal for ExistentialTraitRef { type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialTraitRef { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - } + rustc_ty::ExistentialTraitRef::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + ) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b9372283feb..ef2ee9a166a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -68,7 +68,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { type T = stable_mir::ty::ExistentialTraitRef; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialTraitRef { def_id, args } = self; + let ty::ExistentialTraitRef { def_id, args, .. } = self; stable_mir::ty::ExistentialTraitRef { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), @@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { type T = stable_mir::ty::ExistentialProjection; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialProjection { def_id, args, term } = self; + let ty::ExistentialProjection { def_id, args, term, .. } = self; stable_mir::ty::ExistentialProjection { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 8cfb65c1c50..73bd8d7555b 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -18,7 +18,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 4a21935623b..ffec76370d0 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -1,6 +1,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(Copy, Clone)] enum RegPassKind { @@ -359,3 +360,30 @@ where ); } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if abi == SpecAbi::RustIntrinsic { + return; + } + + let grlen = cx.data_layout().pointer_size.bits(); + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() { + continue; + } + + // LLVM integers types do not differentiate between signed or unsigned integers. + // Some LoongArch instructions do not have a `.w` suffix version, they use all the + // GRLEN bits. By explicitly setting the `signext` or `zeroext` attribute + // according to signedness to avoid unnecessary integer extending instructions. + // + // This is similar to the RISC-V case, see + // https://github.com/rust-lang/rust/issues/114508 for details. + extend_integer_width(arg, grlen); + } +} diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 5d120a68059..25b001b57e8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,11 +1,14 @@ -use std::fmt; use std::str::FromStr; +use std::{fmt, iter}; pub use rustc_abi::{Reg, RegKind}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; -use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; +use crate::abi::{ + self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout, +}; +use crate::spec::abi::Abi as SpecAbi; use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; mod aarch64; @@ -720,6 +723,118 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } + + pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: SpecAbi) + where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, + { + let spec = cx.target_spec(); + match &spec.arch[..] { + "x86" => x86::compute_rust_abi_info(cx, self, abi), + "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), + "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), + _ => {} + }; + + for (arg_idx, arg) in self + .args + .iter_mut() + .enumerate() + .map(|(idx, arg)| (Some(idx), arg)) + .chain(iter::once((None, &mut self.ret))) + { + if arg.is_ignore() { + continue; + } + + if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 { + // Return values larger than 2 registers using a return area + // pointer. LLVM and Cranelift disagree about how to return + // values that don't fit in the registers designated for return + // values. LLVM will force the entire return value to be passed + // by return area pointer, while Cranelift will look at each IR level + // return value independently and decide to pass it in a + // register or not, which would result in the return value + // being passed partially in registers and partially through a + // return area pointer. + // + // While Cranelift may need to be fixed as the LLVM behavior is + // generally more correct with respect to the surface language, + // forcing this behavior in rustc itself makes it easier for + // other backends to conform to the Rust ABI and for the C ABI + // rustc already handles this behavior anyway. + // + // In addition LLVM's decision to pass the return value in + // registers or using a return area pointer depends on how + // exactly the return type is lowered to an LLVM IR type. For + // example `Option<u128>` can be lowered as `{ i128, i128 }` + // in which case the x86_64 backend would use a return area + // pointer, or it could be passed as `{ i32, i128 }` in which + // case the x86_64 backend would pass it in registers by taking + // advantage of an LLVM ABI extension that allows using 3 + // registers for the x86_64 sysv call conv rather than the + // officially specified 2 registers. + // + // FIXME: Technically we should look at the amount of available + // return registers rather than guessing that there are 2 + // registers for return values. In practice only a couple of + // architectures have less than 2 return registers. None of + // which supported by Cranelift. + // + // NOTE: This adjustment is only necessary for the Rust ABI as + // for other ABI's the calling convention implementations in + // rustc_target already ensure any return value which doesn't + // fit in the available amount of return registers is passed in + // the right way for the current target. + arg.make_indirect(); + continue; + } + + match arg.layout.abi { + Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => { + arg.make_indirect(); + continue; + } + + _ => continue, + } + // Compute `Aggregate` ABI. + + let is_indirect_not_on_stack = + matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); + assert!(is_indirect_not_on_stack); + + let size = arg.layout.size; + if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) { + // We want to pass small aggregates as immediates, but using + // an LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { kind: RegKind::Integer, size }); + } + } + } } impl FromStr for Conv { diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index be6bc701b49..f96169e6a61 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -7,6 +7,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(Copy, Clone)] enum RegPassKind { @@ -365,3 +366,29 @@ where ); } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if abi == SpecAbi::RustIntrinsic { + return; + } + + let xlen = cx.data_layout().pointer_size.bits(); + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() { + continue; + } + + // LLVM integers types do not differentiate between signed or unsigned integers. + // Some RISC-V instructions do not have a `.w` suffix version, they use all the + // XLEN bits. By explicitly setting the `signext` or `zeroext` attribute + // according to signedness to avoid unnecessary integer extending instructions. + // + // See https://github.com/rust-lang/rust/issues/114508 for details. + extend_integer_width(arg, xlen); + } +} diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 40c3e7a891a..e907beecb38 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -1,6 +1,9 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{ + Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, +}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(PartialEq)] pub(crate) enum Flavor { @@ -207,3 +210,35 @@ pub(crate) fn fill_inregs<'a, Ty, C>( } } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + // Avoid returning floats in x87 registers on x86 as loading and storing from x87 + // registers will quiet signalling NaNs. Also avoid using SSE registers since they + // are not always available (depending on target features). + if !fn_abi.ret.is_ignore() + // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs. + && abi != SpecAbi::RustIntrinsic + { + let has_float = match fn_abi.ret.layout.abi { + Abi::Scalar(s) => matches!(s.primitive(), Float(_)), + Abi::ScalarPair(s1, s2) => { + matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_)) + } + _ => false, // anyway not passed via registers on x86 + }; + if has_float { + if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) { + // Same size or smaller than pointer, return in a register. + fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size }); + } else { + // Larger than a pointer, return indirectly. + fn_abi.ret.make_indirect(); + } + return; + } + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 62204f63dd0..0cf7c43beb5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. let trait_bounds = bounds.iter().filter_map(|bound| match bound { - hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => { + hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => { Some(ptr) } _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 549beafd196..9ee4963a360 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3026,7 +3026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, span: Span, ) -> Result<Diag<'a>, ErrorGuaranteed> { - if !self.tcx.features().generic_const_exprs { + if !self.tcx.features().generic_const_exprs() { let guar = self .dcx() .struct_span_err(span, "constant expression depends on a generic parameter") 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 677905a3085..1fe93cb017a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3044,7 +3044,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if local { err.note("all local variables must have a statically known size"); } - if !tcx.features().unsized_locals { + if !tcx.features().unsized_locals() { err.help("unsized locals are gated as an unstable feature"); } } @@ -3125,7 +3125,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("all function arguments must have a statically known size"); } if tcx.sess.opts.unstable_features.is_nightly_build() - && !tcx.features().unsized_fn_params + && !tcx.features().unsized_fn_params() { err.help("unsized fn params are gated as an unstable feature"); } @@ -3594,52 +3594,64 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) = - self.tcx.coroutine_kind(obligation.cause.body_id) - { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - let impls_future = self.type_implements_trait( - future_trait, - [self.tcx.instantiate_bound_regions_with_erased(self_ty)], - obligation.param_env, - ); - if !impls_future.must_apply_modulo_regions() { - return; - } + let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); + let impls_future = self.type_implements_trait( + future_trait, + [self.tcx.instantiate_bound_regions_with_erased(self_ty)], + obligation.param_env, + ); + if !impls_future.must_apply_modulo_regions() { + return; + } - let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - // `<T as Future>::Output` - let projection_ty = trait_pred.map_bound(|trait_pred| { - Ty::new_projection( - self.tcx, - item_def_id, - // Future::Output has no args - [trait_pred.self_ty()], - ) - }); - let InferOk { value: projection_ty, .. } = - self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + // `<T as Future>::Output` + let projection_ty = trait_pred.map_bound(|trait_pred| { + Ty::new_projection( + self.tcx, + item_def_id, + // Future::Output has no args + [trait_pred.self_ty()], + ) + }); + let InferOk { value: projection_ty, .. } = + self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); - debug!( - normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) - ); - let try_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), - ); - debug!(try_trait_obligation = ?try_obligation); - if self.predicate_may_hold(&try_obligation) - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - && snippet.ends_with('?') - { - err.span_suggestion_verbose( - span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await", - Applicability::MaybeIncorrect, - ); + debug!( + normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) + ); + let try_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), + ); + debug!(try_trait_obligation = ?try_obligation); + if self.predicate_may_hold(&try_obligation) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && snippet.ends_with('?') + { + match self.tcx.coroutine_kind(obligation.cause.body_id) { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + err.span_suggestion_verbose( + span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, + ); + } + _ => { + let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into(); + span.push_span_label( + self.tcx.def_span(obligation.cause.body_id), + "this is not `async`", + ); + err.span_note( + span, + "this implements `Future` and its output type supports \ + `?`, but the future cannot be awaited in a synchronous function", + ); + } } } } @@ -4498,7 +4510,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, ) { // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. - if self.tcx.features().return_type_notation { + if self.tcx.features().return_type_notation() { return; } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 4975a9ce0c7..e735020a63e 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { }; let mut nested_goals = vec![]; - self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step.evaluation); + self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step); candidates } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index c258832bf2b..1be3c964454 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -40,7 +40,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { let ct = tcx.expand_abstract_consts(unexpanded_ct); let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 364a13b3a75..cc0450e0b05 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -254,7 +254,7 @@ fn super_predicates_have_non_lifetime_binders( trait_def_id: DefId, ) -> SmallVec<[Span; 1]> { // If non_lifetime_binders is disabled, then exit early - if !tcx.features().non_lifetime_binders { + if !tcx.features().non_lifetime_binders() { return SmallVec::new(); } tcx.explicit_super_predicates_of(trait_def_id) @@ -327,7 +327,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( .collect(), // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. ty::AssocKind::Type => { - if !tcx.features().generic_associated_types_extended + if !tcx.features().generic_associated_types_extended() && !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e56f1866970..2bdeb00bdac 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -598,7 +598,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let tcx = self.selcx.tcx(); assert!( - tcx.features().generic_const_exprs, + tcx.features().generic_const_exprs(), "`ConstEquate` without a feature gate: {c1:?} {c2:?}", ); // FIXME: we probably should only try to unify abstract constants diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index cffb9b59841..cdf24887e76 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -346,7 +346,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates: Vec<_> = util::elaborate( tcx, unnormalized_env.caller_bounds().into_iter().map(|predicate| { - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { return predicate; } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d246d37f748..12e00ec79ac 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -402,7 +402,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs + if tcx.features().generic_const_exprs() || !needs_normalization(&constant, self.param_env.reveal()) { constant diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index cc634b65a0b..38722c0ff7c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -189,7 +189,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), ProjectAndUnifyResult::Holds(obligations) if old_universe != new_universe - && selcx.tcx().features().generic_associated_types_extended => + && selcx.tcx().features().generic_associated_types_extended() => { // If the `generic_associated_types_extended` feature is active, then we ignore any // obligations references lifetimes from any universe greater than or equal to the diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index ac38c9e24a2..eea3867190d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -876,7 +876,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().dyn_compatible_for_dispatch { + if !self.infcx.tcx.features().dyn_compatible_for_dispatch() { principal.with_self_ty(self.tcx(), self_ty) } else if self.tcx().is_dyn_compatible(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) @@ -936,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let tcx = self.tcx(); - if tcx.features().trait_upcasting { + if tcx.features().trait_upcasting() { return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9a49fd7e77e..e7d3004aa20 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut assume = predicate.trait_ref.args.const_at(2); // FIXME(min_generic_const_exprs): We should shallowly normalize this. - if self.tcx().features().generic_const_exprs { + if self.tcx().features().generic_const_exprs() { assume = assume.normalize_internal(self.tcx(), obligation.param_env); } let Some(assume) = @@ -626,7 +626,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { let defs: &ty::Generics = tcx.generics_of(assoc_type); - if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended { + if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended() { tcx.dcx().span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4757430a21c..d5b1c5a97da 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -865,7 +865,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let tcx = self.tcx(); assert!( - tcx.features().generic_const_exprs, + tcx.features().generic_const_exprs(), "`ConstEquate` without a feature gate: {c1:?} {c2:?}", ); @@ -2195,7 +2195,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => None, hir::Movability::Movable => { - if self.tcx().features().coroutine_clone { + if self.tcx().features().coroutine_clone() { let resolved_upvars = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let resolved_witness = diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b82a3433645..0e45f7a195f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -136,7 +136,7 @@ pub fn translate_args_with_cause<'tcx>( } pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool { - tcx.features().specialization || tcx.features().min_specialization + tcx.features().specialization() || tcx.features().min_specialization() } /// Is `impl1` a specialization of `impl2`? diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index f8d98eb856e..23b5f62b5ca 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -82,7 +82,7 @@ impl<'tcx> At<'_, 'tcx> { } Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) - } else if self.infcx.tcx.features().generic_const_exprs { + } else if self.infcx.tcx.features().generic_const_exprs() { Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) } else { Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 07e68e5a3e8..8904a9a6858 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -836,7 +836,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch; + let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch(); if !defer_to_coercion { if let Some(principal) = data.principal_def_id() { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 13691204c96..48149a08de8 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,8 +1,7 @@ use std::iter; -use rustc_abi::Float::*; -use rustc_abi::Primitive::{Float, Pointer}; -use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size}; +use rustc_abi::Primitive::Pointer; +use rustc_abi::{Abi, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; @@ -14,8 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, - RiscvInterruptKind, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind, }; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; @@ -679,6 +677,8 @@ fn fn_abi_adjust_for_abi<'tcx>( let tcx = cx.tcx(); if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic { + fn_abi.adjust_for_rust_abi(cx, abi); + // Look up the deduced parameter attributes for this function, if we have its def ID and // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes // as appropriate. @@ -689,131 +689,9 @@ fn fn_abi_adjust_for_abi<'tcx>( &[] }; - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| { + for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { if arg.is_ignore() { - return; - } - - // Avoid returning floats in x87 registers on x86 as loading and storing from x87 - // registers will quiet signalling NaNs. - if tcx.sess.target.arch == "x86" - && arg_idx.is_none() - // Intrinsics themselves are not actual "real" functions, so theres no need to - // change their ABIs. - && abi != SpecAbi::RustIntrinsic - { - match arg.layout.abi { - // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled - // below, by returning arguments up to the size of a pointer (32 bits on x86) - // cast to an appropriately sized integer. - Abi::Scalar(s) if s.primitive() == Float(F32) => { - // Same size as a pointer, return in a register. - arg.cast_to(Reg::i32()); - return; - } - Abi::Scalar(s) if s.primitive() == Float(F64) => { - // Larger than a pointer, return indirectly. - arg.make_indirect(); - return; - } - Abi::ScalarPair(s1, s2) - if matches!(s1.primitive(), Float(F32 | F64)) - || matches!(s2.primitive(), Float(F32 | F64)) => - { - // Larger than a pointer, return indirectly. - arg.make_indirect(); - return; - } - _ => {} - }; - } - - if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 { - // Return values larger than 2 registers using a return area - // pointer. LLVM and Cranelift disagree about how to return - // values that don't fit in the registers designated for return - // values. LLVM will force the entire return value to be passed - // by return area pointer, while Cranelift will look at each IR level - // return value independently and decide to pass it in a - // register or not, which would result in the return value - // being passed partially in registers and partially through a - // return area pointer. - // - // While Cranelift may need to be fixed as the LLVM behavior is - // generally more correct with respect to the surface language, - // forcing this behavior in rustc itself makes it easier for - // other backends to conform to the Rust ABI and for the C ABI - // rustc already handles this behavior anyway. - // - // In addition LLVM's decision to pass the return value in - // registers or using a return area pointer depends on how - // exactly the return type is lowered to an LLVM IR type. For - // example `Option<u128>` can be lowered as `{ i128, i128 }` - // in which case the x86_64 backend would use a return area - // pointer, or it could be passed as `{ i32, i128 }` in which - // case the x86_64 backend would pass it in registers by taking - // advantage of an LLVM ABI extension that allows using 3 - // registers for the x86_64 sysv call conv rather than the - // officially specified 2 registers. - // - // FIXME: Technically we should look at the amount of available - // return registers rather than guessing that there are 2 - // registers for return values. In practice only a couple of - // architectures have less than 2 return registers. None of - // which supported by Cranelift. - // - // NOTE: This adjustment is only necessary for the Rust ABI as - // for other ABI's the calling convention implementations in - // rustc_target already ensure any return value which doesn't - // fit in the available amount of return registers is passed in - // the right way for the current target. - arg.make_indirect(); - return; - } - - match arg.layout.abi { - Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - Abi::Vector { .. } - if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect => - { - arg.make_indirect(); - return; - } - - _ => return, - } - // Compute `Aggregate` ABI. - - let is_indirect_not_on_stack = - matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); - assert!(is_indirect_not_on_stack, "{:?}", arg); - - let size = arg.layout.size; - if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) { - // We want to pass small aggregates as immediates, but using - // an LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); + continue; } // If we deduced that this parameter was read-only, add that to the attribute list now. @@ -821,9 +699,7 @@ fn fn_abi_adjust_for_abi<'tcx>( // The `readonly` parameter only applies to pointers, so we can only do this if the // argument was passed indirectly. (If the argument is passed directly, it's an SSA // value, so it's implicitly immutable.) - if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) = - (arg_idx, &mut arg.mode) - { + if let &mut PassMode::Indirect { ref mut attrs, .. } = &mut arg.mode { // The `deduced_param_attrs` list could be empty if this is a type of function // we can't deduce any parameters for, so make sure the argument index is in // bounds. @@ -834,11 +710,6 @@ fn fn_abi_adjust_for_abi<'tcx>( } } } - }; - - fixup(&mut fn_abi.ret, None); - for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { - fixup(arg, Some(arg_idx)); } } else { fn_abi diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a057caa9329..a3210dd80d7 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -181,7 +181,7 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { // don't synthesize the associated type even if the user has written `const_trait` // if the effects feature is disabled. - if !tcx.features().effects { + if !tcx.features().effects() { return None; } let (feed, parent_did) = match tcx.def_kind(def_id) { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 391985ce88a..4b770d9938c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -406,7 +406,7 @@ fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: LocalDefId, ) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> { - if !tcx.features().generic_const_exprs { + if !tcx.features().generic_const_exprs() { return Ok(None); } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index f20beb79750..c06a578d8ec 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -496,8 +496,8 @@ where /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), /// but on an iterator of values that deref to a `TypeFoldable`. - pub fn iter_identity_copied(self) -> impl Iterator<Item = <Iter::Item as Deref>::Target> { - self.value.into_iter().map(|v| *v) + pub fn iter_identity_copied(self) -> IterIdentityCopied<Iter> { + IterIdentityCopied { it: self.value.into_iter() } } } @@ -546,6 +546,44 @@ where { } +pub struct IterIdentityCopied<Iter: IntoIterator> { + it: Iter::IntoIter, +} + +impl<Iter: IntoIterator> Iterator for IterIdentityCopied<Iter> +where + Iter::Item: Deref, + <Iter::Item as Deref>::Target: Copy, +{ + type Item = <Iter::Item as Deref>::Target; + + fn next(&mut self) -> Option<Self::Item> { + self.it.next().map(|i| *i) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.it.size_hint() + } +} + +impl<Iter: IntoIterator> DoubleEndedIterator for IterIdentityCopied<Iter> +where + Iter::IntoIter: DoubleEndedIterator, + Iter::Item: Deref, + <Iter::Item as Deref>::Target: Copy, +{ + fn next_back(&mut self) -> Option<Self::Item> { + self.it.next_back().map(|i| *i) + } +} + +impl<Iter: IntoIterator> ExactSizeIterator for IterIdentityCopied<Iter> +where + Iter::IntoIter: ExactSizeIterator, + Iter::Item: Deref, + <Iter::Item as Deref>::Target: Copy, +{ +} pub struct EarlyBinderIter<I, T> { t: T, _tcx: PhantomData<I>, diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 8a6d37b7d23..cdff77f742d 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -27,10 +27,9 @@ impl<T> ExpectedFound<T> { #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum TypeError<I: Interner> { Mismatch, - ConstnessMismatch(ExpectedFound<ty::BoundConstness>), - PolarityMismatch(ExpectedFound<ty::PredicatePolarity>), - SafetyMismatch(ExpectedFound<I::Safety>), - AbiMismatch(ExpectedFound<I::Abi>), + PolarityMismatch(#[type_visitable(ignore)] ExpectedFound<ty::PredicatePolarity>), + SafetyMismatch(#[type_visitable(ignore)] ExpectedFound<I::Safety>), + AbiMismatch(#[type_visitable(ignore)] ExpectedFound<I::Abi>), Mutability, ArgumentMutability(usize), TupleSize(ExpectedFound<usize>), @@ -73,9 +72,9 @@ impl<I: Interner> TypeError<I> { pub fn must_include_note(self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch + | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | ArgumentMutability(_) diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f7875bb5152..02ec29a7f3d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -208,14 +208,14 @@ pub trait Tys<I: Interner<Tys = Self>>: fn output(self) -> I::Ty; } -pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + Relate<I> { +pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq { fn rust() -> Self; /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + Relate<I> { +pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq { fn safe() -> Self; fn is_safe(self) -> bool; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f06017d7e5c..4184e9e313f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,9 +15,7 @@ use crate::solve::{ CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, }; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{ - search_graph, {self as ty}, -}; +use crate::{self as ty, search_graph}; pub trait Interner: Sized @@ -173,6 +171,10 @@ pub trait Interner: fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. + fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output where I: Iterator<Item = T>, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index b613505f826..e8ce39be3e5 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -289,9 +289,26 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> { pub struct ExistentialTraitRef<I: Interner> { pub def_id: I::DefId, pub args: I::GenericArgs, + /// This field exists to prevent the creation of `ExistentialTraitRef` without + /// calling [`ExistentialTraitRef::new_from_args`]. + _use_existential_trait_ref_new_instead: (), } impl<I: Interner> ExistentialTraitRef<I> { + pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self { + interner.debug_assert_existential_args_compatible(trait_def_id, args); + Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () } + } + + pub fn new( + interner: I, + trait_def_id: I::DefId, + args: impl IntoIterator<Item: Into<I::GenericArg>>, + ) -> Self { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, trait_def_id, args) + } + pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> { // Assert there is a Self. trait_ref.args.type_at(0); @@ -299,6 +316,7 @@ impl<I: Interner> ExistentialTraitRef<I> { ExistentialTraitRef { def_id: trait_ref.def_id, args: interner.mk_args(&trait_ref.args.as_slice()[1..]), + _use_existential_trait_ref_new_instead: (), } } @@ -336,9 +354,33 @@ pub struct ExistentialProjection<I: Interner> { pub def_id: I::DefId, pub args: I::GenericArgs, pub term: I::Term, + + /// This field exists to prevent the creation of `ExistentialProjection` + /// without using [`ExistentialProjection::new_from_args`]. + use_existential_projection_new_instead: (), } impl<I: Interner> ExistentialProjection<I> { + pub fn new_from_args( + interner: I, + def_id: I::DefId, + args: I::GenericArgs, + term: I::Term, + ) -> ExistentialProjection<I> { + interner.debug_assert_existential_args_compatible(def_id, args); + Self { def_id, args, term, use_existential_projection_new_instead: () } + } + + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator<Item: Into<I::GenericArg>>, + term: I::Term, + ) -> ExistentialProjection<I> { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, def_id, args, term) + } + /// Extracts the underlying existential trait reference from this projection. /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait @@ -347,7 +389,7 @@ impl<I: Interner> ExistentialProjection<I> { let def_id = interner.parent(self.def_id); let args_count = interner.generics_of(def_id).count() - 1; let args = interner.mk_args(&self.args.as_slice()[..args_count]); - ExistentialTraitRef { def_id, args } + ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () } } pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> { @@ -372,6 +414,7 @@ impl<I: Interner> ExistentialProjection<I> { def_id: projection_predicate.projection_term.def_id, args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]), term: projection_predicate.term, + use_existential_projection_new_instead: (), } } } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e1f3e493e36..ad17911830b 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -174,12 +174,17 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> { ExpectedFound::new(true, a, b) })); } - let safety = relation.relate(a.safety, b.safety)?; - let abi = relation.relate(a.abi, b.abi)?; + + if a.safety != b.safety { + return Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a.safety, b.safety))); + } + + if a.abi != b.abi { + return Err(TypeError::AbiMismatch(ExpectedFound::new(true, a.abi, b.abi))); + }; let a_inputs = a.inputs(); let b_inputs = b.inputs(); - if a_inputs.len() != b_inputs.len() { return Err(TypeError::ArgCount); } @@ -212,26 +217,12 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> { Ok(ty::FnSig { inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?, c_variadic: a.c_variadic, - safety, - abi, + safety: a.safety, + abi: a.abi, }) } } -impl<I: Interner> Relate<I> for ty::BoundConstness { - fn relate<R: TypeRelation<I>>( - _relation: &mut R, - a: ty::BoundConstness, - b: ty::BoundConstness, - ) -> RelateResult<I, ty::BoundConstness> { - if a != b { - Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b))) - } else { - Ok(a) - } - } -} - impl<I: Interner> Relate<I> for ty::AliasTy<I> { fn relate<R: TypeRelation<I>>( relation: &mut R, @@ -333,7 +324,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> { a.args, b.args, )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term)) } } } @@ -373,7 +364,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> { })) } else { let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -659,29 +650,18 @@ impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> { } } -impl<I: Interner> Relate<I> for ty::PredicatePolarity { - fn relate<R: TypeRelation<I>>( - _relation: &mut R, - a: ty::PredicatePolarity, - b: ty::PredicatePolarity, - ) -> RelateResult<I, ty::PredicatePolarity> { - if a != b { - Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b))) - } else { - Ok(a) - } - } -} - impl<I: Interner> Relate<I> for ty::TraitPredicate<I> { fn relate<R: TypeRelation<I>>( relation: &mut R, a: ty::TraitPredicate<I>, b: ty::TraitPredicate<I>, ) -> RelateResult<I, ty::TraitPredicate<I>> { - Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, - polarity: relation.relate(a.polarity, b.polarity)?, - }) + let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?; + if a.polarity != b.polarity { + return Err(TypeError::PolarityMismatch(ExpectedFound::new( + true, a.polarity, b.polarity, + ))); + } + Ok(ty::TraitPredicate { trait_ref, polarity: a.polarity }) } } diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 138ba8bac88..d0e618dc6f9 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -23,9 +23,7 @@ use std::hash::Hash; use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::solve::{ - CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, -}; +use crate::solve::{CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; /// Some `data` together with information about how they relate to the input @@ -69,15 +67,10 @@ pub struct CanonicalGoalEvaluation<I: Interner> { #[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub enum CanonicalGoalEvaluationKind<I: Interner> { Overflow, - Evaluation { final_revision: CanonicalGoalEvaluationStep<I> }, -} - -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] -pub struct CanonicalGoalEvaluationStep<I: Interner> { - pub instantiated_goal: QueryInput<I, I::Predicate>, - - /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: Probe<I>, + Evaluation { + /// This is always `ProbeKind::Root`. + final_revision: Probe<I>, + }, } /// A self-contained computation during trait solving. This either diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index b7f6ef4ffbb..499e6d3dd37 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -861,7 +861,11 @@ pub struct TypeAndMut<I: Interner> { pub struct FnSig<I: Interner> { pub inputs_and_output: I::Tys, pub c_variadic: bool, + #[type_visitable(ignore)] + #[type_foldable(identity)] pub safety: I::Safety, + #[type_visitable(ignore)] + #[type_foldable(identity)] pub abi: I::Abi, } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 09a43b17955..10b164eae02 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -372,8 +372,12 @@ pub struct CoroutineClosureSignature<I: Interner> { /// Always false pub c_variadic: bool, /// Always `Normal` (safe) + #[type_visitable(ignore)] + #[type_foldable(identity)] pub safety: I::Safety, /// Always `RustCall` + #[type_visitable(ignore)] + #[type_foldable(identity)] pub abi: I::Abi, } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 1a0a2479f6f..aaf69e2648d 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -1,18 +1,73 @@ -use quote::quote; -use syn::parse_quote; +use quote::{ToTokens, quote}; use syn::visit_mut::VisitMut; +use syn::{Attribute, parse_quote}; use synstructure::decl_derive; decl_derive!( - [TypeFoldable_Generic] => type_foldable_derive + [TypeVisitable_Generic, attributes(type_visitable)] => type_visitable_derive ); decl_derive!( - [TypeVisitable_Generic] => type_visitable_derive + [TypeFoldable_Generic, attributes(type_foldable)] => type_foldable_derive ); decl_derive!( [Lift_Generic] => lift_derive ); +fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool { + let mut ignored = false; + attrs.iter().for_each(|attr| { + if !attr.path().is_ident(name) { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident(meta) { + ignored = true; + } + Ok(()) + }); + }); + + ignored +} + +fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { + s.add_impl_generic(parse_quote! { I }); + } + + s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_visitable", "ignore")); + + s.add_where_predicate(parse_quote! { I: Interner }); + s.add_bounds(synstructure::AddBounds::Fields); + let body_visit = s.each(|bind| { + quote! { + match ::rustc_ast_ir::visit::VisitorResult::branch( + ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) + ) { + ::core::ops::ControlFlow::Continue(()) => {}, + ::core::ops::ControlFlow::Break(r) => { + return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); + }, + } + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); + + s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable<I>), quote! { + fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>( + &self, + __visitor: &mut __V + ) -> __V::Result { + match *self { #body_visit } + <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + } + }) +} + fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { panic!("cannot derive on union") @@ -29,12 +84,23 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; - quote! { - ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + } } }) }); + // We filter fields which get ignored and don't require them to implement + // `TypeFoldable`. We do so after generating `body_fold` as we still need + // to generate code for them. + s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_foldable", "identity")); + s.add_bounds(synstructure::AddBounds::Fields); s.bound_impl(quote!(::rustc_type_ir::fold::TypeFoldable<I>), quote! { fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder<I>>( self, @@ -113,39 +179,3 @@ fn lift(mut ty: syn::Type) -> syn::Type { ty } - -fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - if let syn::Data::Union(_) = s.ast().data { - panic!("cannot derive on union") - } - - if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { - s.add_impl_generic(parse_quote! { I }); - } - - s.add_where_predicate(parse_quote! { I: Interner }); - s.add_bounds(synstructure::AddBounds::Fields); - let body_visit = s.each(|bind| { - quote! { - match ::rustc_ast_ir::visit::VisitorResult::branch( - ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) - ) { - ::core::ops::ControlFlow::Continue(()) => {}, - ::core::ops::ControlFlow::Break(r) => { - return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); - }, - } - } - }); - s.bind_with(|_| synstructure::BindStyle::Move); - - s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable<I>), quote! { - fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>( - &self, - __visitor: &mut __V - ) -> __V::Result { - match *self { #body_visit } - <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() - } - }) -} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e98ae7c31ad..582d850e14b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2312,7 +2312,16 @@ impl<T: Default> Default for Rc<T> { /// ``` #[inline] fn default() -> Rc<T> { - Rc::new(Default::default()) + unsafe { + Self::from_inner( + Box::leak(Box::write(Box::new_uninit(), RcInner { + strong: Cell::new(1), + weak: Cell::new(1), + value: T::default(), + })) + .into(), + ) + } } } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 52ceb8b45f9..26c1ba2a5c4 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -269,8 +269,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String { - // Fast path for ASCII to ASCII case. - + // Fast path for replacing a single ASCII character with another. if let Some(from_byte) = match from.as_utf8_pattern() { Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte), Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()), @@ -280,8 +279,13 @@ impl str { return unsafe { replace_ascii(self.as_bytes(), from_byte, *to_byte) }; } } - - let mut result = String::new(); + // Set result capacity to self.len() when from.len() <= to.len() + let default_capacity = match from.as_utf8_pattern() { + Some(Utf8Pattern::StringPattern(s)) if s.len() <= to.len() => self.len(), + Some(Utf8Pattern::CharPattern(c)) if c.len_utf8() <= to.len() => self.len(), + _ => 0, + }; + let mut result = String::with_capacity(default_capacity); let mut last_end = 0; for (start, part) in self.match_indices(from) { result.push_str(unsafe { self.get_unchecked(last_end..start) }); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index acbc325a514..13677245e98 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3447,13 +3447,16 @@ impl<T: Default> Default for Arc<T> { /// assert_eq!(*x, 0); /// ``` fn default() -> Arc<T> { - let x = Box::into_raw(Box::write(Box::new_uninit(), ArcInner { - strong: atomic::AtomicUsize::new(1), - weak: atomic::AtomicUsize::new(1), - data: T::default(), - })); - // SAFETY: `Box::into_raw` consumes the `Box` and never returns null - unsafe { Self::from_inner(NonNull::new_unchecked(x)) } + unsafe { + Self::from_inner( + Box::leak(Box::write(Box::new_uninit(), ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data: T::default(), + })) + .into(), + ) + } } } diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 1769612def0..9cb00644e64 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -257,3 +257,29 @@ impl SliceContains for i8 { memchr::memchr(byte, bytes).is_some() } } + +macro_rules! impl_slice_contains { + ($($t:ty),*) => { + $( + impl SliceContains for $t { + #[inline] + fn slice_contains(&self, arr: &[$t]) -> bool { + // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors). + // The compiler will nicely unroll it. + const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8)); + // SIMD + let mut chunks = arr.chunks_exact(LANE_COUNT); + for chunk in &mut chunks { + if chunk.iter().fold(false, |acc, x| acc | (*x == *self)) { + return true; + } + } + // Scalar remainder + return chunks.remainder().iter().any(|x| *x == *self); + } + } + )* + }; +} + +impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 5d6921845d0..14603aa30e8 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -17,11 +17,14 @@ #![feature(clone_to_uninit)] #![feature(const_align_of_val_raw)] #![feature(const_align_offset)] +#![feature(const_bigint_helper_methods)] #![feature(const_black_box)] +#![feature(const_eval_select)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_likely)] #![feature(const_nonnull_new)] +#![feature(const_num_midpoint)] #![feature(const_option_ext)] #![feature(const_pin_2)] #![feature(const_pointer_is_aligned)] @@ -46,6 +49,7 @@ #![feature(get_many_mut)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(inline_const_pat)] #![feature(int_roundings)] #![feature(ip)] #![feature(ip_from)] @@ -104,6 +108,37 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. +macro_rules! assert_eq_const_safe { + ($left:expr, $right:expr$(, $($arg:tt)+)?) => { + { + fn runtime() { + assert_eq!($left, $right, $($arg)*); + } + const fn compiletime() { + assert!(matches!($left, const { $right })); + } + core::intrinsics::const_eval_select((), compiletime, runtime) + } + }; +} + +/// Creates a test for runtime and a test for constant-time. +macro_rules! test_runtime_and_compiletime { + ($( + $(#[$attr:meta])* + fn $test:ident() $block:block + )*) => { + $( + $(#[$attr])* + #[test] + fn $test() $block + $(#[$attr])* + const _: () = $block; + )* + } +} + mod alloc; mod any; mod array; diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 6a26bd15a66..7d3381ee504 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -18,42 +18,6 @@ macro_rules! int_module { } #[test] - fn test_rem_euclid() { - assert_eq!((-1 as $T).rem_euclid(MIN), MAX); - } - - #[test] - pub fn test_abs() { - assert_eq!((1 as $T).abs(), 1 as $T); - assert_eq!((0 as $T).abs(), 0 as $T); - assert_eq!((-1 as $T).abs(), 1 as $T); - } - - #[test] - fn test_signum() { - assert_eq!((1 as $T).signum(), 1 as $T); - assert_eq!((0 as $T).signum(), 0 as $T); - assert_eq!((-0 as $T).signum(), 0 as $T); - assert_eq!((-1 as $T).signum(), -1 as $T); - } - - #[test] - fn test_is_positive() { - assert!((1 as $T).is_positive()); - assert!(!(0 as $T).is_positive()); - assert!(!(-0 as $T).is_positive()); - assert!(!(-1 as $T).is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!(1 as $T).is_negative()); - assert!(!(0 as $T).is_negative()); - assert!(!(-0 as $T).is_negative()); - assert!((-1 as $T).is_negative()); - } - - #[test] fn test_bitwise_operators() { assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T)); assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T)); @@ -63,6 +27,40 @@ macro_rules! int_module { assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); } + test_runtime_and_compiletime! { + + fn test_rem_euclid() { + assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX); + } + + fn test_abs() { + assert_eq_const_safe!((1 as $T).abs(), 1 as $T); + assert_eq_const_safe!((0 as $T).abs(), 0 as $T); + assert_eq_const_safe!((-1 as $T).abs(), 1 as $T); + } + + fn test_signum() { + assert_eq_const_safe!((1 as $T).signum(), 1 as $T); + assert_eq_const_safe!((0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-1 as $T).signum(), -1 as $T); + } + + fn test_is_positive() { + assert!((1 as $T).is_positive()); + assert!(!(0 as $T).is_positive()); + assert!(!(-0 as $T).is_positive()); + assert!(!(-1 as $T).is_positive()); + } + + fn test_is_negative() { + assert!(!(1 as $T).is_negative()); + assert!(!(0 as $T).is_negative()); + assert!(!(-0 as $T).is_negative()); + assert!((-1 as $T).is_negative()); + } + } + const A: $T = 0b0101100; const B: $T = 0b0100001; const C: $T = 0b1111001; @@ -70,134 +68,126 @@ macro_rules! int_module { const _0: $T = 0; const _1: $T = !0; - #[test] - fn test_count_ones() { - assert_eq!(A.count_ones(), 3); - assert_eq!(B.count_ones(), 2); - assert_eq!(C.count_ones(), 5); - } + test_runtime_and_compiletime! { + fn test_count_ones() { + assert_eq_const_safe!(A.count_ones(), 3); + assert_eq_const_safe!(B.count_ones(), 2); + assert_eq_const_safe!(C.count_ones(), 5); + } - #[test] - fn test_count_zeros() { - assert_eq!(A.count_zeros(), $T::BITS - 3); - assert_eq!(B.count_zeros(), $T::BITS - 2); - assert_eq!(C.count_zeros(), $T::BITS - 5); - } + fn test_count_zeros() { + assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3); + assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2); + assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5); + } - #[test] - fn test_leading_trailing_ones() { - let a: $T = 0b0101_1111; - assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), $T::BITS - 7); + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); - assert_eq!(a.reverse_bits().leading_ones(), 5); + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), $T::BITS); - assert_eq!(_1.trailing_ones(), $T::BITS); + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); - assert_eq!((_1 << 1).trailing_ones(), 0); - assert_eq!(MAX.leading_ones(), 0); + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq!(MAX.trailing_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1); - assert_eq!(_0.leading_ones(), 0); - assert_eq!(_0.trailing_ones(), 0); + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); - let x: $T = 0b0010_1100; - assert_eq!(x.leading_ones(), 0); - assert_eq!(x.trailing_ones(), 0); - } + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - assert_eq!(_0.rotate_left(124), _0); - assert_eq!(_1.rotate_left(124), _1); - assert_eq!(_0.rotate_right(124), _0); - assert_eq!(_1.rotate_right(124), _1); - - // Rotating by 0 should have no effect - assert_eq!(A.rotate_left(0), A); - assert_eq!(B.rotate_left(0), B); - assert_eq!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(128), A); - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behaviour. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); + + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } - #[test] - fn test_swap_bytes() { - assert_eq!(A.swap_bytes().swap_bytes(), A); - assert_eq!(B.swap_bytes().swap_bytes(), B); - assert_eq!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq!(_0.swap_bytes(), _0); - assert_eq!(_1.swap_bytes(), _1); - } + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); - #[test] - fn test_le() { - assert_eq!($T::from_le(A.to_le()), A); - assert_eq!($T::from_le(B.to_le()), B); - assert_eq!($T::from_le(C.to_le()), C); - assert_eq!($T::from_le(_0), _0); - assert_eq!($T::from_le(_1), _1); - assert_eq!(_0.to_le(), _0); - assert_eq!(_1.to_le(), _1); - } + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } - #[test] - fn test_be() { - assert_eq!($T::from_be(A.to_be()), A); - assert_eq!($T::from_be(B.to_be()), B); - assert_eq!($T::from_be(C.to_be()), C); - assert_eq!($T::from_be(_0), _0); - assert_eq!($T::from_be(_1), _1); - assert_eq!(_0.to_be(), _0); - assert_eq!(_1.to_be(), _1); - } + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } - #[test] - fn test_signed_checked_div() { - assert_eq!((10 as $T).checked_div(2), Some(5)); - assert_eq!((5 as $T).checked_div(0), None); - assert_eq!(isize::MIN.checked_div(-1), None); - } + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } - #[test] - fn test_saturating_abs() { - assert_eq!((0 as $T).saturating_abs(), 0); - assert_eq!((123 as $T).saturating_abs(), 123); - assert_eq!((-123 as $T).saturating_abs(), 123); - assert_eq!((MAX - 2).saturating_abs(), MAX - 2); - assert_eq!((MAX - 1).saturating_abs(), MAX - 1); - assert_eq!(MAX.saturating_abs(), MAX); - assert_eq!((MIN + 2).saturating_abs(), MAX - 1); - assert_eq!((MIN + 1).saturating_abs(), MAX); - assert_eq!(MIN.saturating_abs(), MAX); - } + fn test_signed_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + assert_eq_const_safe!(isize::MIN.checked_div(-1), None); + } - #[test] - fn test_saturating_neg() { - assert_eq!((0 as $T).saturating_neg(), 0); - assert_eq!((123 as $T).saturating_neg(), -123); - assert_eq!((-123 as $T).saturating_neg(), 123); - assert_eq!((MAX - 2).saturating_neg(), MIN + 3); - assert_eq!((MAX - 1).saturating_neg(), MIN + 2); - assert_eq!(MAX.saturating_neg(), MIN + 1); - assert_eq!((MIN + 2).saturating_neg(), MAX - 1); - assert_eq!((MIN + 1).saturating_neg(), MAX); - assert_eq!(MIN.saturating_neg(), MAX); + fn test_saturating_abs() { + assert_eq_const_safe!((0 as $T).saturating_abs(), 0); + assert_eq_const_safe!((123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((-123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2); + assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1); + assert_eq_const_safe!(MAX.saturating_abs(), MAX); + assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX); + assert_eq_const_safe!(MIN.saturating_abs(), MAX); + } + + fn test_saturating_neg() { + assert_eq_const_safe!((0 as $T).saturating_neg(), 0); + assert_eq_const_safe!((123 as $T).saturating_neg(), -123); + assert_eq_const_safe!((-123 as $T).saturating_neg(), 123); + assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3); + assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2); + assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1); + assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX); + assert_eq_const_safe!(MIN.saturating_neg(), MAX); + } } #[test] @@ -222,173 +212,173 @@ macro_rules! int_module { assert_eq!(from_str::<$T>("x"), None); } - #[test] - fn test_from_str_radix() { - assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32)); - assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); - assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); - assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T)); - - assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T)); - assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); - assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T)); - assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); - assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); - assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); - assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T)); - assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); - - assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>); - assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>); - assert_eq!($T::from_str_radix("10_0", 10).ok(), None::<$T>); - assert_eq!(u32::from_str_radix("-9", 10).ok(), None::<u32>); - } + test_runtime_and_compiletime! { + fn test_from_str_radix() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T)); + + assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); + + assert!($T::from_str_radix("Z", 35).is_err()); + assert!($T::from_str_radix("-9", 2).is_err()); + assert!($T::from_str_radix("10_0", 10).is_err()); + assert!(u32::from_str_radix("-9", 10).is_err()); + } - #[test] - fn test_pow() { - let mut r = 2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); - - r = MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq!(r.wrapping_pow(2), 1 as $T); - assert_eq!(r.checked_pow(2), None); - assert_eq!(r.overflowing_pow(2), (1 as $T, true)); - assert_eq!(r.saturating_pow(2), MAX); - //test for negative exponent. - r = -2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(3), -8 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(3), -8 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(3), Some(-8 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(3), (-8 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(3), -8 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); - } + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + + { + const R: $T = MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } + + { + // test for negative exponent. + const R: $T = -2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(3), -8 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(3), -8 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + } - #[test] - fn test_div_floor() { - let a: $T = 8; - let b = 3; - assert_eq!(a.div_floor(b), 2); - assert_eq!(a.div_floor(-b), -3); - assert_eq!((-a).div_floor(b), -3); - assert_eq!((-a).div_floor(-b), 2); - } + fn test_div_floor() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_floor(B), 2); + assert_eq_const_safe!(A.div_floor(-B), -3); + assert_eq_const_safe!((-A).div_floor(B), -3); + assert_eq_const_safe!((-A).div_floor(-B), 2); + } - #[test] - fn test_div_ceil() { - let a: $T = 8; - let b = 3; - assert_eq!(a.div_ceil(b), 3); - assert_eq!(a.div_ceil(-b), -2); - assert_eq!((-a).div_ceil(b), -2); - assert_eq!((-a).div_ceil(-b), 3); - } + fn test_div_ceil() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_ceil(B), 3); + assert_eq_const_safe!(A.div_ceil(-B), -2); + assert_eq_const_safe!((-A).div_ceil(B), -2); + assert_eq_const_safe!((-A).div_ceil(-B), 3); + } - #[test] - fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!((16 as $T).next_multiple_of(-8), 16); - assert_eq!((23 as $T).next_multiple_of(-8), 16); - assert_eq!((-16 as $T).next_multiple_of(8), -16); - assert_eq!((-23 as $T).next_multiple_of(8), -16); - assert_eq!((-16 as $T).next_multiple_of(-8), -16); - assert_eq!((-23 as $T).next_multiple_of(-8), -24); - assert_eq!(MIN.next_multiple_of(-1), MIN); - } + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24); + assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN); + } - #[test] - fn test_checked_next_multiple_of() { - assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); - assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); - assert_eq!((1 as $T).checked_next_multiple_of(0), None); - assert_eq!(MAX.checked_next_multiple_of(2), None); - assert_eq!(MIN.checked_next_multiple_of(-3), None); - assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); - } + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN)); + } - #[test] - fn test_carrying_add() { - assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true)); - assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true)); - assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true)); - assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false)); - assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow - assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true)); - assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow - assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true)); - assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false)); - } + fn test_carrying_add() { + assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true)); + assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false)); + assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true)); + assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true)); + assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false)); + } - #[test] - fn test_borrowing_sub() { - assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false)); - assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow - assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true)); - assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow - assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); - assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); - } + fn test_borrowing_sub() { + assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true)); + assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true)); + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); + } - #[test] - fn test_midpoint() { - assert_eq!(<$T>::midpoint(1, 3), 2); - assert_eq!(<$T>::midpoint(3, 1), 2); - - assert_eq!(<$T>::midpoint(0, 0), 0); - assert_eq!(<$T>::midpoint(0, 2), 1); - assert_eq!(<$T>::midpoint(2, 0), 1); - assert_eq!(<$T>::midpoint(2, 2), 2); - - assert_eq!(<$T>::midpoint(1, 4), 2); - assert_eq!(<$T>::midpoint(4, 1), 2); - assert_eq!(<$T>::midpoint(3, 4), 3); - assert_eq!(<$T>::midpoint(4, 3), 3); - - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - - assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + } } }; } diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index f4fa789461e..105aad4522d 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -2,7 +2,6 @@ macro_rules! uint_module { ($T:ident) => { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; - use std::str::FromStr; use crate::num; @@ -35,122 +34,115 @@ macro_rules! uint_module { const _0: $T = 0; const _1: $T = !0; - #[test] - fn test_count_ones() { - assert!(A.count_ones() == 3); - assert!(B.count_ones() == 2); - assert!(C.count_ones() == 5); - } + test_runtime_and_compiletime! { + fn test_count_ones() { + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); + } - #[test] - fn test_count_zeros() { - assert!(A.count_zeros() == $T::BITS - 3); - assert!(B.count_zeros() == $T::BITS - 2); - assert!(C.count_zeros() == $T::BITS - 5); - } + fn test_count_zeros() { + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); + } - #[test] - fn test_leading_trailing_ones() { - let a: $T = 0b0101_1111; - assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), $T::BITS - 7); + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); - assert_eq!(a.reverse_bits().leading_ones(), 5); + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), $T::BITS); - assert_eq!(_1.trailing_ones(), $T::BITS); + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); - assert_eq!((_1 << 1).trailing_ones(), 0); - assert_eq!((_1 >> 1).leading_ones(), 0); + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!((_1 >> 1).leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1); - assert_eq!(_0.leading_ones(), 0); - assert_eq!(_0.trailing_ones(), 0); + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); - let x: $T = 0b0010_1100; - assert_eq!(x.leading_ones(), 0); - assert_eq!(x.trailing_ones(), 0); - } + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - assert_eq!(_0.rotate_left(124), _0); - assert_eq!(_1.rotate_left(124), _1); - assert_eq!(_0.rotate_right(124), _0); - assert_eq!(_1.rotate_right(124), _1); - - // Rotating by 0 should have no effect - assert_eq!(A.rotate_left(0), A); - assert_eq!(B.rotate_left(0), B); - assert_eq!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(128), A); - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behaviour. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); + + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } - #[test] - fn test_swap_bytes() { - assert_eq!(A.swap_bytes().swap_bytes(), A); - assert_eq!(B.swap_bytes().swap_bytes(), B); - assert_eq!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq!(_0.swap_bytes(), _0); - assert_eq!(_1.swap_bytes(), _1); - } + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); - #[test] - fn test_reverse_bits() { - assert_eq!(A.reverse_bits().reverse_bits(), A); - assert_eq!(B.reverse_bits().reverse_bits(), B); - assert_eq!(C.reverse_bits().reverse_bits(), C); - - // Swapping these should make no difference - assert_eq!(_0.reverse_bits(), _0); - assert_eq!(_1.reverse_bits(), _1); - } + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } - #[test] - fn test_le() { - assert_eq!($T::from_le(A.to_le()), A); - assert_eq!($T::from_le(B.to_le()), B); - assert_eq!($T::from_le(C.to_le()), C); - assert_eq!($T::from_le(_0), _0); - assert_eq!($T::from_le(_1), _1); - assert_eq!(_0.to_le(), _0); - assert_eq!(_1.to_le(), _1); - } + fn test_reverse_bits() { + assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A); + assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B); + assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C); - #[test] - fn test_be() { - assert_eq!($T::from_be(A.to_be()), A); - assert_eq!($T::from_be(B.to_be()), B); - assert_eq!($T::from_be(C.to_be()), C); - assert_eq!($T::from_be(_0), _0); - assert_eq!($T::from_be(_1), _1); - assert_eq!(_0.to_be(), _0); - assert_eq!(_1.to_be(), _1); - } + // Swapping these should make no difference + assert_eq_const_safe!(_0.reverse_bits(), _0); + assert_eq_const_safe!(_1.reverse_bits(), _1); + } - #[test] - fn test_unsigned_checked_div() { - assert!((10 as $T).checked_div(2) == Some(5)); - assert!((5 as $T).checked_div(0) == None); + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } + + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } + + fn test_unsigned_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + } } - fn from_str<T: FromStr>(t: &str) -> Option<T> { - FromStr::from_str(t).ok() + fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> { + core::str::FromStr::from_str(t).ok() } #[test] @@ -166,52 +158,55 @@ macro_rules! uint_module { assert_eq!(from_str::<$T>("x"), None); } - #[test] - pub fn test_parse_bytes() { - assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16)); - assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); - assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); - - assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>); - assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>); - } + test_runtime_and_compiletime! { + fn test_parse_bytes() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16)); + assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + + assert!($T::from_str_radix("Z", 10).is_err()); + assert!($T::from_str_radix("_", 2).is_err()); + } - #[test] - fn test_pow() { - let mut r = 2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); - - r = MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq!(r.wrapping_pow(2), 1 as $T); - assert_eq!(r.checked_pow(2), None); - assert_eq!(r.overflowing_pow(2), (1 as $T, true)); - assert_eq!(r.saturating_pow(2), MAX); - } + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + + { + const R: $T = $T::MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } + } - #[test] - fn test_isqrt() { - assert_eq!((0 as $T).isqrt(), 0 as $T); - assert_eq!((1 as $T).isqrt(), 1 as $T); - assert_eq!((2 as $T).isqrt(), 1 as $T); - assert_eq!((99 as $T).isqrt(), 9 as $T); - assert_eq!((100 as $T).isqrt(), 10 as $T); - assert_eq!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + fn test_isqrt() { + assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T); + assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T); + assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T); + assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + } } #[cfg(not(miri))] // Miri is too slow @@ -233,85 +228,79 @@ macro_rules! uint_module { } } - #[test] - fn test_div_floor() { - assert_eq!((8 as $T).div_floor(3), 2); - } + test_runtime_and_compiletime! { + fn test_div_floor() { + assert_eq_const_safe!((8 as $T).div_floor(3), 2); + } - #[test] - fn test_div_ceil() { - assert_eq!((8 as $T).div_ceil(3), 3); - } + fn test_div_ceil() { + assert_eq_const_safe!((8 as $T).div_ceil(3), 3); + } - #[test] - fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!(MAX.next_multiple_of(1), MAX); - } + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!(MAX.next_multiple_of(1), MAX); + } - #[test] - fn test_checked_next_multiple_of() { - assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq!((1 as $T).checked_next_multiple_of(0), None); - assert_eq!(MAX.checked_next_multiple_of(2), None); - } + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + } - #[test] - fn test_is_next_multiple_of() { - assert!((12 as $T).is_multiple_of(4)); - assert!(!(12 as $T).is_multiple_of(5)); - assert!((0 as $T).is_multiple_of(0)); - assert!(!(12 as $T).is_multiple_of(0)); - } + fn test_is_next_multiple_of() { + assert!((12 as $T).is_multiple_of(4)); + assert!(!(12 as $T).is_multiple_of(5)); + assert!((0 as $T).is_multiple_of(0)); + assert!(!(12 as $T).is_multiple_of(0)); + } - #[test] - fn test_carrying_add() { - assert_eq!($T::MAX.carrying_add(1, false), (0, true)); - assert_eq!($T::MAX.carrying_add(0, true), (0, true)); - assert_eq!($T::MAX.carrying_add(1, true), (1, true)); - - assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); - assert_eq!($T::MIN.carrying_add(0, true), (1, false)); - assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true)); - } + fn test_carrying_add() { + assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true)); - #[test] - fn test_borrowing_sub() { - assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - - assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); - assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); - assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); - } + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } - #[test] - fn test_midpoint() { - assert_eq!(<$T>::midpoint(1, 3), 2); - assert_eq!(<$T>::midpoint(3, 1), 2); - - assert_eq!(<$T>::midpoint(0, 0), 0); - assert_eq!(<$T>::midpoint(0, 2), 1); - assert_eq!(<$T>::midpoint(2, 0), 1); - assert_eq!(<$T>::midpoint(2, 2), 2); - - assert_eq!(<$T>::midpoint(1, 4), 2); - assert_eq!(<$T>::midpoint(4, 1), 2); - assert_eq!(<$T>::midpoint(3, 4), 3); - assert_eq!(<$T>::midpoint(4, 3), 3); - - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - - assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + fn test_borrowing_sub() { + assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } + + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + } } }; } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e25b571acba..27acaff8255 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1734,13 +1734,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } else { // We need to properly build cargo using the suitable stage compiler. - // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if - // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built - // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off - // the compiler stage by 1 to align with expected `./x test run-make --stage N` - // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri - // which does a similar hack. - let compiler = builder.compiler(builder.top_stage - 1, compiler.host); + let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(|| + // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if + // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built + // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off + // the compiler stage by 1 to align with expected `./x test run-make --stage N` + // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri + // which does a similar hack. + builder.compiler(builder.top_stage - 1, compiler.host)); + builder.ensure(tool::Cargo { compiler, target: compiler.host }) }; @@ -3549,9 +3551,7 @@ impl Step for TestFloatParse { let path = self.path.to_str().unwrap(); let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); - if !builder.download_rustc() { - builder.ensure(compile::Std::new(compiler, self.host)); - } + builder.ensure(tool::TestFloatParse { host: self.host }); // Run any unit tests in the crate let cargo_test = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index f5afa6c4c6c..50f71e167db 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1097,6 +1097,38 @@ tool_extended!((self, builder), Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"]; ); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TestFloatParse { + pub host: TargetSelection, +} + +impl Step for TestFloatParse { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/etc/test-float-parse") + } + + fn run(self, builder: &Builder<'_>) { + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(builder.top_stage, bootstrap_host); + + builder.ensure(ToolBuild { + compiler, + target: bootstrap_host, + tool: "test-float-parse", + mode: Mode::ToolStd, + path: "src/etc/test-float-parse", + source_type: SourceType::InTree, + extra_features: Vec::new(), + allow_features: "", + cargo_args: Vec::new(), + }); + } +} + impl Builder<'_> { /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for /// `host`. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7d4d8d8941d..bf168809e28 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -216,7 +216,7 @@ fn clean_generic_bound<'tcx>( hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), hir::GenericBound::Trait(ref t) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if t.modifiers == hir::TraitBoundModifier::MaybeConst + if let hir::BoundConstness::Maybe(_) = t.modifiers.constness && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) { return None; @@ -263,7 +263,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>( trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints), generic_params: clean_bound_vars(poly_trait_ref.bound_vars()), }, - hir::TraitBoundModifier::None, + hir::TraitBoundModifiers::NONE, ) } @@ -2189,7 +2189,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Alias(ty::Weak, data) => { - if cx.tcx.features().lazy_type_alias { + if cx.tcx.features().lazy_type_alias() { // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. let path = clean_middle_path( diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 675507a44c9..6090de16d55 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -966,8 +966,8 @@ pub(crate) trait AttributesExt { fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> { let sess = tcx.sess; - let doc_cfg_active = tcx.features().doc_cfg; - let doc_auto_cfg_active = tcx.features().doc_auto_cfg; + let doc_cfg_active = tcx.features().doc_cfg(); + let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); fn single<T: IntoIterator>(it: T) -> Option<T::Item> { let mut iter = it.into_iter(); @@ -1257,7 +1257,7 @@ impl Eq for Attributes {} #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericBound { - TraitBound(PolyTrait, hir::TraitBoundModifier), + TraitBound(PolyTrait, hir::TraitBoundModifiers), Outlives(Lifetime), /// `use<'a, T>` precise-capturing bound syntax Use(Vec<Symbol>), @@ -1265,19 +1265,22 @@ pub(crate) enum GenericBound { impl GenericBound { pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::None) + Self::sized_with(cx, hir::TraitBoundModifiers::NONE) } pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::Maybe) + Self::sized_with(cx, hir::TraitBoundModifiers { + polarity: hir::BoundPolarity::Maybe(DUMMY_SP), + constness: hir::BoundConstness::Never, + }) } - fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { + fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) + GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers) } pub(crate) fn is_trait_bound(&self) -> bool { @@ -1285,8 +1288,10 @@ impl GenericBound { } pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { - use rustc_hir::TraitBoundModifier as TBM; - if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self + if let GenericBound::TraitBound( + PolyTrait { ref trait_, .. }, + rustc_hir::TraitBoundModifiers::NONE, + ) = *self && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() { return true; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9bebe1fb4c1..0f7d4d3e8f3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -8,7 +8,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl}; +use rustc_errors::{ErrorGuaranteed, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -21,8 +21,8 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks}; pub(crate) use rustc_session::config::{Options, UnstableOptions}; use rustc_session::{Session, lint}; +use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::{Span, source_map}; use tracing::{debug, info}; use crate::clean::inline::build_external_trait; @@ -381,45 +381,10 @@ pub(crate) fn run_global_ctxt( ); } - fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) { - let mut msg = - dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); - msg.note( - "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \ - for more information", - ); - - if name == "no_default_passes" { - msg.help("`#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`"); - } else if name.starts_with("passes") { - msg.help("`#![doc(passes = \"...\")]` no longer functions; you may want to use `#![doc(document_private_items)]`"); - } else if name.starts_with("plugins") { - msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>"); - } - - msg.emit(); - } - // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. for attr in krate.module.attrs.lists(sym::doc) { - let dcx = ctxt.sess().dcx(); - let name = attr.name_or_empty(); - // `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect - if attr.is_word() && name == sym::no_default_passes { - report_deprecated_attr("no_default_passes", dcx, attr.span()); - } else if attr.value_str().is_some() { - match name { - sym::passes => { - report_deprecated_attr("passes = \"...\"", dcx, attr.span()); - } - sym::plugins => { - report_deprecated_attr("plugins = \"...\"", dcx, attr.span()); - } - _ => (), - } - } if attr.is_word() && name == sym::document_private_items { ctxt.render_options.document_private = true; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2e70a8c080d..5c599f20f9f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -399,13 +399,13 @@ impl clean::GenericBound { ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), - clean::GenericBound::TraitBound(ty, modifier) => { - f.write_str(match modifier { - hir::TraitBoundModifier::None => "", - hir::TraitBoundModifier::Maybe => "?", - hir::TraitBoundModifier::Negative => "!", - // `const` and `~const` trait bounds are experimental; don't render them. - hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", + clean::GenericBound::TraitBound(ty, modifiers) => { + // `const` and `~const` trait bounds are experimental; don't render them. + let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers; + f.write_str(match polarity { + hir::BoundPolarity::Positive => "", + hir::BoundPolarity::Maybe(_) => "?", + hir::BoundPolarity::Negative(_) => "!", })?; ty.print(cx).fmt(f) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 12b63460056..c82f7e9aaf9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -112,7 +112,7 @@ pub(crate) fn write_shared( md_opts.output = cx.dst.clone(); md_opts.external_html = cx.shared.layout.external_html.clone(); try_err!( - crate::markdown::render(&index_page, md_opts, cx.shared.edition()), + crate::markdown::render_and_write(&index_page, md_opts, cx.shared.edition()), &index_page ); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0130f2ce517..7270f170780 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -552,20 +552,18 @@ impl FromClean<clean::GenericBound> for GenericBound { } pub(crate) fn from_trait_bound_modifier( - modifier: rustc_hir::TraitBoundModifier, + modifiers: rustc_hir::TraitBoundModifiers, ) -> TraitBoundModifier { - use rustc_hir::TraitBoundModifier::*; - match modifier { - None => TraitBoundModifier::None, - Maybe => TraitBoundModifier::Maybe, - MaybeConst => TraitBoundModifier::MaybeConst, - // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds - // are less experimental. - Const => TraitBoundModifier::None, - // FIXME(negative-bounds): This bound should be rendered negative, but - // since that's experimental, maybe let's not add it to the rustdoc json - // API just now... - Negative => TraitBoundModifier::None, + use rustc_hir as hir; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + match (constness, polarity) { + (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, + (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, + (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => { + TraitBoundModifier::MaybeConst + } + // FIXME: Fill out the rest of this matrix. + _ => TraitBoundModifier::None, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 10fc0ea9990..cb9b3985bf6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -817,7 +817,7 @@ fn main_args( return wrap_return( dcx, interface::run_compiler(config, |_compiler| { - markdown::render(&md_input, render_options, edition) + markdown::render_and_write(&md_input, render_options, edition) }), ); } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 978f96f38be..76eac084907 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -1,3 +1,13 @@ +//! Standalone markdown rendering. +//! +//! For the (much more common) case of rendering markdown in doc-comments, see +//! [crate::html::markdown]. +//! +//! This is used when [rendering a markdown file to an html file][docs], without processing +//! rust source code. +//! +//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files + use std::fmt::Write as _; use std::fs::{File, create_dir_all, read_to_string}; use std::io::prelude::*; @@ -33,7 +43,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { /// (e.g., output = "bar" => "bar/foo.html"). /// /// Requires session globals to be available, for symbol interning. -pub(crate) fn render<P: AsRef<Path>>( +pub(crate) fn render_and_write<P: AsRef<Path>>( input: P, options: RenderOptions, edition: Edition, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index f4579d85531..484bdb5627c 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -116,7 +116,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item find_testable_code(dox, &mut tests, ErrorCodes::No, false, None); - if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples { + if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples() { if should_have_doc_example(cx, item) { debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 2f0ea8d618c..140fda70918 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1419,7 +1419,7 @@ impl LinkCollector<'_, '_> { && key.path_str.contains("::") // We only want to check this if this is an associated item. { - if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers { + if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers() { self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item); return None; } else { diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 70eb81fa09c..b0389fd9a2f 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -64,7 +64,7 @@ impl LateLintPass<'_> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Enum(..) = item.kind // Only suggest the `never_type` if the feature is enabled - && cx.tcx.features().never_type + && cx.tcx.features().never_type() && let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def() && adt.variants().is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 00f83237224..65fdc93e0ed 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds .iter() .filter_map(|bound| { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() @@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { // simply comparing trait `DefId`s won't be enough. We also need to compare the generics. for (index, bound) in bounds.iter().enumerate() { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index f9ffbc5dc0b..20984bc40ca 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { if matches!(arm2.pat.kind, PatKind::Wild) { - if !cx.tcx.features().non_exhaustive_omitted_patterns_lint + if !cx.tcx.features().non_exhaustive_omitted_patterns_lint() || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) { let arm_span = adjusted_arm_span(cx, arm1.span); diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 564c598a334..42d9efe4ff6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -251,7 +251,7 @@ fn emit_redundant_guards<'tcx>( fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { for_each_expr_without_closures(expr, |expr| { if match expr.kind { - ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat, + ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat(), ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { // Allow ctors matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..)) diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 68c9af07465..9a1c397b5b2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate}; +use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ClauseKind, PredicatePolarity}; use rustc_session::declare_lint_pass; @@ -118,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized { let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) .filter(|bound| { bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) - && bound.trait_bound.modifiers == TraitBoundModifier::Maybe + && matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_)) }) .map(|bound| (bound.param, bound)) .collect(); for bound in type_param_bounds(generics) { - if bound.trait_bound.modifiers == TraitBoundModifier::None + if bound.trait_bound.modifiers == TraitBoundModifiers::NONE && let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 7f528b9d17b..3da4bf67558 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath, - TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, + TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -233,7 +233,7 @@ impl TraitBounds { fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) && let GenericBound::Trait(tr) = bound - && let TraitBoundModifier::Maybe = tr.modifiers + && let BoundPolarity::Maybe(_) = tr.modifiers.polarity { cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() } else { @@ -374,12 +374,12 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen struct ComparableTraitRef<'a, 'tcx> { cx: &'a LateContext<'tcx>, trait_ref: &'tcx TraitRef<'tcx>, - modifier: TraitBoundModifier, + modifiers: TraitBoundModifiers, } impl PartialEq for ComparableTraitRef<'_, '_> { fn eq(&self, other: &Self) -> bool { - self.modifier == other.modifier + SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers) && SpanlessEq::new(self.cx) .paths_by_resolution() .eq_path(self.trait_ref.path, other.trait_ref.path) @@ -390,8 +390,8 @@ impl Hash for ComparableTraitRef<'_, '_> { fn hash<H: Hasher>(&self, state: &mut H) { let mut s = SpanlessHash::new(self.cx).paths_by_resolution(); s.hash_path(self.trait_ref.path); + s.hash_modifiers(self.modifiers); state.write_u64(s.finish()); - self.modifier.hash(state); } } @@ -400,7 +400,7 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &' let trait_path = t.trait_ref.path; let trait_span = { let path_span = trait_path.span; - if let TraitBoundModifier::Maybe = t.modifiers { + if let BoundPolarity::Maybe(_) = t.modifiers.polarity { path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` } else { path_span @@ -427,7 +427,7 @@ fn rollup_traits<'cx, 'tcx>( ComparableTraitRef { cx, trait_ref: &t.trait_ref, - modifier: t.modifiers, + modifiers: t.modifiers, }, t.span, )) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 27c57808ece..181d414cbbd 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -9,7 +9,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, + LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty, + TyKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -126,6 +127,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool { self.inter_expr().eq_path_segments(left, right) } + + pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool { + std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness) + && std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity) + } } pub struct HirEqInterExpr<'a, 'b, 'tcx> { @@ -1143,6 +1149,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) { + let TraitBoundModifiers { constness, polarity } = modifiers; + std::mem::discriminant(&polarity).hash(&mut self.s); + std::mem::discriminant(&constness).hash(&mut self.s); + } + pub fn hash_stmt(&mut self, b: &Stmt<'_>) { std::mem::discriminant(&b.kind).hash(&mut self.s); diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 099e620ffe0..d75cdefe635 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -57,7 +57,7 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |DirectiveLine { directive: ln, .. }| { + &mut |DirectiveLine { raw_directive: ln, .. }| { parse_and_update_aux(config, ln, &mut props.aux); config.parse_and_update_revisions(testfile, ln, &mut props.revisions); }, @@ -344,8 +344,8 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |DirectiveLine { header_revision, directive: ln, .. }| { - if header_revision.is_some() && header_revision != test_revision { + &mut |directive @ DirectiveLine { raw_directive: ln, .. }| { + if !directive.applies_to_test_revision(test_revision) { return; } @@ -678,28 +678,35 @@ impl TestProps { } } -/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present. -/// -/// See [`DirectiveLine`] for a diagram. -pub fn line_directive<'line>( +/// If the given line begins with the appropriate comment prefix for a directive, +/// returns a struct containing various parts of the directive. +fn line_directive<'line>( + line_number: usize, comment: &str, original_line: &'line str, -) -> Option<(Option<&'line str>, &'line str)> { +) -> Option<DirectiveLine<'line>> { // Ignore lines that don't start with the comment prefix. let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start(); + let revision; + let raw_directive; + if let Some(after_open_bracket) = after_comment.strip_prefix('[') { // A comment like `//@[foo]` only applies to revision `foo`. - let Some((line_revision, directive)) = after_open_bracket.split_once(']') else { + let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { panic!( "malformed condition directive: expected `{comment}[foo]`, found `{original_line}`" ) }; - Some((Some(line_revision), directive.trim_start())) + revision = Some(line_revision); + raw_directive = after_close_bracket.trim_start(); } else { - Some((None, after_comment)) - } + revision = None; + raw_directive = after_comment; + }; + + Some(DirectiveLine { line_number, revision, raw_directive }) } // To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`, @@ -730,28 +737,37 @@ const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"]; -/// The broken-down contents of a line containing a test header directive, +/// The (partly) broken-down contents of a line containing a test directive, /// which [`iter_header`] passes to its callback function. /// /// For example: /// /// ```text /// //@ compile-flags: -O -/// ^^^^^^^^^^^^^^^^^ directive +/// ^^^^^^^^^^^^^^^^^ raw_directive /// /// //@ [foo] compile-flags: -O -/// ^^^ header_revision -/// ^^^^^^^^^^^^^^^^^ directive +/// ^^^ revision +/// ^^^^^^^^^^^^^^^^^ raw_directive /// ``` struct DirectiveLine<'ln> { line_number: usize, - /// Some header directives start with a revision name in square brackets + /// Some test directives start with a revision name in square brackets /// (e.g. `[foo]`), and only apply to that revision of the test. /// If present, this field contains the revision name (e.g. `foo`). - header_revision: Option<&'ln str>, - /// The main part of the header directive, after removing the comment prefix + revision: Option<&'ln str>, + /// The main part of the directive, after removing the comment prefix /// and the optional revision specifier. - directive: &'ln str, + /// + /// This is "raw" because the directive's name and colon-separated value + /// (if present) have not yet been extracted or checked. + raw_directive: &'ln str, +} + +impl<'ln> DirectiveLine<'ln> { + fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool { + self.revision.is_none() || self.revision == test_revision + } } pub(crate) struct CheckDirectiveResult<'ln> { @@ -819,8 +835,8 @@ fn iter_header( "ignore-cross-compile", ]; // Process the extra implied directives, with a dummy line number of 0. - for directive in extra_directives { - it(DirectiveLine { line_number: 0, header_revision: None, directive }); + for raw_directive in extra_directives { + it(DirectiveLine { line_number: 0, revision: None, raw_directive }); } } @@ -847,24 +863,21 @@ fn iter_header( return; } - let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln) - else { + let Some(directive_line) = line_directive(line_number, comment, ln) else { continue; }; // Perform unknown directive check on Rust files. if testfile.extension().map(|e| e == "rs").unwrap_or(false) { - let directive_ln = non_revisioned_directive_line.trim(); - let CheckDirectiveResult { is_known_directive, trailing_directive } = - check_directive(directive_ln, mode, ln); + check_directive(directive_line.raw_directive, mode, ln); if !is_known_directive { *poisoned = true; eprintln!( "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_ln, + directive_line.raw_directive, testfile.display(), line_number, ); @@ -888,11 +901,7 @@ fn iter_header( } } - it(DirectiveLine { - line_number, - header_revision, - directive: non_revisioned_directive_line, - }); + it(directive_line); } } @@ -1292,8 +1301,8 @@ pub fn make_test_description<R: Read>( &mut local_poisoned, path, src, - &mut |DirectiveLine { header_revision, directive: ln, line_number }| { - if header_revision.is_some() && header_revision != test_revision { + &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { + if !directive.applies_to_test_revision(test_revision) { return; } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 985fe6381e8..c15422fb6f6 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use crate::common::Config; -use crate::header::line_directive; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -24,7 +23,6 @@ impl DebuggerCommands { file: &Path, config: &Config, debugger_prefixes: &[&str], - rev: Option<&str>, ) -> Result<Self, String> { let directives = debugger_prefixes .iter() @@ -39,18 +37,17 @@ impl DebuggerCommands { for (line_no, line) in reader.lines().enumerate() { counter += 1; let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; - let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); - - // Skip any revision specific directive that doesn't match the current - // revision being tested - if lnrev.is_some() && lnrev != rev { - continue; - } + // Breakpoints appear on lines with actual code, typically at the end of the line. if line.contains("#break") { breakpoint_lines.push(counter); + continue; } + let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else { + continue; + }; + for &(ref command_directive, ref check_directive) in &directives { config .parse_name_value_directive(&line, command_directive) diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index bd0845b4524..c621c22ac99 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -66,13 +66,8 @@ impl TestCx<'_> { }; // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) + .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands let mut script_str = String::with_capacity(2048); @@ -142,13 +137,8 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test_no_opt(&self) { - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["gdb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"]) + .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) @@ -413,13 +403,8 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["lldb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"]) + .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs new file mode 100644 index 00000000000..2a113eed4ba --- /dev/null +++ b/tests/assembly/rust-abi-arg-attr.rs @@ -0,0 +1,108 @@ +//@ assembly-output: emit-asm +//@ revisions: riscv64 riscv64-zbb loongarch64 +//@ compile-flags: -C opt-level=3 +//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb +//@ [riscv64-zbb] needs-llvm-components: riscv +//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64] needs-llvm-components: loongarch + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +// FIXME: Migrate these code after PR #130693 is landed. +// vvvvv core + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +impl Copy for i8 {} +impl Copy for u32 {} +impl Copy for i32 {} + +#[lang = "neg"] +trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> Self::Output { + -self + } +} + +#[lang = "Ordering"] +#[repr(i8)] +enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +extern "rust-intrinsic" { + #[rustc_safe_intrinsic] + fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering; +} + +// ^^^^^ core + +// Reimplementation of function `{integer}::max`. +macro_rules! max { + ($a:expr, $b:expr) => { + match three_way_compare($a, $b) { + Ordering::Less | Ordering::Equal => $b, + Ordering::Greater => $a, + } + }; +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_u32: +pub fn issue_114508_u32(a: u32, b: u32) -> u32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: bltu a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: maxu a0, a0, a1 + + // loongarch64-NEXT: sltu $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_i32: +pub fn issue_114508_i32(a: i32, b: i32) -> i32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: blt a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: max a0, a0, a1 + + // loongarch64-NEXT: slt $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs index 30c5e869633..acd1af8d38a 100644 --- a/tests/assembly/x86-return-float.rs +++ b/tests/assembly/x86-return-float.rs @@ -305,8 +305,10 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) { // CHECK-LABEL: return_f16: #[no_mangle] pub fn return_f16(x: f16) -> f16 { - // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0 - // CHECK-NOT: xmm0 + // CHECK: pushl %ebp + // CHECK: movl %esp, %ebp + // CHECK: movzwl 8(%ebp), %eax + // CHECK: popl %ebp // CHECK: retl x } diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs index 8f3c07119fe..d7dfc7c29e7 100644 --- a/tests/codegen/checked_ilog.rs +++ b/tests/codegen/checked_ilog.rs @@ -5,7 +5,7 @@ // Ensure that when val < base, we do not divide or multiply. // CHECK-LABEL: @checked_ilog -// CHECK-SAME: (i16 noundef %val, i16 noundef %base) +// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base) #[no_mangle] pub fn checked_ilog(val: u16, base: u16) -> Option<u32> { // CHECK-NOT: udiv diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs index 75df5866d6e..63f5c3d34f7 100644 --- a/tests/codegen/checked_math.rs +++ b/tests/codegen/checked_math.rs @@ -8,7 +8,7 @@ // Thanks to poison semantics, this doesn't even need branches. // CHECK-LABEL: @checked_sub_unsigned -// CHECK-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) #[no_mangle] pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> { // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b @@ -26,7 +26,7 @@ pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> { // looking for no-wrap flags, we just need there to not be any masking. // CHECK-LABEL: @checked_shl_unsigned -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -41,7 +41,7 @@ pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> { } // CHECK-LABEL: @checked_shr_unsigned -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -56,7 +56,7 @@ pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> { } // CHECK-LABEL: @checked_shl_signed -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -71,7 +71,7 @@ pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> { } // CHECK-LABEL: @checked_shr_signed -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -86,7 +86,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> { } // CHECK-LABEL: @checked_add_one_unwrap_unsigned -// CHECK-SAME: (i32 noundef %x) +// CHECK-SAME: (i32{{.*}} %x) #[no_mangle] pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 { // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1 diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs index d336c4e6ed3..acce0cb5946 100644 --- a/tests/codegen/comparison-operators-newtype.rs +++ b/tests/codegen/comparison-operators-newtype.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; pub struct Foo(u16); // CHECK-LABEL: @check_lt -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_lt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] @@ -21,7 +21,7 @@ pub fn check_lt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_le -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_le(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] @@ -30,7 +30,7 @@ pub fn check_le(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_gt -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_gt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] @@ -39,7 +39,7 @@ pub fn check_gt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_ge -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_ge(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index b14dd30482c..a171629a076 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -6,11 +6,11 @@ #[no_mangle] pub fn sum(x: u32, y: u32) -> u32 { - // YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1) + // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1) // YES-NEXT: %3 = add i32 %1, %0 // YES-NEXT: ret i32 %3 - // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) + // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y) // NO-NEXT: start: // NO-NEXT: %z = add i32 %y, %x // NO-NEXT: ret i32 %z diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 4af264101de..514d35433e1 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,4 +1,4 @@ -// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +// 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. //@ revisions: x86 bit32 bit64 //@[x86] only-x86 @@ -152,7 +152,9 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) { /* float to float conversions */ -// CHECK-LABEL: half @f128_as_f16( +// x86-LABEL: i16 @f128_as_f16( +// bits32-LABEL: half @f128_as_f16( +// bits64-LABEL: half @f128_as_f16( #[no_mangle] pub fn f128_as_f16(a: f128) -> f16 { // CHECK: fptrunc fp128 %{{.+}} to half diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index 80931051f18..5c3a5893b9d 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,4 +1,4 @@ -// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +// 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. //@ revisions: x86 bit32 bit64 //@[x86] only-x86 @@ -58,42 +58,44 @@ pub fn f16_le(a: f16, b: f16) -> bool { a <= b } -// CHECK-LABEL: half @f16_neg( +// This is where we check the argument and return ABI for f16. +// other-LABEL: half @f16_neg(half +// x86-LABEL: i16 @f16_neg(half #[no_mangle] pub fn f16_neg(a: f16) -> f16 { // CHECK: fneg half %{{.+}} -a } -// CHECK-LABEL: half @f16_add( +// CHECK-LABEL: @f16_add #[no_mangle] pub fn f16_add(a: f16, b: f16) -> f16 { // CHECK: fadd half %{{.+}}, %{{.+}} a + b } -// CHECK-LABEL: half @f16_sub( +// CHECK-LABEL: @f16_sub #[no_mangle] pub fn f16_sub(a: f16, b: f16) -> f16 { // CHECK: fsub half %{{.+}}, %{{.+}} a - b } -// CHECK-LABEL: half @f16_mul( +// CHECK-LABEL: @f16_mul #[no_mangle] pub fn f16_mul(a: f16, b: f16) -> f16 { // CHECK: fmul half %{{.+}}, %{{.+}} a * b } -// CHECK-LABEL: half @f16_div( +// CHECK-LABEL: @f16_div #[no_mangle] pub fn f16_div(a: f16, b: f16) -> f16 { // CHECK: fdiv half %{{.+}}, %{{.+}} a / b } -// CHECK-LABEL: half @f16_rem( +// CHECK-LABEL: @f16_rem #[no_mangle] pub fn f16_rem(a: f16, b: f16) -> f16 { // CHECK: frem half %{{.+}}, %{{.+}} @@ -142,10 +144,13 @@ pub fn f16_rem_assign(a: &mut f16, b: f16) { /* float to float conversions */ -// CHECK-LABEL: half @f16_as_self( +// other-LABEL: half @f16_as_self( +// x86-LABEL: i16 @f16_as_self( #[no_mangle] pub fn f16_as_self(a: f16) -> f16 { - // CHECK: ret half %{{.+}} + // other-CHECK: ret half %{{.+}} + // x86-CHECK: bitcast half + // x86-CHECK: ret i16 a as f16 } @@ -176,21 +181,21 @@ pub fn f16_as_f128(a: f16) -> f128 { a as f128 } -// CHECK-LABEL: half @f32_as_f16( +// CHECK-LABEL: @f32_as_f16 #[no_mangle] pub fn f32_as_f16(a: f32) -> f16 { // CHECK: fptrunc float %{{.+}} to half a as f16 } -// CHECK-LABEL: half @f64_as_f16( +// CHECK-LABEL: @f64_as_f16 #[no_mangle] pub fn f64_as_f16(a: f64) -> f16 { // CHECK: fptrunc double %{{.+}} to half a as f16 } -// CHECK-LABEL: half @f128_as_f16( +// CHECK-LABEL: @f128_as_f16 #[no_mangle] pub fn f128_as_f16(a: f128) -> f16 { // CHECK: fptrunc fp128 %{{.+}} to half @@ -273,70 +278,70 @@ pub fn f16_as_i128(a: f16) -> i128 { /* int to float conversions */ -// CHECK-LABEL: half @u8_as_f16( +// CHECK-LABEL: @u8_as_f16 #[no_mangle] pub fn u8_as_f16(a: u8) -> f16 { // CHECK: uitofp i8 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u16_as_f16( +// CHECK-LABEL: @u16_as_f16 #[no_mangle] pub fn u16_as_f16(a: u16) -> f16 { // CHECK: uitofp i16 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u32_as_f16( +// CHECK-LABEL: @u32_as_f16 #[no_mangle] pub fn u32_as_f16(a: u32) -> f16 { // CHECK: uitofp i32 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u64_as_f16( +// CHECK-LABEL: @u64_as_f16 #[no_mangle] pub fn u64_as_f16(a: u64) -> f16 { // CHECK: uitofp i64 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u128_as_f16( +// CHECK-LABEL: @u128_as_f16 #[no_mangle] pub fn u128_as_f16(a: u128) -> f16 { // CHECK: uitofp i128 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i8_as_f16( +// CHECK-LABEL: @i8_as_f16 #[no_mangle] pub fn i8_as_f16(a: i8) -> f16 { // CHECK: sitofp i8 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i16_as_f16( +// CHECK-LABEL: @i16_as_f16 #[no_mangle] pub fn i16_as_f16(a: i16) -> f16 { // CHECK: sitofp i16 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i32_as_f16( +// CHECK-LABEL: @i32_as_f16 #[no_mangle] pub fn i32_as_f16(a: i32) -> f16 { // CHECK: sitofp i32 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i64_as_f16( +// CHECK-LABEL: @i64_as_f16 #[no_mangle] pub fn i64_as_f16(a: i64) -> f16 { // CHECK: sitofp i64 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i128_as_f16( +// CHECK-LABEL: @i128_as_f16 #[no_mangle] pub fn i128_as_f16(a: i128) -> f16 { // CHECK: sitofp i128 %{{.+}} to half diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index bf9f405192b..7fa1d659885 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -32,7 +32,7 @@ pub fn boolean(x: bool) -> bool { x } -// CHECK: i8 @maybeuninit_boolean(i8 %x) +// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x) #[no_mangle] pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> { x @@ -44,19 +44,19 @@ pub fn enum_bool(x: MyBool) -> MyBool { x } -// CHECK: i8 @maybeuninit_enum_bool(i8 %x) +// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x) #[no_mangle] pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> { x } -// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x) +// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x) #[no_mangle] pub fn char(x: char) -> char { x } -// CHECK: i32 @maybeuninit_char(i32 %x) +// CHECK: i32 @maybeuninit_char(i32{{.*}} %x) #[no_mangle] pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> { x diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs index f3b631abc22..9a476abe891 100644 --- a/tests/codegen/intrinsics/three_way_compare.rs +++ b/tests/codegen/intrinsics/three_way_compare.rs @@ -10,8 +10,7 @@ use std::intrinsics::three_way_compare; #[no_mangle] // CHECK-LABEL: @signed_cmp -// DEBUG-SAME: (i16 %a, i16 %b) -// OPTIM-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 @@ -29,8 +28,7 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { #[no_mangle] // CHECK-LABEL: @unsigned_cmp -// DEBUG-SAME: (i16 %a, i16 %b) -// OPTIM-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs index 04ffb075538..37b024a55b3 100644 --- a/tests/codegen/mir-aggregate-no-alloca.rs +++ b/tests/codegen/mir-aggregate-no-alloca.rs @@ -9,7 +9,7 @@ #[repr(transparent)] pub struct Transparent32(u32); -// CHECK: i32 @make_transparent(i32 noundef %x) +// CHECK: i32 @make_transparent(i32{{.*}} %x) #[no_mangle] pub fn make_transparent(x: u32) -> Transparent32 { // CHECK-NOT: alloca @@ -18,7 +18,7 @@ pub fn make_transparent(x: u32) -> Transparent32 { a } -// CHECK: i32 @make_closure(i32 noundef %x) +// CHECK: i32 @make_closure(i32{{.*}} %x) #[no_mangle] pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 { // CHECK-NOT: alloca @@ -40,7 +40,7 @@ pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair { a } -// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x) +// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x) #[no_mangle] pub fn make_2_tuple(x: u32) -> (u32, u32) { // CHECK-NOT: alloca @@ -59,7 +59,7 @@ pub fn make_cell_of_bool(b: bool) -> std::cell::Cell<bool> { std::cell::Cell::new(b) } -// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s) +// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s) #[no_mangle] pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> { // CHECK-NOT: alloca @@ -92,7 +92,7 @@ pub fn make_struct_0() -> Struct0 { pub struct Struct1(i32); -// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a) +// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a) #[no_mangle] pub fn make_struct_1(a: i32) -> Struct1 { // CHECK: ret i32 %a @@ -104,7 +104,7 @@ pub struct Struct2Asc(i16, i64); // bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s, // bit64-LABEL: { i64, i16 } @make_struct_2_asc( -// CHECK-SAME: i16 noundef %a, i64 noundef %b) +// CHECK-SAME: i16{{.*}} %a, i64 noundef %b) #[no_mangle] pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc { // CHECK-NOT: alloca @@ -122,7 +122,7 @@ pub struct Struct2Desc(i64, i16); // bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s, // bit64-LABEL: { i64, i16 } @make_struct_2_desc( -// CHECK-SAME: i64 noundef %a, i16 noundef %b) +// CHECK-SAME: i64 noundef %a, i16{{.*}} %b) #[no_mangle] pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc { // CHECK-NOT: alloca diff --git a/tests/codegen/placement-new.rs b/tests/codegen/placement-new.rs index edb25df5eb4..0ec2b6a6f20 100644 --- a/tests/codegen/placement-new.rs +++ b/tests/codegen/placement-new.rs @@ -1,9 +1,11 @@ //@ compile-flags: -O +//@ compile-flags: -Zmerge-functions=disabled #![crate_type = "lib"] // Test to check that types with "complex" destructors, but trivial `Default` impls // are constructed directly into the allocation in `Box::default` and `Arc::default`. +use std::rc::Rc; use std::sync::Arc; // CHECK-LABEL: @box_default_inplace @@ -16,6 +18,16 @@ pub fn box_default_inplace() -> Box<(String, String)> { Box::default() } +// CHECK-LABEL: @rc_default_inplace +#[no_mangle] +pub fn rc_default_inplace() -> Rc<(String, String)> { + // CHECK-NOT: alloca + // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc( + // CHECK-NOT: call void @llvm.memcpy + // CHECK: ret ptr [[RC]] + Rc::default() +} + // CHECK-LABEL: @arc_default_inplace #[no_mangle] pub fn arc_default_inplace() -> Arc<(String, String)> { diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs index 8972fc76ca2..a44ec1026b1 100644 --- a/tests/codegen/range-attribute.rs +++ b/tests/codegen/range-attribute.rs @@ -24,7 +24,7 @@ pub fn nonzero_int(x: NonZero<u128>) -> NonZero<u128> { x } -// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x) +// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x) #[no_mangle] pub fn optional_bool(x: Option<bool>) -> Option<bool> { x @@ -36,7 +36,7 @@ pub enum Enum0 { C, } -// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x) +// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x) #[no_mangle] pub fn enum0_value(x: Enum0) -> Enum0 { x diff --git a/tests/codegen/rust-abi-arch-specific-adjustment.rs b/tests/codegen/rust-abi-arch-specific-adjustment.rs new file mode 100644 index 00000000000..9da10f662b0 --- /dev/null +++ b/tests/codegen/rust-abi-arch-specific-adjustment.rs @@ -0,0 +1,111 @@ +//@ compile-flags: -O -C no-prepopulate-passes +//@ revisions: riscv64 loongarch64 + +//@[riscv64] only-riscv64 +//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@[riscv64] needs-llvm-components: riscv + +//@[loongarch64] only-loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch + +#![crate_type = "lib"] + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +pub fn arg_attr_u8(x: u8) -> u8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +pub fn arg_attr_u16(x: u16) -> u16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +pub fn arg_attr_u32(x: u32) -> u32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_u64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x) +pub fn arg_attr_u64(x: u64) -> u64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_u128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x) +pub fn arg_attr_u128(x: u128) -> u128 { + x +} + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +pub fn arg_attr_i8(x: i8) -> i8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +pub fn arg_attr_i16(x: i16) -> i16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +pub fn arg_attr_i32(x: i32) -> i32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_i64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x) +pub fn arg_attr_i64(x: i64) -> i64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_i128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x) +pub fn arg_attr_i128(x: i128) -> i128 { + x +} + +#[no_mangle] +// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +pub fn arg_attr_bool(x: bool) -> bool { + x +} + +#[no_mangle] +// ignore-tidy-linelength +// riscv64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +pub fn arg_attr_char(x: char) -> char { + x +} + +#[no_mangle] +// riscv64: define noundef float @arg_attr_f32(float noundef %x) +// loongarch64: define noundef float @arg_attr_f32(float noundef %x) +pub fn arg_attr_f32(x: f32) -> f32 { + x +} + +#[no_mangle] +// riscv64: define noundef double @arg_attr_f64(double noundef %x) +// loongarch64: define noundef double @arg_attr_f64(double noundef %x) +pub fn arg_attr_f64(x: f64) -> f64 { + x +} diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs index 259967e8918..71ccdc8ca62 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs @@ -12,7 +12,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: Function Attrs: {{.*}} // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: start: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) // CHECK-NEXT: ret i32 {{%.+}} f(arg) } diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks.rs b/tests/codegen/sanitizer/cfi/emit-type-checks.rs index 37edbefee56..ebc66a015df 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-checks.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-checks.rs @@ -11,7 +11,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) // CHECK: type_test.fail: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: unreachable diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index caaa70962d5..43da7c1781e 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -25,7 +25,7 @@ pub fn bool_to_byte(b: bool) -> u8 { unsafe { std::mem::transmute(b) } } -// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte) +// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) // CHECK: %_0 = trunc i8 %byte to i1 // CHECK-NEXT: ret i1 %_0 #[no_mangle] diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index b3c67a59730..2f14682dfa5 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -131,7 +131,7 @@ pub fn test_CUnionU128(_: CUnionU128) { pub union UnionBool { b: bool, } -// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b) +// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b) #[no_mangle] pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index fd163a55551..4ea5b3b436d 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b) +// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn test(a: u32, b: u32) -> u32 { let c = a + b; diff --git a/tests/run-make/import-macro-verbatim/include/include.txt b/tests/run-make/import-macro-verbatim/include/include.txt new file mode 100644 index 00000000000..63d71b14c1d --- /dev/null +++ b/tests/run-make/import-macro-verbatim/include/include.txt @@ -0,0 +1 @@ +static TEST: &str = "Hello World!"; diff --git a/tests/run-make/import-macro-verbatim/rmake.rs b/tests/run-make/import-macro-verbatim/rmake.rs new file mode 100644 index 00000000000..d2bf626e0aa --- /dev/null +++ b/tests/run-make/import-macro-verbatim/rmake.rs @@ -0,0 +1,8 @@ +//@ only-windows other platforms do not have Windows verbatim paths +use run_make_support::rustc; +fn main() { + // Canonicalizing the path ensures that it's verbatim (i.e. starts with `\\?\`) + let mut path = std::fs::canonicalize(file!()).unwrap(); + path.pop(); + rustc().input("verbatim.rs").env("VERBATIM_DIR", path).run(); +} diff --git a/tests/run-make/import-macro-verbatim/verbatim.rs b/tests/run-make/import-macro-verbatim/verbatim.rs new file mode 100644 index 00000000000..56a83673c1f --- /dev/null +++ b/tests/run-make/import-macro-verbatim/verbatim.rs @@ -0,0 +1,12 @@ +//! Include a file by concating the verbatim path using `/` instead of `\` + +include!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); +fn main() { + assert_eq!(TEST, "Hello World!"); + + let s = include_str!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); + assert_eq!(s, "static TEST: &str = \"Hello World!\";\n"); + + let b = include_bytes!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); + assert_eq!(b, b"static TEST: &str = \"Hello World!\";\n"); +} diff --git a/tests/run-make/rust-lld-link-script-provide/main.rs b/tests/run-make/rust-lld-link-script-provide/main.rs new file mode 100644 index 00000000000..5c19e7a4bbf --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/main.rs @@ -0,0 +1,7 @@ +#[no_mangle] +fn foo() {} + +#[no_mangle] +fn bar() {} + +fn main() {} diff --git a/tests/run-make/rust-lld-link-script-provide/rmake.rs b/tests/run-make/rust-lld-link-script-provide/rmake.rs new file mode 100644 index 00000000000..e78a411bc15 --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/rmake.rs @@ -0,0 +1,18 @@ +// This test ensures that the “symbol not found” error does not occur +// when the symbols in the `PROVIDE` of the link script can be eliminated. +// This is a regression test for #131164. + +//@ needs-rust-lld +//@ only-x86_64-unknown-linux-gnu + +use run_make_support::rustc; + +fn main() { + rustc() + .input("main.rs") + .arg("-Zlinker-features=+lld") + .arg("-Clink-self-contained=+linker") + .arg("-Zunstable-options") + .link_arg("-Tscript.t") + .run(); +} diff --git a/tests/run-make/rust-lld-link-script-provide/script.t b/tests/run-make/rust-lld-link-script-provide/script.t new file mode 100644 index 00000000000..4c4c6ddfc36 --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/script.t @@ -0,0 +1 @@ +PROVIDE(foo = bar); diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs index e4802ee2518..3b59e05a012 100644 --- a/tests/rustdoc-ui/deprecated-attrs.rs +++ b/tests/rustdoc-ui/deprecated-attrs.rs @@ -1,16 +1,21 @@ -//@ check-pass //@ compile-flags: --passes unknown-pass //@ error-pattern: the `passes` flag no longer functions #![doc(no_default_passes)] -//~^ WARNING attribute is deprecated +//~^ ERROR unknown `doc` attribute `no_default_passes` +//~| NOTE no longer functions //~| NOTE see issue #44136 -//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]` +//~| HELP you may want to use `doc(document_private_items)` +//~| NOTE `doc(no_default_passes)` is now a no-op +//~| NOTE `#[deny(invalid_doc_attributes)]` on by default #![doc(passes = "collapse-docs unindent-comments")] -//~^ WARNING attribute is deprecated +//~^ ERROR unknown `doc` attribute `passes` +//~| NOTE no longer functions //~| NOTE see issue #44136 -//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]` +//~| HELP you may want to use `doc(document_private_items)` +//~| NOTE `doc(passes)` is now a no-op #![doc(plugins = "xxx")] -//~^ WARNING attribute is deprecated +//~^ ERROR unknown `doc` attribute `plugins` //~| NOTE see issue #44136 -//~| WARNING no longer functions; see CVE +//~| NOTE no longer functions +//~| NOTE `doc(plugins)` is now a no-op diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr index 45b20ce70ef..a30523e7329 100644 --- a/tests/rustdoc-ui/deprecated-attrs.stderr +++ b/tests/rustdoc-ui/deprecated-attrs.stderr @@ -3,32 +3,35 @@ warning: the `passes` flag no longer functions = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information = help: you may want to use --document-private-items -warning: the `#![doc(no_default_passes)]` attribute is deprecated - --> $DIR/deprecated-attrs.rs:5:8 +error: unknown `doc` attribute `no_default_passes` + --> $DIR/deprecated-attrs.rs:4:8 | LL | #![doc(no_default_passes)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ no longer functions | - = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information - = help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]` + = note: `doc` attribute `no_default_passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> + = help: you may want to use `doc(document_private_items)` + = note: `doc(no_default_passes)` is now a no-op + = note: `#[deny(invalid_doc_attributes)]` on by default -warning: the `#![doc(passes = "...")]` attribute is deprecated - --> $DIR/deprecated-attrs.rs:9:8 +error: unknown `doc` attribute `passes` + --> $DIR/deprecated-attrs.rs:11:8 | LL | #![doc(passes = "collapse-docs unindent-comments")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions | - = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information - = help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]` + = note: `doc` attribute `passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> + = help: you may want to use `doc(document_private_items)` + = note: `doc(passes)` is now a no-op -warning: the `#![doc(plugins = "...")]` attribute is deprecated - --> $DIR/deprecated-attrs.rs:13:8 +error: unknown `doc` attribute `plugins` + --> $DIR/deprecated-attrs.rs:17:8 | LL | #![doc(plugins = "xxx")] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ no longer functions | - = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information - = warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622> + = note: `doc` attribute `plugins` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622> + = note: `doc(plugins)` is now a no-op -warning: 3 warnings emitted +error: aborting due to 3 previous errors diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 28c8063a923..33d67360ff1 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -211,6 +211,15 @@ impl Clone for Zst { } } +enum Either<T, U> { + Left(T), + Right(U), +} +enum Either2<T, U> { + Left(T), + Right(U, ()), +} + #[repr(C)] enum ReprCEnum<T> { Variant1, @@ -328,7 +337,8 @@ mod unsized_ { test_transparent_unsized!(dyn_trait, dyn Any); } -// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>. +// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>, including the +// extension ratified at <https://github.com/rust-lang/rust/pull/130628#issuecomment-2402761599>. macro_rules! test_nonnull { ($name:ident, $t:ty) => { mod $name { @@ -340,6 +350,12 @@ macro_rules! test_nonnull { test_abi_compatible!(result_ok_zst, Result<Zst, $t>, $t); test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t); test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t); + test_abi_compatible!(result_err_void, Result<$t, Void>, $t); + test_abi_compatible!(result_ok_void, Result<Void, $t>, $t); + test_abi_compatible!(either_err_zst, Either<$t, Zst>, $t); + test_abi_compatible!(either_ok_zst, Either<Zst, $t>, $t); + test_abi_compatible!(either2_err_zst, Either2<$t, Zst>, $t); + test_abi_compatible!(either2_err_arr, Either2<$t, [i8; 0]>, $t); } } } diff --git a/tests/ui/async-await/field-in-sync.rs b/tests/ui/async-await/field-in-sync.rs new file mode 100644 index 00000000000..586980c6e2b --- /dev/null +++ b/tests/ui/async-await/field-in-sync.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 + +struct S { + field: (), +} + +async fn foo() -> S { todo!() } + +fn main() -> Result<(), ()> { + foo().field; + //~^ ERROR no field `field` on type `impl Future<Output = S>` + Ok(()) +} diff --git a/tests/ui/async-await/field-in-sync.stderr b/tests/ui/async-await/field-in-sync.stderr new file mode 100644 index 00000000000..7be30339c27 --- /dev/null +++ b/tests/ui/async-await/field-in-sync.stderr @@ -0,0 +1,17 @@ +error[E0609]: no field `field` on type `impl Future<Output = S>` + --> $DIR/field-in-sync.rs:10:11 + | +LL | foo().field; + | ^^^^^ field not available in `impl Future`, but it is available in its `Output` + | +note: this implements `Future` and its output type has the field, but the future cannot be awaited in a synchronous function + --> $DIR/field-in-sync.rs:10:5 + | +LL | fn main() -> Result<(), ()> { + | --------------------------- this is not `async` +LL | foo().field; + | ^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr index 44de282988b..b8478c8d138 100644 --- a/tests/ui/async-await/issue-61076.stderr +++ b/tests/ui/async-await/issue-61076.stderr @@ -28,7 +28,7 @@ error[E0609]: no field `0` on type `impl Future<Output = Tuple>` LL | let _: i32 = tuple().0; | ^ field not available in `impl Future`, but it is available in its `Output` | -help: consider `await`ing on the `Future` and access the field of its `Output` +help: consider `await`ing on the `Future` to access the field | LL | let _: i32 = tuple().await.0; | ++++++ @@ -39,7 +39,7 @@ error[E0609]: no field `a` on type `impl Future<Output = Struct>` LL | let _: i32 = struct_().a; | ^ field not available in `impl Future`, but it is available in its `Output` | -help: consider `await`ing on the `Future` and access the field of its `Output` +help: consider `await`ing on the `Future` to access the field | LL | let _: i32 = struct_().await.a; | ++++++ diff --git a/tests/ui/async-await/try-in-sync.rs b/tests/ui/async-await/try-in-sync.rs new file mode 100644 index 00000000000..81d72c3fb9a --- /dev/null +++ b/tests/ui/async-await/try-in-sync.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 + +async fn foo() -> Result<(), ()> { todo!() } + +fn main() -> Result<(), ()> { + foo()?; + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + Ok(()) +} diff --git a/tests/ui/async-await/try-in-sync.stderr b/tests/ui/async-await/try-in-sync.stderr new file mode 100644 index 00000000000..bc7a6bd0151 --- /dev/null +++ b/tests/ui/async-await/try-in-sync.stderr @@ -0,0 +1,18 @@ +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/try-in-sync.rs:6:5 + | +LL | foo()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>` + | + = help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>` +note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function + --> $DIR/try-in-sync.rs:6:10 + | +LL | fn main() -> Result<(), ()> { + | --------------------------- this is not `async` +LL | foo()?; + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 3a2d4df3bee..bd0c8cbc3b1 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -141,10 +141,10 @@ hir-stats FnDecl 120 ( 1.3%) 3 40 hir-stats Attribute 128 ( 1.4%) 4 32 hir-stats GenericArgs 144 ( 1.6%) 3 48 hir-stats Variant 144 ( 1.6%) 2 72 -hir-stats GenericBound 192 ( 2.1%) 4 48 -hir-stats - Trait 192 ( 2.1%) 4 hir-stats WherePredicate 192 ( 2.1%) 3 64 hir-stats - BoundPredicate 192 ( 2.1%) 3 +hir-stats GenericBound 256 ( 2.8%) 4 64 +hir-stats - Trait 256 ( 2.8%) 4 hir-stats Block 288 ( 3.2%) 6 48 hir-stats GenericParam 360 ( 4.0%) 5 72 hir-stats Pat 360 ( 4.0%) 5 72 @@ -155,15 +155,15 @@ hir-stats Generics 560 ( 6.2%) 10 56 hir-stats Ty 720 ( 8.0%) 15 48 hir-stats - Ref 48 ( 0.5%) 1 hir-stats - Ptr 48 ( 0.5%) 1 -hir-stats - Path 624 ( 7.0%) 13 -hir-stats Expr 768 ( 8.6%) 12 64 +hir-stats - Path 624 ( 6.9%) 13 +hir-stats Expr 768 ( 8.5%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 hir-stats - Block 384 ( 4.3%) 6 -hir-stats Item 968 (10.8%) 11 88 +hir-stats Item 968 (10.7%) 11 88 hir-stats - Enum 88 ( 1.0%) 1 hir-stats - Trait 88 ( 1.0%) 1 hir-stats - Impl 88 ( 1.0%) 1 @@ -171,8 +171,8 @@ hir-stats - ExternCrate 88 ( 1.0%) 1 hir-stats - ForeignMod 88 ( 1.0%) 1 hir-stats - Fn 176 ( 2.0%) 2 hir-stats - Use 352 ( 3.9%) 4 -hir-stats Path 1_240 (13.8%) 31 40 -hir-stats PathSegment 1_920 (21.4%) 40 48 +hir-stats Path 1_240 (13.7%) 31 40 +hir-stats PathSegment 1_920 (21.3%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_960 +hir-stats Total 9_024 hir-stats |
