diff options
138 files changed, 2273 insertions, 1063 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 42f3569f0f1..53e64439afc 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -40,7 +40,7 @@ ast_passes_auto_generic = auto traits cannot have generic parameters ast_passes_auto_items = auto traits cannot have associated items .label = {ast_passes_auto_items} - .suggestion = remove these associated items + .suggestion = remove the associated items ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds .label = {ast_passes_auto_super_lifetime} diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ae482ceb9b7..1c1c5f82f3e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -699,19 +699,23 @@ impl<'a> AstValidator<'a> { } } - fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { + fn deny_super_traits(&self, bounds: &GenericBounds, ident: Span) { if let [.., last] = &bounds[..] { - let span = ident_span.shrink_to_hi().to(last.span()); - self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span }); + let span = bounds.iter().map(|b| b.span()).collect(); + let removal = ident.shrink_to_hi().to(last.span()); + self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident }); } } - fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { + fn deny_where_clause(&self, where_clause: &WhereClause, ident: Span) { if !where_clause.predicates.is_empty() { // FIXME: The current diagnostic is misleading since it only talks about // super trait and lifetime bounds while we should just say “bounds”. - self.dcx() - .emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span }); + self.dcx().emit_err(errors::AutoTraitBounds { + span: vec![where_clause.span], + removal: where_clause.span, + ident, + }); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 8b5873a3ef3..60f47490f12 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -344,7 +344,7 @@ pub(crate) struct ModuleNonAscii { #[diag(ast_passes_auto_generic, code = E0567)] pub(crate) struct AutoTraitGeneric { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub span: Span, #[label] pub ident: Span, @@ -354,8 +354,9 @@ pub(crate) struct AutoTraitGeneric { #[diag(ast_passes_auto_super_lifetime, code = E0568)] pub(crate) struct AutoTraitBounds { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub span: Span, + pub span: Vec<Span>, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub removal: Span, #[label] pub ident: Span, } @@ -365,7 +366,7 @@ pub(crate) struct AutoTraitBounds { pub(crate) struct AutoTraitItems { #[primary_span] pub spans: Vec<Span>, - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub total: Span, #[label] pub ident: Span, diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index a90ed830cd1..77b494328c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -44,3 +44,55 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser { }) } } + +pub(crate) struct ShouldPanicParser; + +impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser { + const PATH: &[Symbol] = &[sym::should_panic]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = + template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + Some(AttributeKind::ShouldPanic { + span: cx.attr_span, + reason: match args { + ArgParser::NoArgs => None, + ArgParser::NameValue(name_value) => { + let Some(str_value) = name_value.value_as_str() else { + cx.expected_string_literal( + name_value.value_span, + Some(name_value.value_as_lit()), + ); + return None; + }; + Some(str_value) + } + ArgParser::List(list) => { + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(single) = single.meta_item() else { + cx.expected_name_value(single.span(), Some(sym::expected)); + return None; + }; + if !single.path().word_is(sym::expected) { + cx.expected_specific_argument_strings(list.span, vec!["expected"]); + return None; + } + let Some(nv) = single.args().name_value() else { + cx.expected_name_value(single.span(), Some(sym::expected)); + return None; + }; + let Some(expected) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + Some(expected) + } + }, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 911d2e13310..80dfdffdb55 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -50,7 +50,7 @@ use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; -use crate::attributes::test_attrs::IgnoreParser; +use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser}; use crate::attributes::traits::{ AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, @@ -174,6 +174,7 @@ attribute_parsers!( Single<RustcLayoutScalarValidRangeEnd>, Single<RustcLayoutScalarValidRangeStart>, Single<RustcObjectLifetimeDefaultParser>, + Single<ShouldPanicParser>, Single<SkipDuringMethodDispatchParser>, Single<TransparencyParser>, Single<WithoutArgs<AllowIncoherentImplParser>>, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index ba3d8368b2a..7b57c02b197 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,10 +5,13 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; +use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents}; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; @@ -473,39 +476,19 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> { } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match attr::find_by_name(&i.attrs, sym::should_panic) { - Some(attr) => { - match attr.meta_item_list() { - // Handle #[should_panic(expected = "foo")] - Some(list) => { - let msg = list - .iter() - .find(|mi| mi.has_name(sym::expected)) - .and_then(|mi| mi.meta_item()) - .and_then(|mi| mi.value_str()); - if list.len() != 1 || msg.is_none() { - cx.dcx() - .struct_span_warn( - attr.span, - "argument must be of the form: \ - `expected = \"error message\"`", - ) - .with_note( - "errors in this attribute were erroneously \ - allowed and will become a hard error in a \ - future release", - ) - .emit(); - ShouldPanic::Yes(None) - } else { - ShouldPanic::Yes(msg) - } - } - // Handle #[should_panic] and #[should_panic = "expected"] - None => ShouldPanic::Yes(attr.value_str()), - } - } - None => ShouldPanic::No, + if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) = + AttributeParser::parse_limited( + cx.sess, + &i.attrs, + sym::should_panic, + i.span, + i.node_id(), + None, + ) + { + ShouldPanic::Yes(reason) + } else { + ShouldPanic::No } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53899da183a..3b290e5a129 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -262,6 +262,15 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea // Filter out features that are not supported by the current LLVM version ("aarch64", "fpmr") => None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), + // NVPTX targets added in LLVM 20 + ("nvptx64", "sm_100") if get_version().0 < 20 => None, + ("nvptx64", "sm_100a") if get_version().0 < 20 => None, + ("nvptx64", "sm_101") if get_version().0 < 20 => None, + ("nvptx64", "sm_101a") if get_version().0 < 20 => None, + ("nvptx64", "sm_120") if get_version().0 < 20 => None, + ("nvptx64", "sm_120a") if get_version().0 < 20 => None, + ("nvptx64", "ptx86") if get_version().0 < 20 => None, + ("nvptx64", "ptx87") if get_version().0 < 20 => None, // Filter out features that are not supported by the current LLVM version ("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq") if get_version().0 < 20 => @@ -324,15 +333,12 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen. pub(crate) fn target_config(sess: &Session) -> TargetConfig { - // Add base features for the target. - // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below. - // The reason is that if LLVM considers a feature implied but we do not, we don't want that to - // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of - // the target CPU, that is still expanded to target features (with all their implied features) - // by LLVM. let target_machine = create_informational_target_machine(sess, true); let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + // This closure determines whether the target CPU has the feature according to LLVM. We do + // *not* consider the `-Ctarget-feature`s here, as that will be handled later in + // `cfg_target_feature`. if let Some(feat) = to_llvm_features(sess, feature) { // All the LLVM features this expands to must be enabled. for llvm_feature in feat { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index d984156c674..7e4341a8236 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -197,7 +197,10 @@ fn parse_rust_feature_flag<'a>( /// 2nd component of the return value, respectively). /// /// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is -/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. Note that LLVM +/// may consider features to be implied that we do not and vice-versa. We want `cfg` to be entirely +/// consistent with Rust feature implications, and thus only consult LLVM to expand the target CPU +/// to target features. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( @@ -211,7 +214,15 @@ pub fn cfg_target_feature( .rust_target_features() .iter() .filter(|(feature, _, _)| target_base_has_feature(feature)) - .map(|(feature, _, _)| Symbol::intern(feature)) + .flat_map(|(base_feature, _, _)| { + // Expand the direct base feature into all transitively-implied features. Note that we + // cannot simply use the `implied` field of the tuple since that only contains + // directly-implied features. + // + // Iteration order is irrelevant because we're collecting into an `UnordSet`. + #[allow(rustc::potential_query_instability)] + sess.target.implied_target_features(base_feature).into_iter().map(|f| Symbol::intern(f)) + }) .collect(); // Add enabled and remove disabled features. diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 3840cdf7575..8ace560d85d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![doc(rust_logo)] #![feature(array_try_map)] #![feature(assert_matches)] @@ -10,7 +11,6 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_ptr_get)] -#![feature(strict_overflow_ops)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unqualified_local_imports)] diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index e6b9759819f..2dc746754f8 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -18,7 +18,9 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - unreachable!(); // because `<Self As PrettyPrinter>::should_print_region` returns false + // This is reachable (via `pretty_print_dyn_existential`) even though + // `<Self As PrettyPrinter>::should_print_region` returns false. See #144994. + Ok(()) } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 86e820bcd6b..ca71bcebfdd 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -327,6 +327,7 @@ declare_features! ( (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, movrs_target_feature, "1.88.0", Some(137976)), + (unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index d9d2ec48948..5f419315467 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -436,6 +436,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[should_panic]` + ShouldPanic { reason: Option<Symbol>, span: Span }, + /// Represents `#[rustc_skip_during_method_dispatch]`. SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index b66e5bbeabe..e3a7f0b97a8 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -70,6 +70,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, + ShouldPanic { .. } => No, SkipDuringMethodDispatch { .. } => No, SpecializationTrait(..) => No, Stability { .. } => Yes, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c30c830f9af..34db6f92d92 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1308,6 +1308,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, + Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 2a5a34cdc6e..464f4fc34b9 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -434,7 +434,7 @@ fn emit_mismatch_diagnostic<'tcx>( lints::MismatchedLifetimeSyntaxesSuggestion::Mixed { implicit_suggestions, explicit_anonymous_suggestions, - tool_only: false, + optional_alternative: false, } }); @@ -455,7 +455,10 @@ fn emit_mismatch_diagnostic<'tcx>( let implicit_suggestion = should_suggest_implicit.then(|| { let suggestions = make_implicit_suggestions(&suggest_change_to_implicit); - lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { suggestions, tool_only: false } + lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { + suggestions, + optional_alternative: false, + } }); tracing::debug!( @@ -508,7 +511,7 @@ fn build_mismatch_suggestion( lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { lifetime_name, suggestions, - tool_only: false, + optional_alternative: false, } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ef63c0dee8c..ac6147b1631 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3292,7 +3292,7 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta diag.subdiagnostic(s); for mut s in suggestions { - s.make_tool_only(); + s.make_optional_alternative(); diag.subdiagnostic(s); } } @@ -3303,33 +3303,33 @@ impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSynta pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { Implicit { suggestions: Vec<Span>, - tool_only: bool, + optional_alternative: bool, }, Mixed { implicit_suggestions: Vec<Span>, explicit_anonymous_suggestions: Vec<(Span, String)>, - tool_only: bool, + optional_alternative: bool, }, Explicit { lifetime_name: String, suggestions: Vec<(Span, String)>, - tool_only: bool, + optional_alternative: bool, }, } impl MismatchedLifetimeSyntaxesSuggestion { - fn make_tool_only(&mut self) { + fn make_optional_alternative(&mut self) { use MismatchedLifetimeSyntaxesSuggestion::*; - let tool_only = match self { - Implicit { tool_only, .. } | Mixed { tool_only, .. } | Explicit { tool_only, .. } => { - tool_only - } + let optional_alternative = match self { + Implicit { optional_alternative, .. } + | Mixed { optional_alternative, .. } + | Explicit { optional_alternative, .. } => optional_alternative, }; - *tool_only = true; + *optional_alternative = true; } } @@ -3337,22 +3337,40 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { use MismatchedLifetimeSyntaxesSuggestion::*; - let style = |tool_only| { - if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways } + let style = |optional_alternative| { + if optional_alternative { + SuggestionStyle::CompletelyHidden + } else { + SuggestionStyle::ShowAlways + } + }; + + let applicability = |optional_alternative| { + // `cargo fix` can't handle more than one fix for the same issue, + // so hide alternative suggestions from it by marking them as maybe-incorrect + if optional_alternative { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } }; match self { - Implicit { suggestions, tool_only } => { + Implicit { suggestions, optional_alternative } => { let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect(); diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } - Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => { + Mixed { + implicit_suggestions, + explicit_anonymous_suggestions, + optional_alternative, + } => { let message = if implicit_suggestions.is_empty() { fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths } else { @@ -3368,12 +3386,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( message, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } - Explicit { lifetime_name, suggestions, tool_only } => { + Explicit { lifetime_name, suggestions, optional_alternative } => { diag.arg("lifetime_name", lifetime_name); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, @@ -3382,8 +3400,8 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( msg, suggestions, - Applicability::MaybeIncorrect, - style(tool_only), + applicability(optional_alternative), + style(optional_alternative), ); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3b84c6b6110..e660b950262 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2156,6 +2156,7 @@ declare_lint! { @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", + report_in_deps: true, }; crate_level_only } @@ -2839,7 +2840,7 @@ declare_lint! { /// [issue #79813]: https://github.com/rust-lang/rust/issues/79813 /// [future-incompatible]: ../index.md#future-incompatible-lints pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - Warn, + Deny, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, @@ -2887,11 +2888,12 @@ declare_lint! { /// struct S { /* fields */ } /// ``` pub LEGACY_DERIVE_HELPERS, - Warn, + Deny, "detects derive helper attributes that are used before they are introduced", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>", + report_in_deps: true, }; } @@ -4624,11 +4626,12 @@ declare_lint! { /// /// [future-incompatible]: ../index.md#future-incompatible-lints pub PRIVATE_MACRO_USE, - Warn, + Deny, "detects certain macro bindings that should not be re-exported", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #120192 <https://github.com/rust-lang/rust/issues/120192>", + report_in_deps: true, }; } @@ -4828,7 +4831,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,compile_fail /// #![doc = in_root!()] /// /// macro_rules! in_root { () => { "" } } @@ -4853,11 +4856,12 @@ declare_lint! { /// /// [future-incompatible]: ../index.md#future-incompatible-lints pub OUT_OF_SCOPE_MACRO_CALLS, - Warn, + Deny, "detects out of scope calls to `macro_rules` in key-value attributes", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>", + report_in_deps: true, }; } diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index a71196f79d7..566d89f4269 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use tracing::debug; use crate::builder::ForGuard::OutsideGuard; -use crate::builder::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; +use crate::builder::matches::{DeclareLetBindings, ScheduleDrops}; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -199,15 +199,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, Some((Some(&destination), initializer_span)), ); - this.visit_primary_bindings(pattern, &mut |this, node, span| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - ScheduleDrops::Yes, - ); - }); let else_block_span = this.thir[*else_block].span; let (matching, failure) = this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { @@ -218,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, initializer_span, DeclareLetBindings::No, - EmitStorageLive::No, ) }); matching.and(failure) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 3a7854a5e11..7a848536d0e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -124,9 +124,19 @@ impl<'tcx> MatchPairTree<'tcx> { let test_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, - PatKind::Or { ref pats } => Some(TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }), + PatKind::Or { ref pats } => { + let pats: Box<[FlatPat<'tcx>]> = + pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(); + if !pats[0].extra_data.bindings.is_empty() { + // Hold a place for any bindings established in (possibly-nested) or-patterns. + // By only holding a place when bindings are present, we skip over any + // or-patterns that will be simplified by `merge_trivial_subcandidates`. In + // other words, we can assume this expands into subcandidates. + // FIXME(@dianne): this needs updating/removing if we always merge or-patterns + extra_data.bindings.push(super::SubpatternBindings::FromOrPattern); + } + Some(TestCase::Or { pats }) + } PatKind::Range(ref range) => { if range.is_full_range(cx.tcx) == Some(true) { @@ -194,12 +204,12 @@ impl<'tcx> MatchPairTree<'tcx> { // Then push this binding, after any bindings in the subpattern. if let Some(source) = place { - extra_data.bindings.push(super::Binding { + extra_data.bindings.push(super::SubpatternBindings::One(super::Binding { span: pattern.span, source, var_id: var, binding_mode: mode, - }); + })); } None diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2c29b862841..aebd78515a2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,11 +5,11 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::mem; use std::sync::Arc; +use itertools::{Itertools, Position}; use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -69,18 +69,6 @@ pub(crate) enum DeclareLetBindings { LetNotPermitted, } -/// Used by [`Builder::bind_matched_candidate_for_arm_body`] to determine -/// whether or not to call [`Builder::storage_live_binding`] to emit -/// [`StatementKind::StorageLive`]. -#[derive(Clone, Copy)] -pub(crate) enum EmitStorageLive { - /// Yes, emit `StorageLive` as normal. - Yes, - /// No, don't emit `StorageLive`. The caller has taken responsibility for - /// emitting `StorageLive` as appropriate. - No, -} - /// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`] /// to decide whether to schedule drops. #[derive(Clone, Copy, Debug)] @@ -207,7 +195,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, - EmitStorageLive::Yes, ), _ => { let mut block = block; @@ -479,7 +466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &built_match_tree.fake_borrow_temps, scrutinee_span, Some((arm, match_scope)), - EmitStorageLive::Yes, ); this.fixed_temps_scope = old_dedup_scope; @@ -533,7 +519,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - emit_storage_live: EmitStorageLive, ) -> BasicBlock { if branch.sub_branches.len() == 1 { let [sub_branch] = branch.sub_branches.try_into().unwrap(); @@ -544,7 +529,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, arm_match_scope, ScheduleDrops::Yes, - emit_storage_live, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -561,27 +545,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // return: it isn't bound by move until right before enter the arm. // To handle this we instead unschedule it's drop after each time // we lower the guard. + // As a result, we end up with the drop order of the last sub-branch we lower. To use + // the drop order for the first sub-branch, we lower sub-branches in reverse (#142163). let target_block = self.cfg.start_new_block(); - let mut schedule_drops = ScheduleDrops::Yes; - let arm = arm_match_scope.unzip().0; - // We keep a stack of all of the bindings and type ascriptions - // from the parent candidates that we visit, that also need to - // be bound for each candidate. - for sub_branch in branch.sub_branches { - if let Some(arm) = arm { - self.clear_top_scope(arm.scope); - } + for (pos, sub_branch) in branch.sub_branches.into_iter().rev().with_position() { + debug_assert!(pos != Position::Only); + let schedule_drops = + if pos == Position::Last { ScheduleDrops::Yes } else { ScheduleDrops::No }; let binding_end = self.bind_and_guard_matched_candidate( sub_branch, fake_borrow_temps, scrutinee_span, arm_match_scope, schedule_drops, - emit_storage_live, ); - if arm.is_none() { - schedule_drops = ScheduleDrops::No; - } self.cfg.goto(binding_end, outer_source_info, target_block); } @@ -741,7 +718,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &[], irrefutable_pat.span, None, - EmitStorageLive::Yes, ) .unit() } @@ -996,7 +972,7 @@ struct PatternExtraData<'tcx> { span: Span, /// Bindings that must be established. - bindings: Vec<Binding<'tcx>>, + bindings: Vec<SubpatternBindings<'tcx>>, /// Types that must be asserted. ascriptions: Vec<Ascription<'tcx>>, @@ -1011,6 +987,15 @@ impl<'tcx> PatternExtraData<'tcx> { } } +#[derive(Debug, Clone)] +enum SubpatternBindings<'tcx> { + /// A single binding. + One(Binding<'tcx>), + /// Holds the place for an or-pattern's bindings. This ensures their drops are scheduled in the + /// order the primary bindings appear. See rust-lang/rust#142163 for more information. + FromOrPattern, +} + /// A pattern in a form suitable for lowering the match tree, with all irrefutable /// patterns simplified away. /// @@ -1226,7 +1211,7 @@ fn traverse_candidate<'tcx, C, T, I>( } } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] struct Binding<'tcx> { span: Span, source: Place<'tcx>, @@ -1452,12 +1437,7 @@ impl<'tcx> MatchTreeSubBranch<'tcx> { span: candidate.extra_data.span, success_block: candidate.pre_binding_block.unwrap(), otherwise_block: candidate.otherwise_block.unwrap(), - bindings: parent_data - .iter() - .flat_map(|d| &d.bindings) - .chain(&candidate.extra_data.bindings) - .cloned() - .collect(), + bindings: sub_branch_bindings(parent_data, &candidate.extra_data.bindings), ascriptions: parent_data .iter() .flat_map(|d| &d.ascriptions) @@ -1490,6 +1470,68 @@ impl<'tcx> MatchTreeBranch<'tcx> { } } +/// Collects the bindings for a [`MatchTreeSubBranch`], preserving the order they appear in the +/// pattern, as though the or-alternatives chosen in this sub-branch were inlined. +fn sub_branch_bindings<'tcx>( + parents: &[PatternExtraData<'tcx>], + leaf_bindings: &[SubpatternBindings<'tcx>], +) -> Vec<Binding<'tcx>> { + // In the common case, all bindings will be in leaves. Allocate to fit the leaf's bindings. + let mut all_bindings = Vec::with_capacity(leaf_bindings.len()); + let mut remainder = parents + .iter() + .map(|parent| parent.bindings.as_slice()) + .chain([leaf_bindings]) + // Skip over unsimplified or-patterns without bindings. + .filter(|bindings| !bindings.is_empty()); + if let Some(candidate_bindings) = remainder.next() { + push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder); + } + // Make sure we've included all bindings. For ill-formed patterns like `(x, _ | y)`, we may not + // have collected all bindings yet, since we only check the first alternative when determining + // whether to inline subcandidates' bindings. + // FIXME(@dianne): prevent ill-formed patterns from getting here + while let Some(candidate_bindings) = remainder.next() { + ty::tls::with(|tcx| { + tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted") + }); + // To recover, we collect the rest in an arbitrary order. + push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder); + } + all_bindings +} + +/// Helper for [`sub_branch_bindings`]. Collects bindings from `candidate_bindings` into +/// `flattened`. Bindings in or-patterns are collected recursively from `remainder`. +fn push_sub_branch_bindings<'c, 'tcx: 'c>( + flattened: &mut Vec<Binding<'tcx>>, + candidate_bindings: &'c [SubpatternBindings<'tcx>], + remainder: &mut impl Iterator<Item = &'c [SubpatternBindings<'tcx>]>, +) { + for subpat_bindings in candidate_bindings { + match subpat_bindings { + SubpatternBindings::One(binding) => flattened.push(*binding), + SubpatternBindings::FromOrPattern => { + // Inline bindings from an or-pattern. By construction, this always + // corresponds to a subcandidate and its closest descendants (i.e. those + // from nested or-patterns, but not adjacent or-patterns). To handle + // adjacent or-patterns, e.g. `(x | x, y | y)`, we update the `remainder` to + // point to the first descendant candidate from outside this or-pattern. + if let Some(subcandidate_bindings) = remainder.next() { + push_sub_branch_bindings(flattened, subcandidate_bindings, remainder); + } else { + // For ill-formed patterns like `x | _`, we may not have any subcandidates left + // to inline bindings from. + // FIXME(@dianne): prevent ill-formed patterns from getting here + ty::tls::with(|tcx| { + tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted") + }); + }; + } + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum HasMatchGuard { Yes, @@ -2364,7 +2406,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_scope: Option<SourceScope>, scope_span: Span, declare_let_bindings: DeclareLetBindings, - emit_storage_live: EmitStorageLive, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); @@ -2398,14 +2439,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let success = self.bind_pattern( - self.source_info(pat.span), - branch, - &[], - expr_span, - None, - emit_storage_live, - ); + let success = self.bind_pattern(self.source_info(pat.span), branch, &[], expr_span, None); // If branch coverage is enabled, record this branch. self.visit_coverage_conditional_let(pat, success, built_tree.otherwise_block); @@ -2428,7 +2462,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: ScheduleDrops, - emit_storage_live: EmitStorageLive, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(subbranch={:?})", sub_branch); @@ -2453,11 +2486,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Bindings for guards require some extra handling to automatically // insert implicit references/dereferences. - self.bind_matched_candidate_for_guard( - block, - schedule_drops, - sub_branch.bindings.iter(), - ); + // This always schedules storage drops, so we may need to unschedule them below. + self.bind_matched_candidate_for_guard(block, sub_branch.bindings.iter()); let guard_frame = GuardFrame { locals: sub_branch .bindings @@ -2489,6 +2519,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) }); + // If this isn't the final sub-branch being lowered, we need to unschedule drops of + // bindings and temporaries created for and by the guard. As a result, the drop order + // for the arm will correspond to the binding order of the final sub-branch lowered. + if matches!(schedule_drops, ScheduleDrops::No) { + self.clear_top_scope(arm.scope); + } + let source_info = self.source_info(guard_span); let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); let guard_frame = self.guard_context.pop().unwrap(); @@ -2538,16 +2575,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause = FakeReadCause::ForGuardBinding; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } - assert_matches!( - schedule_drops, - ScheduleDrops::Yes, - "patterns with guards must schedule drops" - ); + // Only schedule drops for the last sub-branch we lower. self.bind_matched_candidate_for_arm_body( post_guard_block, - ScheduleDrops::Yes, + schedule_drops, by_value_bindings, - emit_storage_live, ); post_guard_block @@ -2559,7 +2591,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, schedule_drops, sub_branch.bindings.iter(), - emit_storage_live, ); block } @@ -2671,7 +2702,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_guard<'b>( &mut self, block: BasicBlock, - schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, ) where 'tcx: 'b, @@ -2690,12 +2720,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // a reference R: &T pointing to the location matched by // the pattern, and every occurrence of P within a guard // denotes *R. + // Drops must be scheduled to emit `StorageDead` on the guard's failure/break branches. let ref_for_guard = self.storage_live_binding( block, binding.var_id, binding.span, RefWithinGuard, - schedule_drops, + ScheduleDrops::Yes, ); match binding.binding_mode.0 { ByRef::No => { @@ -2705,13 +2736,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } ByRef::Yes(mutbl) => { - // The arm binding will be by reference, so eagerly create it now. + // The arm binding will be by reference, so eagerly create it now. Drops must + // be scheduled to emit `StorageDead` on the guard's failure/break branches. let value_for_arm = self.storage_live_binding( block, binding.var_id, binding.span, OutsideGuard, - schedule_drops, + ScheduleDrops::Yes, ); let rvalue = @@ -2730,7 +2762,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, - emit_storage_live: EmitStorageLive, ) where 'tcx: 'b, { @@ -2740,19 +2771,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = match emit_storage_live { - // Here storages are already alive, probably because this is a binding - // from let-else. - // We just need to schedule drop for the value. - EmitStorageLive::No => self.var_local_id(binding.var_id, OutsideGuard).into(), - EmitStorageLive::Yes => self.storage_live_binding( - block, - binding.var_id, - binding.span, - OutsideGuard, - schedule_drops, - ), - }; + let local = self.storage_live_binding( + block, + binding.var_id, + binding.span, + OutsideGuard, + schedule_drops, + ); if matches!(schedule_drops, ScheduleDrops::Yes) { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 589e350a03f..2c8ad95b6af 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -138,7 +138,9 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { fn visit_candidate(&mut self, candidate: &Candidate<'tcx>) { for binding in &candidate.extra_data.bindings { - self.visit_binding(binding); + if let super::SubpatternBindings::One(binding) = binding { + self.visit_binding(binding); + } } for match_pair in &candidate.match_pairs { self.visit_match_pair(match_pair); @@ -147,7 +149,9 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'tcx>) { for binding in &flat_pat.extra_data.bindings { - self.visit_binding(binding); + if let super::SubpatternBindings::One(binding) = binding { + self.visit_binding(binding); + } } for match_pair in &flat_pat.match_pairs { self.visit_match_pair(match_pair); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 890028d977d..10c532b436a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -315,6 +315,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { self.check_used(*attr_span, target, span); } + Attribute::Parsed(AttributeKind::ShouldPanic { span: attr_span, .. }) => self + .check_generic_attr(hir_id, sym::should_panic, *attr_span, target, Target::Fn), &Attribute::Parsed(AttributeKind::PassByValue(attr_span)) => { self.check_pass_by_value(attr_span, span, target) } @@ -387,9 +389,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), - [sym::should_panic, ..] => { - self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) - } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d9671c43b3d..a7f52be9e3d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -27,7 +27,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -969,8 +969,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); if ident.name != kw::Underscore && parent == self.r.graph_root { - let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) + let norm_ident = Macros20NormalizedIdent::new(ident); + if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() @@ -986,7 +986,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } use indexmap::map::Entry; - match self.r.extern_prelude.entry(ident) { + match self.r.extern_prelude.entry(norm_ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); if let Some(old_binding) = entry.binding.get() diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b85a814776a..11d93a58ae2 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -33,7 +33,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS, }; -use rustc_span::{DUMMY_SP, Ident, Span, kw}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string}; @@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { if self .r .extern_prelude - .get(&extern_crate.ident) + .get(&Macros20NormalizedIdent::new(extern_crate.ident)) .is_none_or(|entry| entry.introduced_by_item) { continue; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d18554bba1b..4da39b8a240 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,7 +30,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -320,8 +320,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if the target of the use for both bindings is the same. let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); - let from_item = - self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item); + let from_item = self + .extern_prelude + .get(&Macros20NormalizedIdent::new(ident)) + .is_none_or(|entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -530,7 +532,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.for_each_child(self, |_this, ident, _ns, binding| { let res = binding.res(); if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_ident(ident, res)); + names.push(TypoSuggestion::typo_from_ident(ident.0, res)); } }); } @@ -1100,7 +1102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.keys().filter_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); } Scope::ToolPrelude => { @@ -1246,7 +1248,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; segms.append(&mut path_segments.clone()); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; if child_accessible @@ -1319,7 +1321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let alias_import = if let NameBindingKind::Import { import, .. } = name_binding.kind @@ -1453,7 +1455,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if needs_disambiguation { crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } - crate_path.push(ast::PathSegment::from_ident(ident)); + crate_path.push(ast::PathSegment::from_ident(ident.0)); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 156df45147f..93d7b6ba547 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -489,7 +489,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define or update `binding` in `module`s glob importers. for import in glob_importers.iter() { let mut ident = key.ident; - let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -498,7 +498,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let imported_binding = self.import(binding, *import); let _ = self.try_define_local( import.parent_scope.module, - ident, + ident.0, key.ns, imported_binding, warn_ambiguity, @@ -1504,7 +1504,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) .collect::<Vec<_>>(); for (mut key, binding) in bindings { - let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -1517,7 +1517,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define_local( import.parent_scope.module, - key.ident, + key.ident.0, key.ns, imported_binding, warn_ambiguity, @@ -1550,7 +1550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { next_binding = binding; } - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + children.push(ModChild { ident: ident.0, res, vis: binding.vis, reexport_chain }); } }); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c8ca57a380f..165a0eb63f6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1472,7 +1472,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }) .collect(); if let [target] = targets.as_slice() { - return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); + return Some(TypoSuggestion::single_item_from_ident( + target.0.ident.0, + target.1, + )); } } } @@ -2479,7 +2482,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { names.extend(self.r.extern_prelude.keys().flat_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); filter_fn(res) - .then_some(TypoSuggestion::typo_from_ident(*ident, res)) + .then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); if let Some(prelude) = self.r.prelude { @@ -2639,7 +2642,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { @@ -2678,7 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { enum_module.for_each_child(self.r, |_, ident, _, name_binding| { if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; variants.push((path, def_id, kind)); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6b034c5129f..2a75070ef54 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -71,7 +71,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -531,7 +531,7 @@ impl ModuleKind { struct BindingKey { /// The identifier for the binding, always the `normalize_to_macros_2_0` version of the /// identifier. - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, /// When we add an underscore binding (with ident `_`) to some module, this field has /// a non-zero value that uniquely identifies this binding in that module. @@ -543,7 +543,7 @@ struct BindingKey { impl BindingKey { fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 } } fn new_disambiguated( @@ -552,7 +552,7 @@ impl BindingKey { disambiguator: impl FnOnce() -> u32, ) -> BindingKey { let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator } } } @@ -593,7 +593,8 @@ struct ModuleData<'ra> { globs: RefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>, + traits: + RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -659,7 +660,7 @@ impl<'ra> Module<'ra> { fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>( self, resolver: &R, - mut f: impl FnMut(&R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -671,7 +672,7 @@ impl<'ra> Module<'ra> { fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>( self, resolver: &mut R, - mut f: impl FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -1054,7 +1055,7 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, prelude: Option<Module<'ra>>, - extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'ra>>, + extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap<Vec<Ident>>, @@ -1499,7 +1500,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let name = Symbol::intern(name) && name.can_be_raw() { - Some((Ident::with_dummy_span(name), Default::default())) + Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default())) } else { None } @@ -1507,9 +1508,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); if !attr::contains_name(attrs, sym::no_core) { - extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default()); if !attr::contains_name(attrs, sym::no_std) { - extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default()); } } @@ -1879,7 +1882,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0); found_traits.push(TraitCandidate { def_id, import_ids }); } } @@ -2020,7 +2023,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope { - if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) { + if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) { return; } @@ -2179,7 +2182,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { let mut record_use = None; - let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0()); + let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); let binding = entry.and_then(|entry| match entry.binding.get() { Some(binding) if binding.is_import() => { if finalize { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4e3c0cd5bc0..ecf4f797434 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -536,11 +536,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident, ns)) + && overriding_keys.contains(&BindingKey::new(ident.0, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { - idents.push((ident, None)); + idents.push((ident.0, None)); } }); Ok(idents) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 3f72ccd9f89..d647ec28aae 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -66,7 +66,8 @@ pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; pub use symbol::{ - ByteSymbol, Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym, + ByteSymbol, Ident, MacroRulesNormalizedIdent, Macros20NormalizedIdent, STDLIB_STABLE_CRATES, + Symbol, kw, sym, }; mod analyze_source_file; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d54175548e3..36197950221 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -3,6 +3,7 @@ //! type, and vice versa. use std::hash::{Hash, Hasher}; +use std::ops::Deref; use std::{fmt, str}; use rustc_arena::DroplessArena; @@ -1512,6 +1513,7 @@ symbols! { not, notable_trait, note, + nvptx_target_feature, object_safe_for_dispatch, of, off, @@ -2562,16 +2564,17 @@ impl fmt::Display for IdentPrinter { } /// An newtype around `Ident` that calls [Ident::normalize_to_macro_rules] on -/// construction. -// FIXME(matthewj, petrochenkov) Use this more often, add a similar -// `ModernIdent` struct and use that as well. +/// construction for "local variable hygiene" comparisons. +/// +/// Use this type when you need to compare identifiers according to macro_rules hygiene. +/// This ensures compile-time safety and avoids manual normalization calls. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct MacroRulesNormalizedIdent(Ident); impl MacroRulesNormalizedIdent { #[inline] pub fn new(ident: Ident) -> Self { - Self(ident.normalize_to_macro_rules()) + MacroRulesNormalizedIdent(ident.normalize_to_macro_rules()) } } @@ -2587,6 +2590,48 @@ impl fmt::Display for MacroRulesNormalizedIdent { } } +/// An newtype around `Ident` that calls [Ident::normalize_to_macros_2_0] on +/// construction for "item hygiene" comparisons. +/// +/// Identifiers with same string value become same if they came from the same macro 2.0 macro +/// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from +/// different macro 2.0 macros. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct Macros20NormalizedIdent(pub Ident); + +impl Macros20NormalizedIdent { + #[inline] + pub fn new(ident: Ident) -> Self { + Macros20NormalizedIdent(ident.normalize_to_macros_2_0()) + } + + // dummy_span does not need to be normalized, so we can use `Ident` directly + pub fn with_dummy_span(name: Symbol) -> Self { + Macros20NormalizedIdent(Ident::with_dummy_span(name)) + } +} + +impl fmt::Debug for Macros20NormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for Macros20NormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// By impl Deref, we can access the wrapped Ident as if it were a normal Ident +/// such as `norm_ident.name` instead of `norm_ident.0.name`. +impl Deref for Macros20NormalizedIdent { + type Target = Ident; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// An interned UTF-8 string. /// /// Internally, a `Symbol` is implemented as an index, and all operations diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index aa8292c0504..a7f64085bd9 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -234,7 +234,9 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - unreachable!(); // because `<Self As PrettyPrinter>::should_print_region` returns false + // This might be reachable (via `pretty_print_dyn_existential`) even though + // `<Self As PrettyPrinter>::should_print_region` returns false. See #144994. + Ok(()) } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b2af99228fe..297d9ed84c5 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -517,6 +517,71 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-end ]; +const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("sm_20", Unstable(sym::nvptx_target_feature), &[]), + ("sm_21", Unstable(sym::nvptx_target_feature), &["sm_20"]), + ("sm_30", Unstable(sym::nvptx_target_feature), &["sm_21"]), + ("sm_32", Unstable(sym::nvptx_target_feature), &["sm_30"]), + ("sm_35", Unstable(sym::nvptx_target_feature), &["sm_32"]), + ("sm_37", Unstable(sym::nvptx_target_feature), &["sm_35"]), + ("sm_50", Unstable(sym::nvptx_target_feature), &["sm_37"]), + ("sm_52", Unstable(sym::nvptx_target_feature), &["sm_50"]), + ("sm_53", Unstable(sym::nvptx_target_feature), &["sm_52"]), + ("sm_60", Unstable(sym::nvptx_target_feature), &["sm_53"]), + ("sm_61", Unstable(sym::nvptx_target_feature), &["sm_60"]), + ("sm_62", Unstable(sym::nvptx_target_feature), &["sm_61"]), + ("sm_70", Unstable(sym::nvptx_target_feature), &["sm_62"]), + ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), + ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), + ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), + ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]), + ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]), + ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]), + ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]), + ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]), + ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("ptx32", Unstable(sym::nvptx_target_feature), &[]), + ("ptx40", Unstable(sym::nvptx_target_feature), &["ptx32"]), + ("ptx41", Unstable(sym::nvptx_target_feature), &["ptx40"]), + ("ptx42", Unstable(sym::nvptx_target_feature), &["ptx41"]), + ("ptx43", Unstable(sym::nvptx_target_feature), &["ptx42"]), + ("ptx50", Unstable(sym::nvptx_target_feature), &["ptx43"]), + ("ptx60", Unstable(sym::nvptx_target_feature), &["ptx50"]), + ("ptx61", Unstable(sym::nvptx_target_feature), &["ptx60"]), + ("ptx62", Unstable(sym::nvptx_target_feature), &["ptx61"]), + ("ptx63", Unstable(sym::nvptx_target_feature), &["ptx62"]), + ("ptx64", Unstable(sym::nvptx_target_feature), &["ptx63"]), + ("ptx65", Unstable(sym::nvptx_target_feature), &["ptx64"]), + ("ptx70", Unstable(sym::nvptx_target_feature), &["ptx65"]), + ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), + ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), + ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), + ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]), + ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]), + ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]), + ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]), + ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]), + ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]), + ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]), + ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]), + ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]), + ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]), + ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]), + ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]), + ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]), + // tidy-alphabetical-end +]; + static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", Stable, &["zaamo", "zalrsc"]), @@ -782,6 +847,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> { .chain(HEXAGON_FEATURES.iter()) .chain(POWERPC_FEATURES.iter()) .chain(MIPS_FEATURES.iter()) + .chain(NVPTX_FEATURES.iter()) .chain(RISCV_FEATURES.iter()) .chain(WASM_FEATURES.iter()) .chain(BPF_FEATURES.iter()) @@ -847,6 +913,7 @@ impl Target { "x86" | "x86_64" => X86_FEATURES, "hexagon" => HEXAGON_FEATURES, "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES, + "nvptx64" => NVPTX_FEATURES, "powerpc" | "powerpc64" => POWERPC_FEATURES, "riscv32" | "riscv64" => RISCV_FEATURES, "wasm32" | "wasm64" => WASM_FEATURES, @@ -873,7 +940,7 @@ impl Target { "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI, - "bpf" | "m68k" => &[], // no vector ABI + "nvptx64" | "bpf" | "m68k" => &[], // no vector ABI "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 38393379a78..ceb9748e7fe 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -725,7 +725,7 @@ unsafe impl Send for TypeId {} unsafe impl Sync for TypeId {} #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq for TypeId { #[inline] fn eq(&self, other: &Self) -> bool { @@ -773,7 +773,7 @@ impl TypeId { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] + #[rustc_const_stable(feature = "const_type_id", since = "CURRENT_RUSTC_VERSION")] pub const fn of<T: ?Sized + 'static>() -> TypeId { const { intrinsics::type_id::<T>() } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3c33f4b1368..d5bce6ad233 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -195,6 +195,7 @@ #![feature(hexagon_target_feature)] #![feature(loongarch_target_feature)] #![feature(mips_target_feature)] +#![feature(nvptx_target_feature)] #![feature(powerpc_target_feature)] #![feature(riscv_target_feature)] #![feature(rtm_target_feature)] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index f8344da79ad..6c7ba491971 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1936,8 +1936,8 @@ pub mod math { /// let abs_difference_x = (f32::math::abs_sub(x, 1.0) - 2.0).abs(); /// let abs_difference_y = (f32::math::abs_sub(y, 1.0) - 0.0).abs(); /// - /// assert!(abs_difference_x <= f32::EPSILON); - /// assert!(abs_difference_y <= f32::EPSILON); + /// assert!(abs_difference_x <= 1e-6); + /// assert!(abs_difference_y <= 1e-6); /// ``` /// /// _This standalone function is for testing only. @@ -1982,7 +1982,7 @@ pub mod math { /// // x^(1/3) - 2 == 0 /// let abs_difference = (f32::math::cbrt(x) - 2.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` /// /// _This standalone function is for testing only. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 10efb8aff4a..bd2f7445612 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -469,17 +469,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -560,17 +559,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -611,17 +609,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -702,17 +699,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -753,17 +749,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] /// ``` /// /// The following panics because of overflow: /// /// ``` should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -855,24 +850,22 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -924,24 +917,22 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1092,24 +1083,22 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1160,24 +1149,22 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1249,17 +1236,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] /// - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1306,17 +1292,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1422,17 +1407,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1542,17 +1526,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1612,17 +1595,16 @@ macro_rules! int_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 41a9418492a..1c2783e4769 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -538,17 +538,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -630,22 +629,20 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] /// ``` /// /// The following panic because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")] /// ``` /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -695,17 +692,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -817,22 +813,20 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".strict_sub_signed(2), 1);")] /// ``` /// /// The following panic because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_sub_signed(2);")] /// ``` /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -932,17 +926,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] /// ``` /// /// The following panics because of overflow: /// /// ``` should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1029,17 +1022,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1085,16 +1077,15 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] /// ``` /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1239,17 +1230,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1296,17 +1286,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] /// ``` /// /// The following panics because of division by zero: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1568,17 +1557,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] /// - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1625,17 +1613,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1741,17 +1728,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1867,17 +1853,16 @@ macro_rules! uint_impl { /// # Examples /// /// ``` - /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] /// ``` /// /// The following panics because of overflow: /// /// ```should_panic - /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` - #[unstable(feature = "strict_overflow_ops", issue = "118260")] + #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 26661b20c12..7489a8bb6e7 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -187,6 +187,80 @@ impl<B, C> ControlFlow<B, C> { } } + /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// `ControlFlow` was `Break` and `Err` if otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_ok)] + /// + /// use std::ops::ControlFlow; + /// + /// struct TreeNode<T> { + /// value: T, + /// left: Option<Box<TreeNode<T>>>, + /// right: Option<Box<TreeNode<T>>>, + /// } + /// + /// impl<T> TreeNode<T> { + /// fn find<'a>(&'a self, mut predicate: impl FnMut(&T) -> bool) -> Result<&'a T, ()> { + /// let mut f = |t: &'a T| -> ControlFlow<&'a T> { + /// if predicate(t) { + /// ControlFlow::Break(t) + /// } else { + /// ControlFlow::Continue(()) + /// } + /// }; + /// + /// self.traverse_inorder(&mut f).break_ok() + /// } + /// + /// fn traverse_inorder<'a, B>( + /// &'a self, + /// f: &mut impl FnMut(&'a T) -> ControlFlow<B>, + /// ) -> ControlFlow<B> { + /// if let Some(left) = &self.left { + /// left.traverse_inorder(f)?; + /// } + /// f(&self.value)?; + /// if let Some(right) = &self.right { + /// right.traverse_inorder(f)?; + /// } + /// ControlFlow::Continue(()) + /// } + /// + /// fn leaf(value: T) -> Option<Box<TreeNode<T>>> { + /// Some(Box::new(Self { + /// value, + /// left: None, + /// right: None, + /// })) + /// } + /// } + /// + /// let node = TreeNode { + /// value: 0, + /// left: TreeNode::leaf(1), + /// right: Some(Box::new(TreeNode { + /// value: -1, + /// left: TreeNode::leaf(5), + /// right: TreeNode::leaf(2), + /// })), + /// }; + /// + /// let res = node.find(|val: &i32| *val > 3); + /// assert_eq!(res, Ok(&5)); + /// ``` + #[inline] + #[unstable(feature = "control_flow_ok", issue = "140266")] + pub fn break_ok(self) -> Result<B, C> { + match self { + ControlFlow::Continue(c) => Err(c), + ControlFlow::Break(b) => Ok(b), + } + } + /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function /// to the break value in case it exists. #[inline] @@ -218,6 +292,79 @@ impl<B, C> ControlFlow<B, C> { } } + /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// `ControlFlow` was `Continue` and `Err` if otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_ok)] + /// + /// use std::ops::ControlFlow; + /// + /// struct TreeNode<T> { + /// value: T, + /// left: Option<Box<TreeNode<T>>>, + /// right: Option<Box<TreeNode<T>>>, + /// } + /// + /// impl<T> TreeNode<T> { + /// fn validate<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> Result<(), B> { + /// self.traverse_inorder(f).continue_ok() + /// } + /// + /// fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> { + /// if let Some(left) = &self.left { + /// left.traverse_inorder(f)?; + /// } + /// f(&self.value)?; + /// if let Some(right) = &self.right { + /// right.traverse_inorder(f)?; + /// } + /// ControlFlow::Continue(()) + /// } + /// + /// fn leaf(value: T) -> Option<Box<TreeNode<T>>> { + /// Some(Box::new(Self { + /// value, + /// left: None, + /// right: None, + /// })) + /// } + /// } + /// + /// let node = TreeNode { + /// value: 0, + /// left: TreeNode::leaf(1), + /// right: Some(Box::new(TreeNode { + /// value: -1, + /// left: TreeNode::leaf(5), + /// right: TreeNode::leaf(2), + /// })), + /// }; + /// + /// let res = node.validate(&mut |val| { + /// if *val < 0 { + /// return ControlFlow::Break("negative value detected"); + /// } + /// + /// if *val > 4 { + /// return ControlFlow::Break("too big value detected"); + /// } + /// + /// ControlFlow::Continue(()) + /// }); + /// assert_eq!(res, Err("too big value detected")); + /// ``` + #[inline] + #[unstable(feature = "control_flow_ok", issue = "140266")] + pub fn continue_ok(self) -> Result<C, B> { + match self { + ControlFlow::Continue(c) => Ok(c), + ControlFlow::Break(b) => Err(b), + } + } + /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function /// to the continue value in case it exists. #[inline] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0a9c0c61c95..a0c594d2d59 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -22,6 +22,7 @@ #![feature(const_ref_cell)] #![feature(const_result_trait_fn)] #![feature(const_trait_impl)] +#![feature(control_flow_ok)] #![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] diff --git a/library/coretests/tests/ops/control_flow.rs b/library/coretests/tests/ops/control_flow.rs index eacfd63a6c4..1df6599ac4a 100644 --- a/library/coretests/tests/ops/control_flow.rs +++ b/library/coretests/tests/ops/control_flow.rs @@ -16,3 +16,15 @@ fn control_flow_discriminants_match_result() { discriminant_value(&Result::<i32, i32>::Ok(3)), ); } + +#[test] +fn control_flow_break_ok() { + assert_eq!(ControlFlow::<char, i32>::Break('b').break_ok(), Ok('b')); + assert_eq!(ControlFlow::<char, i32>::Continue(3).break_ok(), Err(3)); +} + +#[test] +fn control_flow_continue_ok() { + assert_eq!(ControlFlow::<char, i32>::Break('b').continue_ok(), Err('b')); + assert_eq!(ControlFlow::<char, i32>::Continue(3).continue_ok(), Ok(3)); +} diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 5dee68ad909..d16028c0543 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -582,8 +582,8 @@ impl f32 { /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); /// - /// assert!(abs_difference_x <= f32::EPSILON); - /// assert!(abs_difference_y <= f32::EPSILON); + /// assert!(abs_difference_x <= 1e-6); + /// assert!(abs_difference_y <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -621,7 +621,7 @@ impl f32 { /// // x^(1/3) - 2 == 0 /// let abs_difference = (x.cbrt() - 2.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -652,7 +652,7 @@ impl f32 { /// // sqrt(x^2 + y^2) /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); /// - /// assert!(abs_difference <= 1e-6); + /// assert!(abs_difference <= 1e-5); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -725,7 +725,7 @@ impl f32 { /// let x = std::f32::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -749,12 +749,12 @@ impl f32 { /// # Examples /// /// ``` - /// let f = std::f32::consts::FRAC_PI_2; + /// let f = std::f32::consts::FRAC_PI_4; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - std::f32::consts::FRAC_PI_2).abs(); + /// let abs_difference = (f.sin().asin() - f).abs(); /// - /// assert!(abs_difference <= 1e-3); + /// assert!(abs_difference <= 1e-6); /// ``` #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] @@ -813,7 +813,7 @@ impl f32 { /// // atan(tan(1)) /// let abs_difference = (f.tan().atan() - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[doc(alias = "arctan")] #[rustc_allow_incoherent_impl] @@ -854,8 +854,8 @@ impl f32 { /// let abs_difference_1 = (y1.atan2(x1) - (-std::f32::consts::FRAC_PI_4)).abs(); /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f32::consts::FRAC_PI_4)).abs(); /// - /// assert!(abs_difference_1 <= f32::EPSILON); - /// assert!(abs_difference_2 <= f32::EPSILON); + /// assert!(abs_difference_1 <= 1e-5); + /// assert!(abs_difference_2 <= 1e-5); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -884,8 +884,8 @@ impl f32 { /// let abs_difference_0 = (f.0 - x.sin()).abs(); /// let abs_difference_1 = (f.1 - x.cos()).abs(); /// - /// assert!(abs_difference_0 <= 1e-6); - /// assert!(abs_difference_1 <= 1e-6); + /// assert!(abs_difference_0 <= 1e-4); + /// assert!(abs_difference_1 <= 1e-4); /// ``` #[doc(alias = "sincos")] #[rustc_allow_incoherent_impl] @@ -982,7 +982,7 @@ impl f32 { /// let g = ((e * e) - 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -1012,7 +1012,7 @@ impl f32 { /// let abs_difference = (f - g).abs(); /// /// // Same result - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -1042,7 +1042,7 @@ impl f32 { /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); /// let abs_difference = (f - g).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -1067,7 +1067,7 @@ impl f32 { /// /// let abs_difference = (f - x).abs(); /// - /// assert!(abs_difference <= 1e-7); + /// assert!(abs_difference <= 1e-6); /// ``` #[doc(alias = "arcsinh")] #[rustc_allow_incoherent_impl] @@ -1125,7 +1125,7 @@ impl f32 { /// /// let abs_difference = (f - e).abs(); /// - /// assert!(abs_difference <= 1e-5); + /// assert!(abs_difference <= 1e-4); /// ``` #[doc(alias = "arctanh")] #[rustc_allow_incoherent_impl] @@ -1153,7 +1153,7 @@ impl f32 { /// /// let abs_difference = (x.gamma() - 24.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-4); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -1248,7 +1248,7 @@ impl f32 { /// let one = x.erf() + x.erfc(); /// let abs_difference = (one - 1.0).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-6); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 3ec80f68bdb..91e8f161c51 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -749,12 +749,12 @@ impl f64 { /// # Examples /// /// ``` - /// let f = std::f64::consts::FRAC_PI_2; + /// let f = std::f64::consts::FRAC_PI_4; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs(); + /// let abs_difference = (f.sin().asin() - f).abs(); /// - /// assert!(abs_difference < 1e-7); + /// assert!(abs_difference < 1e-14); /// ``` #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] @@ -1153,7 +1153,7 @@ impl f64 { /// /// let abs_difference = (x.gamma() - 24.0).abs(); /// - /// assert!(abs_difference <= f64::EPSILON); + /// assert!(abs_difference <= 1e-10); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] @@ -1248,7 +1248,7 @@ impl f64 { /// let one = x.erf() + x.erfc(); /// let abs_difference = (one - 1.0).abs(); /// - /// assert!(abs_difference <= f64::EPSILON); + /// assert!(abs_difference <= 1e-10); /// ``` #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index 38c906c1d87..bea9e8282a6 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -79,7 +79,7 @@ fn test_log() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(10.0f32.log(10.0), 1.0, APPROX_DELTA); assert_approx_eq!(2.3f32.log(3.5), 0.664858); assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA); assert!(1.0f32.log(1.0).is_nan()); @@ -140,10 +140,10 @@ fn test_asinh() { assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); + assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32, APPROX_DELTA); // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh()); + assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh(), APPROX_DELTA); // mul needed for approximate comparison to be meaningful assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32); } @@ -196,10 +196,10 @@ fn test_gamma() { assert_approx_eq!(1.0f32.gamma(), 1.0f32); assert_approx_eq!(2.0f32.gamma(), 1.0f32); assert_approx_eq!(3.0f32.gamma(), 2.0f32); - assert_approx_eq!(4.0f32.gamma(), 6.0f32); - assert_approx_eq!(5.0f32.gamma(), 24.0f32); + assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA); + assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA); assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA); assert_eq!(0.0f32.gamma(), f32::INFINITY); assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); assert!((-1.0f32).gamma().is_nan()); @@ -218,7 +218,7 @@ fn test_ln_gamma() { assert_eq!(2.0f32.ln_gamma().1, 1); assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln()); assert_eq!(3.0f32.ln_gamma().1, 1); - assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); + assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), APPROX_DELTA); assert_eq!((-0.5f32).ln_gamma().1, -1); } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 7039f31cdde..e1ee0773107 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2384,15 +2384,19 @@ pub fn run_cargo( let mut deps = Vec::new(); let mut toplevel = Vec::new(); let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { - let (filenames, crate_types) = match msg { + let (filenames_vec, crate_types) = match msg { CargoMessage::CompilerArtifact { filenames, target: CargoTarget { crate_types }, .. - } => (filenames, crate_types), + } => { + let mut f: Vec<String> = filenames.into_iter().map(|s| s.into_owned()).collect(); + f.sort(); // Sort the filenames + (f, crate_types) + } _ => return, }; - for filename in filenames { + for filename in filenames_vec { // Skip files like executables let mut keep = false; if filename.ends_with(".lib") diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0465a071159..cbbfb6b6a11 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -174,36 +174,12 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> { found } -fn make_win_dist( - rust_root: &Path, - plat_root: &Path, - target: TargetSelection, - builder: &Builder<'_>, -) { +fn make_win_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) { if builder.config.dry_run() { return; } - //Ask gcc where it keeps its stuff - let mut cmd = command(builder.cc(target)); - cmd.arg("-print-search-dirs"); - let gcc_out = cmd.run_capture_stdout(builder).stdout(); - - let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); - let mut lib_path = Vec::new(); - - for line in gcc_out.lines() { - let idx = line.find(':').unwrap(); - let key = &line[..idx]; - let trim_chars: &[_] = &[' ', '=']; - let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars)); - - if key == "programs" { - bin_path.extend(value); - } else if key == "libraries" { - lib_path.extend(value); - } - } + let (bin_path, lib_path) = get_cc_search_dirs(target, builder); let compiler = if target == "i686-pc-windows-gnu" { "i686-w64-mingw32-gcc.exe" @@ -213,12 +189,6 @@ fn make_win_dist( "gcc.exe" }; let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"]; - let mut rustc_dlls = vec!["libwinpthread-1.dll"]; - if target.starts_with("i686-") { - rustc_dlls.push("libgcc_s_dw2-1.dll"); - } else { - rustc_dlls.push("libgcc_s_seh-1.dll"); - } // Libraries necessary to link the windows-gnu toolchains. // System libraries will be preferred if they are available (see #67429). @@ -274,25 +244,8 @@ fn make_win_dist( //Find mingw artifacts we want to bundle let target_tools = find_files(&target_tools, &bin_path); - let rustc_dlls = find_files(&rustc_dlls, &bin_path); let target_libs = find_files(&target_libs, &lib_path); - // Copy runtime dlls next to rustc.exe - let rust_bin_dir = rust_root.join("bin/"); - fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed"); - for src in &rustc_dlls { - builder.copy_link_to_folder(src, &rust_bin_dir); - } - - if builder.config.lld_enabled { - // rust-lld.exe also needs runtime dlls - let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin"); - fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed"); - for src in &rustc_dlls { - builder.copy_link_to_folder(src, &rust_target_bin_dir); - } - } - //Copy platform tools to platform-specific bin directory let plat_target_bin_self_contained_dir = plat_root.join("lib/rustlib").join(target).join("bin/self-contained"); @@ -320,6 +273,82 @@ fn make_win_dist( } } +fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder<'_>) { + if builder.config.dry_run() { + return; + } + + let (bin_path, libs_path) = get_cc_search_dirs(target, builder); + + let mut rustc_dlls = vec![]; + // windows-gnu and windows-gnullvm require different runtime libs + if target.ends_with("windows-gnu") { + rustc_dlls.push("libwinpthread-1.dll"); + if target.starts_with("i686-") { + rustc_dlls.push("libgcc_s_dw2-1.dll"); + } else { + rustc_dlls.push("libgcc_s_seh-1.dll"); + } + } else if target.ends_with("windows-gnullvm") { + rustc_dlls.push("libunwind.dll"); + } else { + panic!("Vendoring of runtime DLLs for `{target}` is not supported`"); + } + // FIXME(#144656): Remove this whole `let ...` + let bin_path = if target.ends_with("windows-gnullvm") && builder.host_target != target { + bin_path + .into_iter() + .chain(libs_path.iter().map(|path| path.with_file_name("bin"))) + .collect() + } else { + bin_path + }; + let rustc_dlls = find_files(&rustc_dlls, &bin_path); + + // Copy runtime dlls next to rustc.exe + let rust_bin_dir = rust_root.join("bin/"); + fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_bin_dir); + } + + if builder.config.lld_enabled { + // rust-lld.exe also needs runtime dlls + let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin"); + fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_target_bin_dir); + } + } +} + +fn get_cc_search_dirs( + target: TargetSelection, + builder: &Builder<'_>, +) -> (Vec<PathBuf>, Vec<PathBuf>) { + //Ask gcc where it keeps its stuff + let mut cmd = command(builder.cc(target)); + cmd.arg("-print-search-dirs"); + let gcc_out = cmd.run_capture_stdout(builder).stdout(); + + let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); + let mut lib_path = Vec::new(); + + for line in gcc_out.lines() { + let idx = line.find(':').unwrap(); + let key = &line[..idx]; + let trim_chars: &[_] = &[' ', '=']; + let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars)); + + if key == "programs" { + bin_path.extend(value); + } else if key == "libraries" { + lib_path.extend(value); + } + } + (bin_path, lib_path) +} + #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Mingw { pub host: TargetSelection, @@ -350,11 +379,7 @@ impl Step for Mingw { let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple); tarball.set_product_name("Rust MinGW"); - // The first argument is a "temporary directory" which is just - // thrown away (this contains the runtime DLLs included in the rustc package - // above) and the second argument is where to place all the MinGW components - // (which is what we want). - make_win_dist(&tmpdir(builder), tarball.image_dir(), host, builder); + make_win_dist(tarball.image_dir(), host, builder); Some(tarball.generate()) } @@ -394,17 +419,14 @@ impl Step for Rustc { prepare_image(builder, compiler, tarball.image_dir()); // On MinGW we've got a few runtime DLL dependencies that we need to - // include. The first argument to this script is where to put these DLLs - // (the image we're creating), and the second argument is a junk directory - // to ignore all other MinGW stuff the script creates. - // + // include. // On 32-bit MinGW we're always including a DLL which needs some extra // licenses to distribute. On 64-bit MinGW we don't actually distribute // anything requiring us to distribute a license, but it's likely the // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. - if host.ends_with("pc-windows-gnu") && builder.config.dist_include_mingw_linker { - make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder); + if host.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker { + runtime_dll_dist(tarball.image_dir(), host, builder); tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc"); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index b2056f5cf37..721ba6ca459 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1528,8 +1528,12 @@ impl Step for Libunwind { // FIXME: https://github.com/alexcrichton/cc-rs/issues/545#issuecomment-679242845 let mut count = 0; - for entry in fs::read_dir(&out_dir).unwrap() { - let file = entry.unwrap().path().canonicalize().unwrap(); + let mut files = fs::read_dir(&out_dir) + .unwrap() + .map(|entry| entry.unwrap().path().canonicalize().unwrap()) + .collect::<Vec<_>>(); + files.sort(); + for file in files { if file.is_file() && file.extension() == Some(OsStr::new("o")) { // Object file name without the hash prefix is "Unwind-EHABI", "Unwind-seh" or "libunwind". let base_name = unhashed_basename(&file); diff --git a/src/doc/book b/src/doc/book -Subproject b2d1a0821e12a676b496d61891b8e3d374a8e83 +Subproject 3e9dc46aa563ca0c53ec826c41b05f10c591592 diff --git a/src/doc/reference b/src/doc/reference -Subproject 1f45bd41fa6c17b7c048ed6bfe5f168c4311206 +Subproject 1be151c051a082b542548c62cafbcb055fa8944 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject e386be5f44af711854207c11fdd61bb576270b0 +Subproject bd1279cdc9865bfff605e741fb76a0b2f07314a diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index e9f1626f1fd..6ec700b9b4d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -383b9c447b61641e1f1a3850253944a897a60827 +6bcdcc73bd11568fd85f5a38b58e1eda054ad1cd diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index 1e792de3c8c..b376e962ff6 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -8,7 +8,7 @@ First you need to clone and configure the Rust repository: ```bash git clone git@github.com:rust-lang/rust cd rust -./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-offload --enable-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs +./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-llvm-offload --enable-llvm-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs ``` Afterwards you can build rustc using: diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index 12b76828b5c..378d8c4453f 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -321,6 +321,10 @@ the name `'tcx`, which means that something is tied to the lifetime of the [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html +For more information about queries in the compiler, see [the queries chapter][queries]. + +[queries]: ./query.md + ### `ty::Ty` Types are really important in Rust, and they form the core of a lot of compiler diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index f6e313062cd..317b65f98cd 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -342,7 +342,6 @@ coordinate running tests (see [src/bootstrap/src/core/build_steps/test.rs]). > **TODO** > > - Is there any support for using an iOS emulator? -> - It's also unclear to me how the wasm or asm.js tests are run. [armhf-gnu]: https://github.com/rust-lang/rust/tree/master/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile [QEMU]: https://www.qemu.org/ @@ -350,6 +349,28 @@ coordinate running tests (see [src/bootstrap/src/core/build_steps/test.rs]). [remote-test-server]: https://github.com/rust-lang/rust/tree/master/src/tools/remote-test-server [src/bootstrap/src/core/build_steps/test.rs]: https://github.com/rust-lang/rust/blob/master/src/bootstrap/src/core/build_steps/test.rs +## Testing tests on wasi (wasm32-wasip1) + +Some tests are specific to wasm targets. +To run theste tests, you have to pass `--target wasm32-wasip1` to `x test`. +Additionally, you need the wasi sdk. +Follow the install instructions from the [wasi sdk repository] to get a sysroot on your computer. +On the [wasm32-wasip1 target support page] a minimum version is specified that your sdk must be able to build. +Some cmake commands that take a while and give a lot of very concerning c++ warnings... +Then, in `bootstrap.toml`, point to the sysroot like so: + +``` +[target.wasm32-wasip1] +wasi-root = "<wasi-sdk location>/build/sysroot/install/share/wasi-sysroot" +``` + +In my case I git-cloned it next to my rust folder, so it was `../wasi-sdk/build/....` +Now, tests should just run, you don't have to set up anything else. + +[wasi sdk repository]: https://github.com/WebAssembly/wasi-sdk +[wasm32-wasip1 target support page]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support/wasm32-wasip1.md#building-the-target. + + ## Running rustc_codegen_gcc tests First thing to know is that it only supports linux x86_64 at the moment. We will diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 106ec562bfc..36598982481 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -10,6 +10,46 @@ platform. [@RDambrosio016](https://github.com/RDambrosio016) [@kjetilkjeka](https://github.com/kjetilkjeka) +## Requirements + +This target is `no_std` and will typically be built with crate-type `cdylib` and `-C linker-flavor=llbc`, which generates PTX. +The necessary components for this workflow are: + +- `rustup toolchain add nightly` +- `rustup component add llvm-tools --toolchain nightly` +- `rustup component add llvm-bitcode-linker --toolchain nightly` + +There are two options for using the core library: + +- `rustup component add rust-src --toolchain nightly` and build using `-Z build-std=core`. +- `rustup target add nvptx64-nvidia-cuda --toolchain nightly` + +### Target and features + +It is generally necessary to specify the target, such as `-C target-cpu=sm_89`, because the default is very old. This implies two target features: `sm_89` and `ptx78` (and all preceding features within `sm_*` and `ptx*`). Rust will default to using the oldest PTX version that supports the target processor (see [this table](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#release-notes-ptx-release-history)), which maximizes driver compatibility. +One can use `-C target-feature=+ptx80` to choose a later PTX version without changing the target (the default in this case, `ptx78`, requires CUDA driver version 11.8, while `ptx80` would require driver version 12.0). +Later PTX versions may allow more efficient code generation. + +Although Rust follows LLVM in representing `ptx*` and `sm_*` as target features, they should be thought of as having crate granularity, set via (either via `-Ctarget-cpu` and optionally `-Ctarget-feature`). +While the compiler accepts `#[target_feature(enable = "ptx80", enable = "sm_89")]`, it is not supported, may not behave as intended, and may become erroneous in the future. + +## Building Rust kernels + +A `no_std` crate containing one or more functions with `extern "ptx-kernel"` can be compiled to PTX using a command like the following. + +```console +$ RUSTFLAGS='-Ctarget-cpu=sm_89' cargo +nightly rustc --target=nvptx64-nvidia-cuda -Zbuild-std=core --crate-type=cdylib -- -Clinker-flavor=llbc -Zunstable-options +``` + +Intrinsics in `core::arch::nvptx` may use `#[cfg(target_feature = "...")]`, thus it's necessary to use `-Zbuild-std=core` with appropriate `RUSTFLAGS`. The following components are needed for this workflow: + +```console +$ rustup component add rust-src --toolchain nightly +$ rustup component add llvm-tools --toolchain nightly +$ rustup component add llvm-bitcode-linker --toolchain nightly +``` + + <!-- FIXME: fill this out ## Requirements diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index b5e81460773..e0e09ac6835 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -3,20 +3,16 @@ mod atomic; mod simd; -use std::ops::Neg; - use rand::Rng; use rustc_abi::Size; -use rustc_apfloat::ieee::{IeeeFloat, Semantics}; use rustc_apfloat::{self, Float, Round}; use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy, ScalarInt}; +use rustc_middle::ty::{self, FloatTy}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; use self::helpers::{ToHost, ToSoft}; use self::simd::EvalContextExt as _; -use crate::math::{IeeeExt, apply_random_float_error_ulp}; use crate::*; /// Check that the number of args is what we expect. @@ -209,7 +205,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; - let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { + let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let host = f.to_host(); @@ -227,7 +223,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = apply_random_float_error_ulp( + let res = math::apply_random_float_error_ulp( this, res, 2, // log2(4) @@ -235,7 +231,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Clamp the result to the guaranteed range of this function according to the C standard, // if any. - clamp_float_value(intrinsic_name, res) + math::clamp_float_value(intrinsic_name, res) }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; @@ -253,7 +249,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; - let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { + let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let host = f.to_host(); @@ -271,7 +267,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = apply_random_float_error_ulp( + let res = math::apply_random_float_error_ulp( this, res, 2, // log2(4) @@ -279,7 +275,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Clamp the result to the guaranteed range of this function according to the C standard, // if any. - clamp_float_value(intrinsic_name, res) + math::clamp_float_value(intrinsic_name, res) }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; @@ -330,16 +326,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; - let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); + let res = + math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) - }); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } @@ -348,16 +345,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; - let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); + let res = + math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) - }); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } @@ -367,13 +365,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f = this.read_scalar(f)?.to_f32()?; let i = this.read_scalar(i)?.to_i32()?; - let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| { + let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( + math::apply_random_float_error_ulp( this, res, 2, // log2(4) ) }); @@ -385,13 +383,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f = this.read_scalar(f)?.to_f64()?; let i = this.read_scalar(i)?.to_i32()?; - let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| { + let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( + math::apply_random_float_error_ulp( this, res, 2, // log2(4) ) }); @@ -448,7 +446,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Apply a relative error of 4ULP to simulate non-deterministic precision loss // due to optimizations. - let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?; + let res = math::apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?; this.write_immediate(*res, dest)?; } @@ -485,133 +483,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } } - -/// Applies a random ULP floating point error to `val` and returns the new value. -/// So if you want an X ULP error, `ulp_exponent` should be log2(X). -/// -/// Will fail if `val` is not a floating point number. -fn apply_random_float_error_to_imm<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - val: ImmTy<'tcx>, - ulp_exponent: u32, -) -> InterpResult<'tcx, ImmTy<'tcx>> { - let scalar = val.to_scalar_int()?; - let res: ScalarInt = match val.layout.ty.kind() { - ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), - ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), - ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), - ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), - _ => bug!("intrinsic called with non-float input type"), - }; - - interp_ok(ImmTy::from_scalar_int(res, val.layout)) -} - -/// For the intrinsics: -/// - sinf32, sinf64 -/// - cosf32, cosf64 -/// - expf32, expf64, exp2f32, exp2f64 -/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64 -/// - powf32, powf64 -/// -/// # Return -/// -/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard -/// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error -/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying -/// implementation. Returns `None` if no specific value is guaranteed. -/// -/// # Note -/// -/// For `powf*` operations of the form: -/// -/// - `(SNaN)^(±0)` -/// - `1^(SNaN)` -/// -/// The result is implementation-defined: -/// - musl returns for both `1.0` -/// - glibc returns for both `NaN` -/// -/// This discrepancy exists because SNaN handling is not consistently defined across platforms, -/// and the C standard leaves behavior for SNaNs unspecified. -/// -/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically. -fn fixed_float_value<S: Semantics>( - ecx: &mut MiriInterpCx<'_>, - intrinsic_name: &str, - args: &[IeeeFloat<S>], -) -> Option<IeeeFloat<S>> { - let one = IeeeFloat::<S>::one(); - Some(match (intrinsic_name, args) { - // cos(+- 0) = 1 - ("cosf32" | "cosf64", [input]) if input.is_zero() => one, - - // e^0 = 1 - ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one, - - // (-1)^(±INF) = 1 - ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one, - - // 1^y = 1 for any y, even a NaN - ("powf32" | "powf64", [base, exp]) if *base == one => { - let rng = ecx.machine.rng.get_mut(); - // SNaN exponents get special treatment: they might return 1, or a NaN. - let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random(); - // Handle both the musl and glibc cases non-deterministically. - if return_nan { ecx.generate_nan(args) } else { one } - } - - // x^(±0) = 1 for any x, even a NaN - ("powf32" | "powf64", [base, exp]) if exp.is_zero() => { - let rng = ecx.machine.rng.get_mut(); - // SNaN bases get special treatment: they might return 1, or a NaN. - let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random(); - // Handle both the musl and glibc cases non-deterministically. - if return_nan { ecx.generate_nan(args) } else { one } - } - - // There are a lot of cases for fixed outputs according to the C Standard, but these are - // mainly INF or zero which are not affected by the applied error. - _ => return None, - }) -} - -/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the -/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`. -fn fixed_powi_float_value<S: Semantics>( - ecx: &mut MiriInterpCx<'_>, - base: IeeeFloat<S>, - exp: i32, -) -> Option<IeeeFloat<S>> { - Some(match exp { - 0 => { - let one = IeeeFloat::<S>::one(); - let rng = ecx.machine.rng.get_mut(); - let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling(); - // For SNaN treatment, we are consistent with `powf`above. - // (We wouldn't have two, unlike powf all implementations seem to agree for powi, - // but for now we are maximally conservative.) - if return_nan { ecx.generate_nan(&[base]) } else { one } - } - - _ => return None, - }) -} - -/// Given an floating-point operation and a floating-point value, clamps the result to the output -/// range of the given operation. -fn clamp_float_value<S: Semantics>(intrinsic_name: &str, val: IeeeFloat<S>) -> IeeeFloat<S> { - match intrinsic_name { - // sin and cos: [-1, 1] - "sinf32" | "cosf32" | "sinf64" | "cosf64" => - val.clamp(IeeeFloat::<S>::one().neg(), IeeeFloat::<S>::one()), - // exp: [0, +INF] - "expf32" | "exp2f32" | "expf64" | "exp2f64" => - IeeeFloat::<S>::maximum(val, IeeeFloat::<S>::ZERO), - _ => val, - } -} diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2b92c25a424..9272cd29788 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![feature(abort_unwind)] #![feature(cfg_select)] #![feature(rustc_private)] @@ -11,13 +12,14 @@ #![feature(variant_count)] #![feature(yeet_expr)] #![feature(nonzero_ops)] -#![feature(strict_overflow_ops)] #![feature(pointer_is_aligned_to)] #![feature(ptr_metadata)] #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] +#![feature(f16)] +#![feature(f128)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index e9e5a1070c9..3eee6b82e8c 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -1,6 +1,9 @@ +use std::ops::Neg; +use std::{f16, f32, f64, f128}; + use rand::Rng as _; use rustc_apfloat::Float as _; -use rustc_apfloat::ieee::IeeeFloat; +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, Semantics, SingleS}; use rustc_middle::ty::{self, FloatTy, ScalarInt}; use crate::*; @@ -50,29 +53,236 @@ pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>( apply_random_float_error(ecx, val, err_scale) } -/// Applies a random 16ULP floating point error to `val` and returns the new value. +/// Applies a random ULP floating point error to `val` and returns the new value. +/// So if you want an X ULP error, `ulp_exponent` should be log2(X). +/// /// Will fail if `val` is not a floating point number. pub(crate) fn apply_random_float_error_to_imm<'tcx>( ecx: &mut MiriInterpCx<'tcx>, val: ImmTy<'tcx>, ulp_exponent: u32, ) -> InterpResult<'tcx, ImmTy<'tcx>> { + let this = ecx.eval_context_mut(); let scalar = val.to_scalar_int()?; let res: ScalarInt = match val.layout.ty.kind() { ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), + apply_random_float_error_ulp(this, scalar.to_f16(), ulp_exponent).into(), ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), + apply_random_float_error_ulp(this, scalar.to_f32(), ulp_exponent).into(), ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), + apply_random_float_error_ulp(this, scalar.to_f64(), ulp_exponent).into(), ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), + apply_random_float_error_ulp(this, scalar.to_f128(), ulp_exponent).into(), _ => bug!("intrinsic called with non-float input type"), }; interp_ok(ImmTy::from_scalar_int(res, val.layout)) } +/// Given a floating-point operation and a floating-point value, clamps the result to the output +/// range of the given operation according to the C standard, if any. +pub(crate) fn clamp_float_value<S: Semantics>( + intrinsic_name: &str, + val: IeeeFloat<S>, +) -> IeeeFloat<S> +where + IeeeFloat<S>: IeeeExt, +{ + let zero = IeeeFloat::<S>::ZERO; + let one = IeeeFloat::<S>::one(); + let two = IeeeFloat::<S>::two(); + let pi = IeeeFloat::<S>::pi(); + let pi_over_2 = (pi / two).value; + + match intrinsic_name { + // sin, cos, tanh: [-1, 1] + #[rustfmt::skip] + | "sinf32" + | "sinf64" + | "cosf32" + | "cosf64" + | "tanhf" + | "tanh" + => val.clamp(one.neg(), one), + + // exp: [0, +INF) + "expf32" | "exp2f32" | "expf64" | "exp2f64" => val.maximum(zero), + + // cosh: [1, +INF) + "coshf" | "cosh" => val.maximum(one), + + // acos: [0, π] + "acosf" | "acos" => val.clamp(zero, pi), + + // asin: [-π, +π] + "asinf" | "asin" => val.clamp(pi.neg(), pi), + + // atan: (-π/2, +π/2) + "atanf" | "atan" => val.clamp(pi_over_2.neg(), pi_over_2), + + // erfc: (-1, 1) + "erff" | "erf" => val.clamp(one.neg(), one), + + // erfc: (0, 2) + "erfcf" | "erfc" => val.clamp(zero, two), + + // atan2(y, x): arctan(y/x) in [−π, +π] + "atan2f" | "atan2" => val.clamp(pi.neg(), pi), + + _ => val, + } +} + +/// For the intrinsics: +/// - sinf32, sinf64, sinhf, sinh +/// - cosf32, cosf64, coshf, cosh +/// - tanhf, tanh, atanf, atan, atan2f, atan2 +/// - expf32, expf64, exp2f32, exp2f64 +/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64 +/// - powf32, powf64 +/// - erff, erf, erfcf, erfc +/// - hypotf, hypot +/// +/// # Return +/// +/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard +/// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error +/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying +/// implementation. Returns `None` if no specific value is guaranteed. +/// +/// # Note +/// +/// For `powf*` operations of the form: +/// +/// - `(SNaN)^(±0)` +/// - `1^(SNaN)` +/// +/// The result is implementation-defined: +/// - musl returns for both `1.0` +/// - glibc returns for both `NaN` +/// +/// This discrepancy exists because SNaN handling is not consistently defined across platforms, +/// and the C standard leaves behavior for SNaNs unspecified. +/// +/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically. +pub(crate) fn fixed_float_value<S: Semantics>( + ecx: &mut MiriInterpCx<'_>, + intrinsic_name: &str, + args: &[IeeeFloat<S>], +) -> Option<IeeeFloat<S>> +where + IeeeFloat<S>: IeeeExt, +{ + let this = ecx.eval_context_mut(); + let one = IeeeFloat::<S>::one(); + let two = IeeeFloat::<S>::two(); + let three = IeeeFloat::<S>::three(); + let pi = IeeeFloat::<S>::pi(); + let pi_over_2 = (pi / two).value; + let pi_over_4 = (pi_over_2 / two).value; + + Some(match (intrinsic_name, args) { + // cos(±0) and cosh(±0)= 1 + ("cosf32" | "cosf64" | "coshf" | "cosh", [input]) if input.is_zero() => one, + + // e^0 = 1 + ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one, + + // tanh(±INF) = ±1 + ("tanhf" | "tanh", [input]) if input.is_infinite() => one.copy_sign(*input), + + // atan(±INF) = ±π/2 + ("atanf" | "atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input), + + // erf(±INF) = ±1 + ("erff" | "erf", [input]) if input.is_infinite() => one.copy_sign(*input), + + // erfc(-INF) = 2 + ("erfcf" | "erfc", [input]) if input.is_neg_infinity() => (one + one).value, + + // hypot(x, ±0) = abs(x), if x is not a NaN. + ("_hypotf" | "hypotf" | "_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => + x.abs(), + + // atan2(±0,−0) = ±π. + // atan2(±0, y) = ±π for y < 0. + // Must check for non NaN because `y.is_negative()` also applies to NaN. + ("atan2f" | "atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => + pi.copy_sign(*x), + + // atan2(±x,−∞) = ±π for finite x > 0. + ("atan2f" | "atan2", [x, y]) + if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() => + pi.copy_sign(*x), + + // atan2(x, ±0) = −π/2 for x < 0. + // atan2(x, ±0) = π/2 for x > 0. + ("atan2f" | "atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x), + + //atan2(±∞, −∞) = ±3π/4 + ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() => + (pi_over_4 * three).value.copy_sign(*x), + + //atan2(±∞, +∞) = ±π/4 + ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => + pi_over_4.copy_sign(*x), + + // atan2(±∞, y) returns ±π/2 for finite y. + ("atan2f" | "atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) => + pi_over_2.copy_sign(*x), + + // (-1)^(±INF) = 1 + ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one, + + // 1^y = 1 for any y, even a NaN + ("powf32" | "powf64", [base, exp]) if *base == one => { + let rng = this.machine.rng.get_mut(); + // SNaN exponents get special treatment: they might return 1, or a NaN. + let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random(); + // Handle both the musl and glibc cases non-deterministically. + if return_nan { this.generate_nan(args) } else { one } + } + + // x^(±0) = 1 for any x, even a NaN + ("powf32" | "powf64", [base, exp]) if exp.is_zero() => { + let rng = this.machine.rng.get_mut(); + // SNaN bases get special treatment: they might return 1, or a NaN. + let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random(); + // Handle both the musl and glibc cases non-deterministically. + if return_nan { this.generate_nan(args) } else { one } + } + + // There are a lot of cases for fixed outputs according to the C Standard, but these are + // mainly INF or zero which are not affected by the applied error. + _ => return None, + }) +} + +/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the +/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`. +pub(crate) fn fixed_powi_value<S: Semantics>( + ecx: &mut MiriInterpCx<'_>, + base: IeeeFloat<S>, + exp: i32, +) -> Option<IeeeFloat<S>> +where + IeeeFloat<S>: IeeeExt, +{ + match exp { + 0 => { + let one = IeeeFloat::<S>::one(); + let rng = ecx.machine.rng.get_mut(); + let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling(); + // For SNaN treatment, we are consistent with `powf`above. + // (We wouldn't have two, unlike powf all implementations seem to agree for powi, + // but for now we are maximally conservative.) + Some(if return_nan { ecx.generate_nan(&[base]) } else { one }) + } + + _ => return None, + } +} + pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> { match x.category() { // preserve zero sign @@ -155,19 +365,49 @@ pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFl } } -/// Extend functionality of rustc_apfloat softfloats +/// Extend functionality of `rustc_apfloat` softfloats for IEEE float types. pub trait IeeeExt: rustc_apfloat::Float { + // Some values we use: + #[inline] fn one() -> Self { Self::from_u128(1).value } #[inline] + fn two() -> Self { + Self::from_u128(2).value + } + + #[inline] + fn three() -> Self { + Self::from_u128(3).value + } + + fn pi() -> Self; + + #[inline] fn clamp(self, min: Self, max: Self) -> Self { self.maximum(min).minimum(max) } } -impl<S: rustc_apfloat::ieee::Semantics> IeeeExt for IeeeFloat<S> {} + +macro_rules! impl_ieee_pi { + ($float_ty:ident, $semantic:ty) => { + impl IeeeExt for IeeeFloat<$semantic> { + #[inline] + fn pi() -> Self { + // We take the value from the standard library as the most reasonable source for an exact π here. + Self::from_bits($float_ty::consts::PI.to_bits() as _) + } + } + }; +} + +impl_ieee_pi!(f16, HalfS); +impl_ieee_pi!(f32, SingleS); +impl_ieee_pi!(f64, DoubleS); +impl_ieee_pi!(f128, QuadS); #[cfg(test)] mod tests { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 21545b68029..bf4db2de2d7 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -17,6 +17,7 @@ use rustc_target::callconv::FnAbi; use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; +use crate::helpers::EvalContextExt as _; use crate::*; /// Type of dynamic symbols (for `dlsym` et al) @@ -779,33 +780,38 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { => { let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f32()?; - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let f_host = f.to_host(); - let res = match link_name.as_str() { - "cbrtf" => f_host.cbrt(), - "coshf" => f_host.cosh(), - "sinhf" => f_host.sinh(), - "tanf" => f_host.tan(), - "tanhf" => f_host.tanh(), - "acosf" => f_host.acos(), - "asinf" => f_host.asin(), - "atanf" => f_host.atan(), - "log1pf" => f_host.ln_1p(), - "expm1f" => f_host.exp_m1(), - "tgammaf" => f_host.gamma(), - "erff" => f_host.erf(), - "erfcf" => f_host.erfc(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp( - // this, - // res, - // 4, // log2(16) - // ); + + let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let f_host = f.to_host(); + let res = match link_name.as_str() { + "cbrtf" => f_host.cbrt(), + "coshf" => f_host.cosh(), + "sinhf" => f_host.sinh(), + "tanf" => f_host.tan(), + "tanhf" => f_host.tanh(), + "acosf" => f_host.acos(), + "asinf" => f_host.asin(), + "atanf" => f_host.atan(), + "log1pf" => f_host.ln_1p(), + "expm1f" => f_host.exp_m1(), + "tgammaf" => f_host.gamma(), + "erff" => f_host.erf(), + "erfcf" => f_host.erfc(), + _ => bug!(), + }; + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } @@ -818,24 +824,28 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let res = match link_name.as_str() { - "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), - "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), - #[allow(deprecated)] - "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(), - _ => bug!(), - }; - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp( - // this, - // res, - // 4, // log2(16) - // ); + + let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { + let res = match link_name.as_str() { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) + // Using host floats (but it's fine, these operations do not have guaranteed precision). + "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), + #[allow(deprecated)] + "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(), + _ => bug!(), + }; + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } @@ -856,33 +866,38 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { => { let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f64()?; - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let f_host = f.to_host(); - let res = match link_name.as_str() { - "cbrt" => f_host.cbrt(), - "cosh" => f_host.cosh(), - "sinh" => f_host.sinh(), - "tan" => f_host.tan(), - "tanh" => f_host.tanh(), - "acos" => f_host.acos(), - "asin" => f_host.asin(), - "atan" => f_host.atan(), - "log1p" => f_host.ln_1p(), - "expm1" => f_host.exp_m1(), - "tgamma" => f_host.gamma(), - "erf" => f_host.erf(), - "erfc" => f_host.erfc(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp( - // this, - // res.to_soft(), - // 4, // log2(16) - // ); + + let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let f_host = f.to_host(); + let res = match link_name.as_str() { + "cbrt" => f_host.cbrt(), + "cosh" => f_host.cosh(), + "sinh" => f_host.sinh(), + "tan" => f_host.tan(), + "tanh" => f_host.tanh(), + "acos" => f_host.acos(), + "asin" => f_host.asin(), + "atan" => f_host.atan(), + "log1p" => f_host.ln_1p(), + "expm1" => f_host.exp_m1(), + "tgamma" => f_host.gamma(), + "erf" => f_host.erf(), + "erfc" => f_host.erfc(), + _ => bug!(), + }; + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } @@ -895,24 +910,28 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let res = match link_name.as_str() { - "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), - "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), - #[allow(deprecated)] - "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(), - _ => bug!(), - }; - // Apply a relative error of 16ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp( - // this, - // res, - // 4, // log2(16) - // ); + + let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { + let res = match link_name.as_str() { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) + // Using host floats (but it's fine, these operations do not have guaranteed precision). + "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), + #[allow(deprecated)] + "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(), + _ => bug!(), + }; + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, res, 2, // log2(4) + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; } @@ -938,11 +957,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; + let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism + // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */); + let res = math::apply_random_float_error_ulp(this, res, 2 /* log2(4) */); + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + let res = math::clamp_float_value(link_name.as_str(), res); let res = this.adjust_nan(res, &[x]); this.write_scalar(res, dest)?; } @@ -954,11 +976,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; + let res = res.to_soft(); - // Apply a relative error of 16ULP to introduce some non-determinism + // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - // FIXME: temporarily disabled as it breaks std tests. - // let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */); + let res = math::apply_random_float_error_ulp(this, res, 2 /* log2(4) */); + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + let res = math::clamp_float_value(link_name.as_str(), res); let res = this.adjust_nan(res, &[x]); this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index fe7316c6680..96590b4bf2b 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1088,6 +1088,8 @@ pub fn libm() { assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0); assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0); + assert_approx_eq!(f32::NEG_INFINITY.exp_m1(), -1.0); + assert_approx_eq!(f64::NEG_INFINITY.exp_m1(), -1.0); assert_approx_eq!(10f32.exp2(), 1024f32); assert_approx_eq!(50f64.exp2(), 1125899906842624f64); @@ -1123,6 +1125,7 @@ pub fn libm() { assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); assert_eq!(ldexp(1.42, -0xFFFF), 0f64); + assert_eq!(ldexp(42.0, 0), 42.0); // Trigonometric functions. @@ -1131,8 +1134,14 @@ pub fn libm() { assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5); assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5); - assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); - assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); + // Increase error tolerance from 12ULP to 16ULP because of the extra operation. + assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4, 16); + assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4, 16); + assert_biteq(0.0f32.asin(), 0.0f32, "asin(+0) = +0"); + assert_biteq((-0.0f32).asin(), -0.0, "asin(-0) = -0"); + assert_biteq(0.0f64.asin(), 0.0, "asin(+0) = +0"); + assert_biteq((-0.0f64).asin(), -0.0, "asin(-0) = -0"); + assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); assert_approx_eq!(1.0f64.sinh(), 1.1752011936438014f64); @@ -1159,11 +1168,18 @@ pub fn libm() { assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5); assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5); - assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); - assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); + // Increase error tolerance from 12ULP to 16ULP because of the extra operation. + assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4, 16); + assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4, 16); + assert_biteq(1.0f32.acos(), 0.0, "acos(1) = 0"); + assert_biteq(1.0f64.acos(), 0.0, "acos(1) = 0"); assert_approx_eq!(1.0f32.cosh(), 1.54308f32); assert_approx_eq!(1.0f64.cosh(), 1.5430806348152437f64); + assert_eq!(0.0f32.cosh(), 1.0); + assert_eq!(0.0f64.cosh(), 1.0); + assert_eq!((-0.0f32).cosh(), 1.0); + assert_eq!((-0.0f64).cosh(), 1.0); assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); @@ -1173,6 +1189,47 @@ pub fn libm() { assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + // C standard defines a bunch of fixed outputs for atan2 + macro_rules! fixed_atan2_cases{ + ($float_type:ident) => {{ + use std::$float_type::consts::{PI, FRAC_PI_2, FRAC_PI_4}; + use $float_type::{INFINITY, NEG_INFINITY}; + + // atan2(±0,−0) = ±π. + assert_eq!($float_type::atan2(0.0, -0.0), PI, "atan2(0,−0) = π"); + assert_eq!($float_type::atan2(-0.0, -0.0), -PI, "atan2(-0,−0) = -π"); + + // atan2(±0, y) = ±π for y < 0. + assert_eq!($float_type::atan2(0.0, -1.0), PI, "atan2(0, y) = π for y < 0."); + assert_eq!($float_type::atan2(-0.0, -1.0), -PI, "atan2(-0, y) = -π for y < 0."); + + // atan2(x, ±0) = −π/2 for x < 0. + assert_eq!($float_type::atan2(-1.0, 0.0), -FRAC_PI_2, "atan2(x, 0) = −π/2 for x < 0"); + assert_eq!($float_type::atan2(-1.0, -0.0), -FRAC_PI_2, "atan2(x, -0) = −π/2 for x < 0"); + + // atan2(x, ±0) = π/2 for x > 0. + assert_eq!($float_type::atan2(1.0, 0.0), FRAC_PI_2, "atan2(x, 0) = π/2 for x > 0."); + assert_eq!($float_type::atan2(1.0, -0.0), FRAC_PI_2, "atan2(x, -0) = π/2 for x > 0."); + + // atan2(±x,−∞) = ±π for finite x > 0. + assert_eq!($float_type::atan2(1.0, NEG_INFINITY), PI, "atan2(x, −∞) = π for finite x > 0"); + assert_eq!($float_type::atan2(-1.0, NEG_INFINITY), -PI, "atan2(-x, −∞) = -π for finite x > 0"); + + // atan2(±∞, y) returns ±π/2 for finite y. + assert_eq!($float_type::atan2(INFINITY, 1.0), FRAC_PI_2, "atan2(+∞, y) returns π/2 for finite y"); + assert_eq!($float_type::atan2(NEG_INFINITY, 1.0), -FRAC_PI_2, "atan2(-∞, y) returns -π/2 for finite y"); + + // atan2(±∞, −∞) = ±3π/4 + assert_eq!($float_type::atan2(INFINITY, NEG_INFINITY), 3.0 * FRAC_PI_4, "atan2(+∞, −∞) = 3π/4"); + assert_eq!($float_type::atan2(NEG_INFINITY, NEG_INFINITY), -3.0 * FRAC_PI_4, "atan2(-∞, −∞) = -3π/4"); + + // atan2(±∞, +∞) = ±π/4 + assert_eq!($float_type::atan2(INFINITY, INFINITY), FRAC_PI_4, "atan2(+∞, +∞) = π/4"); + assert_eq!($float_type::atan2(NEG_INFINITY, INFINITY), -FRAC_PI_4, "atan2(-∞, +∞) = -π/4"); + }} + } + fixed_atan2_cases!(f32); + fixed_atan2_cases!(f64); assert_approx_eq!( 1.0f32.tanh(), @@ -1182,6 +1239,11 @@ pub fn libm() { 1.0f64.tanh(), (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2)) ); + assert_eq!(f32::INFINITY.tanh(), 1.0); + assert_eq!(f32::NEG_INFINITY.tanh(), -1.0); + assert_eq!(f64::INFINITY.tanh(), 1.0); + assert_eq!(f64::NEG_INFINITY.tanh(), -1.0); + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); @@ -1202,8 +1264,14 @@ pub fn libm() { assert_approx_eq!(1.0f32.erf(), 0.84270079294971486934122063508260926f32); assert_approx_eq!(1.0f64.erf(), 0.84270079294971486934122063508260926f64); + assert_eq!(f32::INFINITY.erf(), 1.0); + assert_eq!(f64::INFINITY.erf(), 1.0); assert_approx_eq!(1.0f32.erfc(), 0.15729920705028513065877936491739074f32); assert_approx_eq!(1.0f64.erfc(), 0.15729920705028513065877936491739074f64); + assert_eq!(f32::NEG_INFINITY.erfc(), 2.0); + assert_eq!(f64::NEG_INFINITY.erfc(), 2.0); + assert_eq!(f32::INFINITY.erfc(), 0.0); + assert_eq!(f64::INFINITY.erfc(), 0.0); } fn test_fast() { @@ -1413,7 +1481,6 @@ fn test_non_determinism() { } pub fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); - // FIXME: some are temporarily disabled as it breaks std tests. ensure_nondet(|| a.powf(b)); ensure_nondet(|| a.powi(2)); ensure_nondet(|| a.log(b)); @@ -1422,35 +1489,34 @@ fn test_non_determinism() { ensure_nondet(|| f32::consts::E.ln()); ensure_nondet(|| 10f32.log10()); ensure_nondet(|| 8f32.log2()); - // ensure_nondet(|| 1f32.ln_1p()); - // ensure_nondet(|| 27.0f32.cbrt()); - // ensure_nondet(|| 3.0f32.hypot(4.0f32)); + ensure_nondet(|| 1f32.ln_1p()); + ensure_nondet(|| 27.0f32.cbrt()); + ensure_nondet(|| 3.0f32.hypot(4.0f32)); ensure_nondet(|| 1f32.sin()); ensure_nondet(|| 1f32.cos()); // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, // which means the little rounding errors Miri introduces are discarded by the cast down to // `f32`. Just skip the test for them. - // if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { - // ensure_nondet(|| 1.0f32.tan()); - // ensure_nondet(|| 1.0f32.asin()); - // ensure_nondet(|| 5.0f32.acos()); - // ensure_nondet(|| 1.0f32.atan()); - // ensure_nondet(|| 1.0f32.atan2(2.0f32)); - // ensure_nondet(|| 1.0f32.sinh()); - // ensure_nondet(|| 1.0f32.cosh()); - // ensure_nondet(|| 1.0f32.tanh()); - // } - // ensure_nondet(|| 1.0f32.asinh()); - // ensure_nondet(|| 2.0f32.acosh()); - // ensure_nondet(|| 0.5f32.atanh()); - // ensure_nondet(|| 5.0f32.gamma()); - // ensure_nondet(|| 5.0f32.ln_gamma()); - // ensure_nondet(|| 5.0f32.erf()); - // ensure_nondet(|| 5.0f32.erfc()); + if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { + ensure_nondet(|| 1.0f32.tan()); + ensure_nondet(|| 1.0f32.asin()); + ensure_nondet(|| 5.0f32.acos()); + ensure_nondet(|| 1.0f32.atan()); + ensure_nondet(|| 1.0f32.atan2(2.0f32)); + ensure_nondet(|| 1.0f32.sinh()); + ensure_nondet(|| 1.0f32.cosh()); + ensure_nondet(|| 1.0f32.tanh()); + } + ensure_nondet(|| 1.0f32.asinh()); + ensure_nondet(|| 2.0f32.acosh()); + ensure_nondet(|| 0.5f32.atanh()); + ensure_nondet(|| 5.0f32.gamma()); + ensure_nondet(|| 5.0f32.ln_gamma()); + ensure_nondet(|| 5.0f32.erf()); + ensure_nondet(|| 5.0f32.erfc()); } pub fn test_operations_f64(a: f64, b: f64) { test_operations_f!(a, b); - // FIXME: some are temporarily disabled as it breaks std tests. ensure_nondet(|| a.powf(b)); ensure_nondet(|| a.powi(2)); ensure_nondet(|| a.log(b)); @@ -1459,26 +1525,26 @@ fn test_non_determinism() { ensure_nondet(|| 3f64.ln()); ensure_nondet(|| f64::consts::E.log10()); ensure_nondet(|| f64::consts::E.log2()); - // ensure_nondet(|| 1f64.ln_1p()); - // ensure_nondet(|| 27.0f64.cbrt()); - // ensure_nondet(|| 3.0f64.hypot(4.0f64)); + ensure_nondet(|| 1f64.ln_1p()); + ensure_nondet(|| 27.0f64.cbrt()); + ensure_nondet(|| 3.0f64.hypot(4.0f64)); ensure_nondet(|| 1f64.sin()); ensure_nondet(|| 1f64.cos()); - // ensure_nondet(|| 1.0f64.tan()); - // ensure_nondet(|| 1.0f64.asin()); - // ensure_nondet(|| 5.0f64.acos()); - // ensure_nondet(|| 1.0f64.atan()); - // ensure_nondet(|| 1.0f64.atan2(2.0f64)); - // ensure_nondet(|| 1.0f64.sinh()); - // ensure_nondet(|| 1.0f64.cosh()); - // ensure_nondet(|| 1.0f64.tanh()); - // ensure_nondet(|| 1.0f64.asinh()); - // ensure_nondet(|| 3.0f64.acosh()); - // ensure_nondet(|| 0.5f64.atanh()); - // ensure_nondet(|| 5.0f64.gamma()); - // ensure_nondet(|| 5.0f64.ln_gamma()); - // ensure_nondet(|| 5.0f64.erf()); - // ensure_nondet(|| 5.0f64.erfc()); + ensure_nondet(|| 1.0f64.tan()); + ensure_nondet(|| 1.0f64.asin()); + ensure_nondet(|| 5.0f64.acos()); + ensure_nondet(|| 1.0f64.atan()); + ensure_nondet(|| 1.0f64.atan2(2.0f64)); + ensure_nondet(|| 1.0f64.sinh()); + ensure_nondet(|| 1.0f64.cosh()); + ensure_nondet(|| 1.0f64.tanh()); + ensure_nondet(|| 1.0f64.asinh()); + ensure_nondet(|| 3.0f64.acosh()); + ensure_nondet(|| 0.5f64.atanh()); + ensure_nondet(|| 5.0f64.gamma()); + ensure_nondet(|| 5.0f64.ln_gamma()); + ensure_nondet(|| 5.0f64.erf()); + ensure_nondet(|| 5.0f64.erfc()); } pub fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index f9eb44d03ab..14bc380586a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -10706,20 +10706,6 @@ The tracking issue for this feature is: [#77998] deny_since: None, }, Lint { - label: "strict_overflow_ops", - description: r##"# `strict_overflow_ops` - -The tracking issue for this feature is: [#118260] - -[#118260]: https://github.com/rust-lang/rust/issues/118260 - ------------------------- -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { label: "strict_provenance_atomic_ptr", description: r##"# `strict_provenance_atomic_ptr` diff --git a/tests/crashes/144293-indirect-ops-llvm.rs b/tests/crashes/144293-indirect-ops-llvm.rs new file mode 100644 index 00000000000..490a0116d7d --- /dev/null +++ b/tests/crashes/144293-indirect-ops-llvm.rs @@ -0,0 +1,42 @@ +//@ known-bug: #144293 +// Same as recursion-etc but eggs LLVM emission into giving indirect arguments. +#![expect(incomplete_features)] +#![feature(explicit_tail_calls)] + +use std::hint::black_box; + +struct U64Wrapper { + pub x: u64, + pub arbitrary: String, +} + +fn count(curr: U64Wrapper, top: U64Wrapper) -> U64Wrapper { + if black_box(curr.x) >= top.x { + curr + } else { + become count( + U64Wrapper { + x: curr.x + 1, + arbitrary: curr.arbitrary, + }, + top, + ) + } +} + +fn main() { + println!( + "{}", + count( + U64Wrapper { + x: 0, + arbitrary: "hello!".into() + }, + black_box(U64Wrapper { + x: 1000000, + arbitrary: "goodbye!".into() + }) + ) + .x + ); +} diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index e59b23fdd20..8a36c901eed 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -24,7 +24,6 @@ fn main() -> () { _1 = Option::<u8>::Some(const 1_u8); FakeRead(ForLet(None), _1); AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); - StorageLive(_5); PlaceMention(_1); _6 = discriminant(_1); switchInt(move _6) -> [1: bb4, otherwise: bb3]; @@ -55,6 +54,7 @@ fn main() -> () { } bb6: { + StorageLive(_5); _5 = copy ((_1 as Some).0: u8); _0 = const (); StorageDead(_5); @@ -63,7 +63,6 @@ fn main() -> () { } bb7: { - StorageDead(_5); goto -> bb1; } diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir index 6369dbec750..3d26fe24ac9 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -21,9 +21,6 @@ fn let_else() -> () { } bb0: { - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); @@ -51,16 +48,19 @@ fn let_else() -> () { bb4: { AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] }); + StorageLive(_2); _2 = copy (_5.0: u32); + StorageLive(_3); _3 = copy (_5.1: u64); + StorageLive(_4); _4 = copy (_5.2: &char); StorageDead(_7); StorageDead(_5); _0 = const (); - StorageDead(_8); StorageDead(_4); StorageDead(_3); StorageDead(_2); + StorageDead(_8); return; } @@ -68,9 +68,6 @@ fn let_else() -> () { StorageDead(_7); StorageDead(_5); StorageDead(_8); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); goto -> bb1; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index b3eb3e1f8b9..484bc7dad12 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -85,11 +85,11 @@ _8 = &(_2.2: std::string::String); - _3 = &fake shallow (_2.0: bool); - _4 = &fake shallow (_2.1: bool); - StorageLive(_12); - StorageLive(_13); - _13 = copy _1; -- switchInt(move _13) -> [0: bb16, otherwise: bb15]; -+ switchInt(move _13) -> [0: bb13, otherwise: bb12]; + StorageLive(_9); + StorageLive(_10); + _10 = copy _1; +- switchInt(move _10) -> [0: bb12, otherwise: bb11]; ++ switchInt(move _10) -> [0: bb9, otherwise: bb8]; } - bb9: { @@ -100,11 +100,11 @@ _8 = &(_2.2: std::string::String); - _3 = &fake shallow (_2.0: bool); - _4 = &fake shallow (_2.1: bool); - StorageLive(_9); - StorageLive(_10); - _10 = copy _1; -- switchInt(move _10) -> [0: bb12, otherwise: bb11]; -+ switchInt(move _10) -> [0: bb9, otherwise: bb8]; + StorageLive(_12); + StorageLive(_13); + _13 = copy _1; +- switchInt(move _13) -> [0: bb16, otherwise: bb15]; ++ switchInt(move _13) -> [0: bb13, otherwise: bb12]; } - bb10: { @@ -139,7 +139,7 @@ - FakeRead(ForGuardBinding, _6); - FakeRead(ForGuardBinding, _8); StorageLive(_5); - _5 = copy (_2.1: bool); + _5 = copy (_2.0: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); - goto -> bb10; @@ -152,8 +152,8 @@ StorageDead(_9); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb1, imaginary: bb1]; -+ goto -> bb1; +- falseEdge -> [real: bb3, imaginary: bb3]; ++ goto -> bb2; } - bb15: { @@ -181,7 +181,7 @@ - FakeRead(ForGuardBinding, _6); - FakeRead(ForGuardBinding, _8); StorageLive(_5); - _5 = copy (_2.0: bool); + _5 = copy (_2.1: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); - goto -> bb10; @@ -194,8 +194,8 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb3, imaginary: bb3]; -+ goto -> bb2; +- falseEdge -> [real: bb1, imaginary: bb1]; ++ goto -> bb1; } - bb19: { diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index b3eb3e1f8b9..484bc7dad12 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -85,11 +85,11 @@ _8 = &(_2.2: std::string::String); - _3 = &fake shallow (_2.0: bool); - _4 = &fake shallow (_2.1: bool); - StorageLive(_12); - StorageLive(_13); - _13 = copy _1; -- switchInt(move _13) -> [0: bb16, otherwise: bb15]; -+ switchInt(move _13) -> [0: bb13, otherwise: bb12]; + StorageLive(_9); + StorageLive(_10); + _10 = copy _1; +- switchInt(move _10) -> [0: bb12, otherwise: bb11]; ++ switchInt(move _10) -> [0: bb9, otherwise: bb8]; } - bb9: { @@ -100,11 +100,11 @@ _8 = &(_2.2: std::string::String); - _3 = &fake shallow (_2.0: bool); - _4 = &fake shallow (_2.1: bool); - StorageLive(_9); - StorageLive(_10); - _10 = copy _1; -- switchInt(move _10) -> [0: bb12, otherwise: bb11]; -+ switchInt(move _10) -> [0: bb9, otherwise: bb8]; + StorageLive(_12); + StorageLive(_13); + _13 = copy _1; +- switchInt(move _13) -> [0: bb16, otherwise: bb15]; ++ switchInt(move _13) -> [0: bb13, otherwise: bb12]; } - bb10: { @@ -139,7 +139,7 @@ - FakeRead(ForGuardBinding, _6); - FakeRead(ForGuardBinding, _8); StorageLive(_5); - _5 = copy (_2.1: bool); + _5 = copy (_2.0: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); - goto -> bb10; @@ -152,8 +152,8 @@ StorageDead(_9); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb1, imaginary: bb1]; -+ goto -> bb1; +- falseEdge -> [real: bb3, imaginary: bb3]; ++ goto -> bb2; } - bb15: { @@ -181,7 +181,7 @@ - FakeRead(ForGuardBinding, _6); - FakeRead(ForGuardBinding, _8); StorageLive(_5); - _5 = copy (_2.0: bool); + _5 = copy (_2.1: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); - goto -> bb10; @@ -194,8 +194,8 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb3, imaginary: bb3]; -+ goto -> bb2; +- falseEdge -> [real: bb1, imaginary: bb1]; ++ goto -> bb1; } - bb19: { diff --git a/tests/ui/attributes/check-builtin-attr-ice.rs b/tests/ui/attributes/check-builtin-attr-ice.rs index 7745849acd0..811210e2cca 100644 --- a/tests/ui/attributes/check-builtin-attr-ice.rs +++ b/tests/ui/attributes/check-builtin-attr-ice.rs @@ -44,12 +44,10 @@ struct Foo { #[should_panic::skip] //~^ ERROR failed to resolve - //~| ERROR `#[should_panic::skip]` only has an effect on functions pub field: u8, #[should_panic::a::b::c] //~^ ERROR failed to resolve - //~| ERROR `#[should_panic::a::b::c]` only has an effect on functions pub field2: u8, } diff --git a/tests/ui/attributes/check-builtin-attr-ice.stderr b/tests/ui/attributes/check-builtin-attr-ice.stderr index 4f26f71efb7..07bbe01898a 100644 --- a/tests/ui/attributes/check-builtin-attr-ice.stderr +++ b/tests/ui/attributes/check-builtin-attr-ice.stderr @@ -5,35 +5,17 @@ LL | #[should_panic::skip] | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic` - --> $DIR/check-builtin-attr-ice.rs:50:7 + --> $DIR/check-builtin-attr-ice.rs:49:7 | LL | #[should_panic::a::b::c] | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `deny` - --> $DIR/check-builtin-attr-ice.rs:59:7 + --> $DIR/check-builtin-attr-ice.rs:57:7 | LL | #[deny::skip] | ^^^^ use of unresolved module or unlinked crate `deny` -error: `#[should_panic::skip]` only has an effect on functions - --> $DIR/check-builtin-attr-ice.rs:45:5 - | -LL | #[should_panic::skip] - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/check-builtin-attr-ice.rs:42:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error: `#[should_panic::a::b::c]` only has an effect on functions - --> $DIR/check-builtin-attr-ice.rs:50:5 - | -LL | #[should_panic::a::b::c] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/attributes/key-value-expansion-scope.rs b/tests/ui/attributes/key-value-expansion-scope.rs index 49a59502377..6688d698f9e 100644 --- a/tests/ui/attributes/key-value-expansion-scope.rs +++ b/tests/ui/attributes/key-value-expansion-scope.rs @@ -1,7 +1,7 @@ -#![doc = in_root!()] //~ WARN cannot find macro `in_root` +#![doc = in_root!()] //~ ERROR cannot find macro `in_root` //~| WARN this was previously accepted by the compiler #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope -#![doc = in_mod_escape!()] //~ WARN cannot find macro `in_mod_escape` +#![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope @@ -18,10 +18,10 @@ fn before() { macro_rules! in_root { () => { "" } } -#[doc = in_mod!()] //~ WARN cannot find macro `in_mod` +#[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` //~| WARN this was previously accepted by the compiler mod macros_stay { - #![doc = in_mod!()] //~ WARN cannot find macro `in_mod` + #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` //~| WARN this was previously accepted by the compiler macro_rules! in_mod { () => { "" } } @@ -33,10 +33,10 @@ mod macros_stay { } #[macro_use] -#[doc = in_mod_escape!()] //~ WARN cannot find macro `in_mod_escape` +#[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler mod macros_escape { - #![doc = in_mod_escape!()] //~ WARN cannot find macro `in_mod_escape` + #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` //~| WARN this was previously accepted by the compiler macro_rules! in_mod_escape { () => { "" } } diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr index 91a602e57d9..29b48ca4ce6 100644 --- a/tests/ui/attributes/key-value-expansion-scope.stderr +++ b/tests/ui/attributes/key-value-expansion-scope.stderr @@ -126,7 +126,7 @@ LL | #![doc = in_block!()] | = help: have you added the `#[macro_use]` on the module/import? -warning: cannot find macro `in_root` in the current scope when looking from the crate root +error: cannot find macro `in_root` in the current scope when looking from the crate root --> $DIR/key-value-expansion-scope.rs:1:10 | LL | #![doc = in_root!()] @@ -135,9 +135,9 @@ LL | #![doc = in_root!()] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition - = note: `#[warn(out_of_scope_macro_calls)]` on by default + = note: `#[deny(out_of_scope_macro_calls)]` on by default -warning: cannot find macro `in_mod_escape` in the current scope when looking from the crate root +error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root --> $DIR/key-value-expansion-scope.rs:4:10 | LL | #![doc = in_mod_escape!()] @@ -147,7 +147,7 @@ LL | #![doc = in_mod_escape!()] = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition -warning: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` +error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` --> $DIR/key-value-expansion-scope.rs:21:9 | LL | #[doc = in_mod!()] @@ -157,7 +157,7 @@ LL | #[doc = in_mod!()] = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition -warning: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` +error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` --> $DIR/key-value-expansion-scope.rs:24:14 | LL | #![doc = in_mod!()] @@ -167,7 +167,7 @@ LL | #![doc = in_mod!()] = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition -warning: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` +error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` --> $DIR/key-value-expansion-scope.rs:36:9 | LL | #[doc = in_mod_escape!()] @@ -177,7 +177,7 @@ LL | #[doc = in_mod_escape!()] = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition -warning: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` +error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` --> $DIR/key-value-expansion-scope.rs:39:14 | LL | #![doc = in_mod_escape!()] @@ -187,5 +187,77 @@ LL | #![doc = in_mod_escape!()] = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> = help: import `macro_rules` with `use` to make it callable above its definition -error: aborting due to 16 previous errors; 6 warnings emitted +error: aborting due to 22 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: cannot find macro `in_root` in the current scope when looking from the crate root + --> $DIR/key-value-expansion-scope.rs:1:10 + | +LL | #![doc = in_root!()] + | ^^^^^^^ not found from the crate root + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default + +Future breakage diagnostic: +error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root + --> $DIR/key-value-expansion-scope.rs:4:10 + | +LL | #![doc = in_mod_escape!()] + | ^^^^^^^^^^^^^ not found from the crate root + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default + +Future breakage diagnostic: +error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` + --> $DIR/key-value-expansion-scope.rs:21:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^ not found from module `macros_stay` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default + +Future breakage diagnostic: +error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay` + --> $DIR/key-value-expansion-scope.rs:24:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^ not found from module `macros_stay` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default + +Future breakage diagnostic: +error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` + --> $DIR/key-value-expansion-scope.rs:36:9 + | +LL | #[doc = in_mod_escape!()] + | ^^^^^^^^^^^^^ not found from module `macros_escape` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default + +Future breakage diagnostic: +error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape` + --> $DIR/key-value-expansion-scope.rs:39:14 + | +LL | #![doc = in_mod_escape!()] + | ^^^^^^^^^^^^^ not found from module `macros_escape` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535> + = help: import `macro_rules` with `use` to make it callable above its definition + = note: `#[deny(out_of_scope_macro_calls)]` on by default diff --git a/tests/ui/auto-traits/assoc-ty.current.stderr b/tests/ui/auto-traits/assoc-ty.current.stderr index 77a1c8fb654..d793ae66526 100644 --- a/tests/ui/auto-traits/assoc-ty.current.stderr +++ b/tests/ui/auto-traits/assoc-ty.current.stderr @@ -5,7 +5,7 @@ LL | auto trait Trait { | ----- auto traits cannot have associated items LL | LL | type Output; - | -----^^^^^^- help: remove these associated items + | ^^^^^^ error[E0658]: auto traits are experimental and possibly buggy --> $DIR/assoc-ty.rs:8:1 diff --git a/tests/ui/auto-traits/assoc-ty.next.stderr b/tests/ui/auto-traits/assoc-ty.next.stderr index 4ce00d17475..a41f7d99278 100644 --- a/tests/ui/auto-traits/assoc-ty.next.stderr +++ b/tests/ui/auto-traits/assoc-ty.next.stderr @@ -5,7 +5,7 @@ LL | auto trait Trait { | ----- auto traits cannot have associated items LL | LL | type Output; - | -----^^^^^^- help: remove these associated items + | ^^^^^^ error[E0658]: auto traits are experimental and possibly buggy --> $DIR/assoc-ty.rs:8:1 diff --git a/tests/ui/auto-traits/auto-trait-validation.fixed b/tests/ui/auto-traits/auto-trait-validation.fixed index 8a445448c85..b24dc1cb2c3 100644 --- a/tests/ui/auto-traits/auto-trait-validation.fixed +++ b/tests/ui/auto-traits/auto-trait-validation.fixed @@ -11,4 +11,15 @@ auto trait LifetimeBound {} //~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { } //~^ ERROR auto traits cannot have associated items [E0380] +auto trait AssocTy { } +//~^ ERROR auto traits cannot have associated items [E0380] +auto trait All { + //~^ ERROR auto traits cannot have generic parameters [E0567] + +} +// We can't test both generic params and super-traits because the suggestion span overlaps. +auto trait All2 { + //~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] + +} fn main() {} diff --git a/tests/ui/auto-traits/auto-trait-validation.rs b/tests/ui/auto-traits/auto-trait-validation.rs index b5e7505d86a..9665e5bc393 100644 --- a/tests/ui/auto-traits/auto-trait-validation.rs +++ b/tests/ui/auto-traits/auto-trait-validation.rs @@ -11,4 +11,19 @@ auto trait LifetimeBound : 'static {} //~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { fn foo() {} } //~^ ERROR auto traits cannot have associated items [E0380] +auto trait AssocTy { type Bar; } +//~^ ERROR auto traits cannot have associated items [E0380] +auto trait All<'a, T> { + //~^ ERROR auto traits cannot have generic parameters [E0567] + type Bar; + //~^ ERROR auto traits cannot have associated items [E0380] + fn foo() {} +} +// We can't test both generic params and super-traits because the suggestion span overlaps. +auto trait All2: Copy + 'static { + //~^ ERROR auto traits cannot have super traits or lifetime bounds [E0568] + type Bar; + //~^ ERROR auto traits cannot have associated items [E0380] + fn foo() {} +} fn main() {} diff --git a/tests/ui/auto-traits/auto-trait-validation.stderr b/tests/ui/auto-traits/auto-trait-validation.stderr index a6e5ac54869..60757db6d1e 100644 --- a/tests/ui/auto-traits/auto-trait-validation.stderr +++ b/tests/ui/auto-traits/auto-trait-validation.stderr @@ -2,23 +2,23 @@ error[E0567]: auto traits cannot have generic parameters --> $DIR/auto-trait-validation.rs:6:19 | LL | auto trait Generic<T> {} - | -------^^^ help: remove the parameters + | -------^^^ | | | auto trait cannot have generic parameters error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:8:17 + --> $DIR/auto-trait-validation.rs:8:20 | LL | auto trait Bound : Copy {} - | -----^^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^ | | | auto traits cannot have super traits or lifetime bounds error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/auto-trait-validation.rs:10:25 + --> $DIR/auto-trait-validation.rs:10:28 | LL | auto trait LifetimeBound : 'static {} - | -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds + | ------------- ^^^^^^^ | | | auto traits cannot have super traits or lifetime bounds @@ -26,12 +26,59 @@ error[E0380]: auto traits cannot have associated items --> $DIR/auto-trait-validation.rs:12:25 | LL | auto trait MyTrait { fn foo() {} } - | ------- ---^^^----- - | | | - | | help: remove these associated items + | ------- ^^^ + | | + | auto traits cannot have associated items + +error[E0380]: auto traits cannot have associated items + --> $DIR/auto-trait-validation.rs:14:27 + | +LL | auto trait AssocTy { type Bar; } + | ------- ^^^ + | | | auto traits cannot have associated items -error: aborting due to 4 previous errors +error[E0567]: auto traits cannot have generic parameters + --> $DIR/auto-trait-validation.rs:16:15 + | +LL | auto trait All<'a, T> { + | ---^^^^^^^ + | | + | auto trait cannot have generic parameters + +error[E0380]: auto traits cannot have associated items + --> $DIR/auto-trait-validation.rs:18:10 + | +LL | auto trait All<'a, T> { + | --- auto traits cannot have associated items +LL | +LL | type Bar; + | ^^^ +LL | +LL | fn foo() {} + | ^^^ + +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/auto-trait-validation.rs:23:18 + | +LL | auto trait All2: Copy + 'static { + | ---- ^^^^ ^^^^^^^ + | | + | auto traits cannot have super traits or lifetime bounds + +error[E0380]: auto traits cannot have associated items + --> $DIR/auto-trait-validation.rs:25:10 + | +LL | auto trait All2: Copy + 'static { + | ---- auto traits cannot have associated items +LL | +LL | type Bar; + | ^^^ +LL | +LL | fn foo() {} + | ^^^ + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0380, E0567, E0568. For more information about an error, try `rustc --explain E0380`. diff --git a/tests/ui/auto-traits/bad-generics-on-dyn.stderr b/tests/ui/auto-traits/bad-generics-on-dyn.stderr index 06c7cbcd76d..a6977c2037e 100644 --- a/tests/ui/auto-traits/bad-generics-on-dyn.stderr +++ b/tests/ui/auto-traits/bad-generics-on-dyn.stderr @@ -2,7 +2,7 @@ error[E0567]: auto traits cannot have generic parameters --> $DIR/bad-generics-on-dyn.rs:3:18 | LL | auto trait Trait1<'a> {} - | ------^^^^ help: remove the parameters + | ------^^^^ | | | auto trait cannot have generic parameters diff --git a/tests/ui/auto-traits/has-arguments.stderr b/tests/ui/auto-traits/has-arguments.stderr index b8a680e6a5c..5228b6d2d1a 100644 --- a/tests/ui/auto-traits/has-arguments.stderr +++ b/tests/ui/auto-traits/has-arguments.stderr @@ -2,7 +2,7 @@ error[E0567]: auto traits cannot have generic parameters --> $DIR/has-arguments.rs:3:18 | LL | auto trait Trait1<'outer> {} - | ------^^^^^^^^ help: remove the parameters + | ------^^^^^^^^ | | | auto trait cannot have generic parameters diff --git a/tests/ui/auto-traits/issue-117789.stderr b/tests/ui/auto-traits/issue-117789.stderr index 99efb213417..1e047c7d2e0 100644 --- a/tests/ui/auto-traits/issue-117789.stderr +++ b/tests/ui/auto-traits/issue-117789.stderr @@ -2,7 +2,7 @@ error[E0567]: auto traits cannot have generic parameters --> $DIR/issue-117789.rs:1:17 | LL | auto trait Trait<P> {} - | -----^^^ help: remove the parameters + | -----^^^ | | | auto trait cannot have generic parameters diff --git a/tests/ui/auto-traits/issue-23080-2.current.stderr b/tests/ui/auto-traits/issue-23080-2.current.stderr index 62c7b37041f..3af97f57d48 100644 --- a/tests/ui/auto-traits/issue-23080-2.current.stderr +++ b/tests/ui/auto-traits/issue-23080-2.current.stderr @@ -4,7 +4,7 @@ error[E0380]: auto traits cannot have associated items LL | unsafe auto trait Trait { | ----- auto traits cannot have associated items LL | type Output; - | -----^^^^^^- help: remove these associated items + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/auto-traits/issue-23080-2.next.stderr b/tests/ui/auto-traits/issue-23080-2.next.stderr index 62c7b37041f..3af97f57d48 100644 --- a/tests/ui/auto-traits/issue-23080-2.next.stderr +++ b/tests/ui/auto-traits/issue-23080-2.next.stderr @@ -4,7 +4,7 @@ error[E0380]: auto traits cannot have associated items LL | unsafe auto trait Trait { | ----- auto traits cannot have associated items LL | type Output; - | -----^^^^^^- help: remove these associated items + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/auto-traits/issue-23080.stderr b/tests/ui/auto-traits/issue-23080.stderr index 5cea45060c8..02a75519102 100644 --- a/tests/ui/auto-traits/issue-23080.stderr +++ b/tests/ui/auto-traits/issue-23080.stderr @@ -1,13 +1,10 @@ error[E0380]: auto traits cannot have associated items --> $DIR/issue-23080.rs:5:8 | -LL | unsafe auto trait Trait { - | ----- auto traits cannot have associated items -LL | fn method(&self) { - | _____- ^^^^^^ -LL | | println!("Hello"); -LL | | } - | |_____- help: remove these associated items +LL | unsafe auto trait Trait { + | ----- auto traits cannot have associated items +LL | fn method(&self) { + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/auto-traits/issue-84075.stderr b/tests/ui/auto-traits/issue-84075.stderr index 943d521ce9e..4edf2ecdf06 100644 --- a/tests/ui/auto-traits/issue-84075.stderr +++ b/tests/ui/auto-traits/issue-84075.stderr @@ -2,7 +2,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds --> $DIR/issue-84075.rs:5:18 | LL | auto trait Magic where Self: Copy {} - | ----- ^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^^^^^^^^^^^^^ | | | auto traits cannot have super traits or lifetime bounds diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr index 27e38ce06a4..bc17fefc944 100644 --- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr +++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr @@ -1,8 +1,8 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:17 + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20 | LL | auto trait Magic : Sized where Option<Self> : Magic {} - | -----^^^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^^ | | | auto traits cannot have super traits or lifetime bounds @@ -10,7 +10,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:26 | LL | auto trait Magic : Sized where Option<Self> : Magic {} - | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | auto traits cannot have super traits or lifetime bounds diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr index 23aae13639c..bc9791a5799 100644 --- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr +++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr @@ -1,8 +1,8 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/typeck-auto-trait-no-supertraits.rs:28:17 + --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19 | LL | auto trait Magic: Copy {} - | -----^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^ | | | auto traits cannot have super traits or lifetime bounds diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index f422919983b..44fc23b6390 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -198,6 +198,35 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `power9-altivec` `power9-vector` `prfchw` +`ptx32` +`ptx40` +`ptx41` +`ptx42` +`ptx43` +`ptx50` +`ptx60` +`ptx61` +`ptx62` +`ptx63` +`ptx64` +`ptx65` +`ptx70` +`ptx71` +`ptx72` +`ptx73` +`ptx74` +`ptx75` +`ptx76` +`ptx77` +`ptx78` +`ptx80` +`ptx81` +`ptx82` +`ptx83` +`ptx84` +`ptx85` +`ptx86` +`ptx87` `quadword-atomics` `rand` `ras` @@ -222,6 +251,33 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `simd128` `sm3` `sm4` +`sm_100` +`sm_100a` +`sm_101` +`sm_101a` +`sm_120` +`sm_120a` +`sm_20` +`sm_21` +`sm_30` +`sm_32` +`sm_35` +`sm_37` +`sm_50` +`sm_52` +`sm_53` +`sm_60` +`sm_61` +`sm_62` +`sm_70` +`sm_72` +`sm_75` +`sm_80` +`sm_86` +`sm_87` +`sm_89` +`sm_90` +`sm_90a` `sme` `sme-b16b16` `sme-f16f16` diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index 239171217eb..35b0dd216a1 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -1,4 +1,3 @@ -#![feature(const_type_id)] #![feature(generic_const_exprs)] #![feature(const_trait_impl, const_cmp)] #![feature(core_intrinsics)] diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index 7031230db91..f13fd795d7a 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/issue-90318.rs:15:8 + --> $DIR/issue-90318.rs:14:8 | LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True, | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True, = note: this operation may be supported in the future error: overly complex generic constant - --> $DIR/issue-90318.rs:22:8 + --> $DIR/issue-90318.rs:21:8 | LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True, | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-typeid-of-rpass.rs b/tests/ui/consts/const-typeid-of-rpass.rs index 15ffdd1e83a..30f41070893 100644 --- a/tests/ui/consts/const-typeid-of-rpass.rs +++ b/tests/ui/consts/const-typeid-of-rpass.rs @@ -1,6 +1,4 @@ //@ run-pass -#![feature(const_type_id)] -#![feature(core_intrinsics)] use std::any::TypeId; diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index 8c21f7b1a5a..ff44876c5c4 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -1,6 +1,6 @@ //@ ignore-backends: gcc //@ compile-flags: -Znext-solver -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature(const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id.rs b/tests/ui/consts/const_transmute_type_id.rs index a2d4cf37830..98783ad5b81 100644 --- a/tests/ui/consts/const_transmute_type_id.rs +++ b/tests/ui/consts/const_transmute_type_id.rs @@ -1,4 +1,4 @@ -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature(const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id2.rs b/tests/ui/consts/const_transmute_type_id2.rs index 3ceb2b942b0..7e09947b768 100644 --- a/tests/ui/consts/const_transmute_type_id2.rs +++ b/tests/ui/consts/const_transmute_type_id2.rs @@ -1,6 +1,6 @@ //@ normalize-stderr: "0x(ff)+" -> "<u128::MAX>" -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature( const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs index f1bb8cddf77..77c469d42f5 100644 --- a/tests/ui/consts/const_transmute_type_id3.rs +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -1,7 +1,7 @@ //! Test that all bytes of a TypeId must have the //! TypeId marker provenance. -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature( const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs index 0ea75f2a2f4..bedd6084a16 100644 --- a/tests/ui/consts/const_transmute_type_id4.rs +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -1,4 +1,4 @@ -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature(const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs index ae0429f8dbb..7f9a34104a3 100644 --- a/tests/ui/consts/const_transmute_type_id5.rs +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -1,7 +1,7 @@ //! Test that we require an equal TypeId to have an integer part that properly //! reflects the type id hash. -#![feature(const_type_id, const_trait_impl, const_cmp)] +#![feature(const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/issue-102117.rs b/tests/ui/consts/issue-102117.rs index 6cb9832bcd8..b7955283a8d 100644 --- a/tests/ui/consts/issue-102117.rs +++ b/tests/ui/consts/issue-102117.rs @@ -1,5 +1,3 @@ -#![feature(const_type_id)] - use std::alloc::Layout; use std::any::TypeId; use std::mem::transmute; diff --git a/tests/ui/consts/issue-102117.stderr b/tests/ui/consts/issue-102117.stderr index da92db87f18..cea355d01d7 100644 --- a/tests/ui/consts/issue-102117.stderr +++ b/tests/ui/consts/issue-102117.stderr @@ -1,5 +1,5 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/issue-102117.rs:19:26 + --> $DIR/issue-102117.rs:17:26 | LL | type_id: TypeId::of::<T>(), | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | pub fn new<T: 'static>() -> &'static Self { | +++++++++ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/issue-102117.rs:19:26 + --> $DIR/issue-102117.rs:17:26 | LL | type_id: TypeId::of::<T>(), | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index f43823fa155..6459150a660 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -6,7 +6,6 @@ // will be properly rejected. This test will ensure that monomorphic use of these // would not be wrongly rejected in patterns. -#![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_trait_impl)] #![feature(const_cmp)] diff --git a/tests/ui/consts/issue-73976-polymorphic.rs b/tests/ui/consts/issue-73976-polymorphic.rs index 98b4005792d..db06706a970 100644 --- a/tests/ui/consts/issue-73976-polymorphic.rs +++ b/tests/ui/consts/issue-73976-polymorphic.rs @@ -5,7 +5,6 @@ // This test case should either run-pass or be rejected at compile time. // Currently we just disallow this usage and require pattern is monomorphic. -#![feature(const_type_id)] #![feature(const_type_name)] use std::any::{self, TypeId}; diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr index ec9512a2616..41a5e804c67 100644 --- a/tests/ui/consts/issue-73976-polymorphic.stderr +++ b/tests/ui/consts/issue-73976-polymorphic.stderr @@ -1,5 +1,5 @@ error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/issue-73976-polymorphic.rs:20:37 + --> $DIR/issue-73976-polymorphic.rs:19:37 | LL | impl<T: 'static> GetTypeId<T> { | ----------------------------- @@ -12,7 +12,7 @@ LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) | ^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/issue-73976-polymorphic.rs:31:42 + --> $DIR/issue-73976-polymorphic.rs:30:42 | LL | impl<T: 'static> GetTypeNameLen<T> { | ---------------------------------- diff --git a/tests/ui/drop/or-pattern-drop-order.rs b/tests/ui/drop/or-pattern-drop-order.rs index fdc28225c35..cca81673ac3 100644 --- a/tests/ui/drop/or-pattern-drop-order.rs +++ b/tests/ui/drop/or-pattern-drop-order.rs @@ -1,6 +1,7 @@ //@ run-pass //! Test drop order for different ways of declaring pattern bindings involving or-patterns. -//! Currently, it's inconsistent between language constructs (#142163). +//! In particular, are ordered based on the order in which the first occurrence of each binding +//! appears (i.e. the "primary" bindings). Regression test for #142163. use std::cell::RefCell; use std::ops::Drop; @@ -43,11 +44,10 @@ fn main() { y = LogDrop(o, 1); }); - // When bindings are declared with `let pat = expr;`, bindings within or-patterns are seen last, - // thus they're dropped first. + // `let pat = expr;` should have the same drop order. assert_drop_order(1..=3, |o| { - // Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`. - let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 1)), LogDrop(o, 2)); + // Drops are right-to-left: `z`, `y`, `x`. + let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)); }); assert_drop_order(1..=2, |o| { // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. @@ -58,30 +58,29 @@ fn main() { let ((true, x, y) | (false, y, x)) = (false, LogDrop(o, 1), LogDrop(o, 2)); }); - // `match` treats or-patterns as last like `let pat = expr;`, but also determines drop order - // using the order of the bindings in the *last* or-pattern alternative. + // `match` should have the same drop order. assert_drop_order(1..=3, |o| { - // Drops are right-to-left, treating `y` as rightmost: `y`, `z`, `x`. - match (LogDrop(o, 3), Ok(LogDrop(o, 1)), LogDrop(o, 2)) { (x, Ok(y) | Err(y), z) => {} } + // Drops are right-to-left: `z`, `y` `x`. + match (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)) { (x, Ok(y) | Err(y), z) => {} } }); assert_drop_order(1..=2, |o| { - // The last or-pattern alternative determines the bindings' drop order: `x`, `y`. - match (true, LogDrop(o, 1), LogDrop(o, 2)) { (true, x, y) | (false, y, x) => {} } + // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. + match (true, LogDrop(o, 2), LogDrop(o, 1)) { (true, x, y) | (false, y, x) => {} } }); assert_drop_order(1..=2, |o| { - // That drop order is used regardless of which or-pattern alternative matches: `x`, `y`. - match (false, LogDrop(o, 2), LogDrop(o, 1)) { (true, x, y) | (false, y, x) => {} } + // That drop order is used regardless of which or-pattern alternative matches: `y`, `x`. + match (false, LogDrop(o, 1), LogDrop(o, 2)) { (true, x, y) | (false, y, x) => {} } }); // Function params are visited one-by-one, and the order of bindings within a param's pattern is - // the same as `let pat = expr`; + // the same as `let pat = expr;` assert_drop_order(1..=3, |o| { // Among separate params, the drop order is right-to-left: `z`, `y`, `x`. (|x, (Ok(y) | Err(y)), z| {})(LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)); }); assert_drop_order(1..=3, |o| { - // Within a param's pattern, or-patterns are treated as rightmost: `y`, `z`, `x`. - (|(x, Ok(y) | Err(y), z)| {})((LogDrop(o, 3), Ok(LogDrop(o, 1)), LogDrop(o, 2))); + // Within a param's pattern, likewise: `z`, `y`, `x`. + (|(x, Ok(y) | Err(y), z)| {})((LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1))); }); assert_drop_order(1..=2, |o| { // The first or-pattern alternative determines the bindings' drop order: `y`, `x`. @@ -89,12 +88,11 @@ fn main() { }); // `if let` and `let`-`else` see bindings in the same order as `let pat = expr;`. - // Vars in or-patterns are seen last (dropped first), and the first alternative's order is used. assert_drop_order(1..=3, |o| { - if let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 1)), LogDrop(o, 2)) {} + if let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)) {} }); assert_drop_order(1..=3, |o| { - let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 1)), LogDrop(o, 2)) else { + let (x, Ok(y) | Err(y), z) = (LogDrop(o, 3), Ok(LogDrop(o, 2)), LogDrop(o, 1)) else { unreachable!(); }; }); @@ -106,4 +104,21 @@ fn main() { unreachable!(); }; }); + + // Test nested and adjacent or-patterns, including or-patterns without bindings under a guard. + assert_drop_order(1..=6, |o| { + // The `LogDrop`s that aren't moved into bindings are dropped last. + match [ + [LogDrop(o, 6), LogDrop(o, 4)], + [LogDrop(o, 3), LogDrop(o, 2)], + [LogDrop(o, 1), LogDrop(o, 5)], + ] { + [ + [_ | _, w | w] | [w | w, _ | _], + [x | x, y | y] | [y | y, x | x], + [z | z, _ | _] | [_ | _, z | z], + ] if true => {} + _ => unreachable!(), + } + }); } diff --git a/tests/ui/dropck/eager-by-ref-binding-for-guards.rs b/tests/ui/dropck/eager-by-ref-binding-for-guards.rs index 3f475839171..90ff9a747ae 100644 --- a/tests/ui/dropck/eager-by-ref-binding-for-guards.rs +++ b/tests/ui/dropck/eager-by-ref-binding-for-guards.rs @@ -17,15 +17,15 @@ fn main() { (mut long2, ref short2) if true => long2.0 = &short2, _ => unreachable!(), } - // This depends on the binding modes of the final or-pattern alternatives (see #142163): + // This depends on the binding modes of the first or-pattern alternatives: let res: &Result<u8, &u8> = &Ok(1); match (Struct(&&0), res) { (mut long3, Ok(short3) | &Err(short3)) if true => long3.0 = &short3, - //~^ ERROR `short3` does not live long enough _ => unreachable!(), } match (Struct(&&0), res) { (mut long4, &Err(short4) | Ok(short4)) if true => long4.0 = &short4, + //~^ ERROR `short4` does not live long enough _ => unreachable!(), } } diff --git a/tests/ui/dropck/eager-by-ref-binding-for-guards.stderr b/tests/ui/dropck/eager-by-ref-binding-for-guards.stderr index cb1a04cd444..2648ce6f99c 100644 --- a/tests/ui/dropck/eager-by-ref-binding-for-guards.stderr +++ b/tests/ui/dropck/eager-by-ref-binding-for-guards.stderr @@ -11,15 +11,15 @@ LL | (mut long1, ref short1) => long1.0 = &short1, | = note: values in a scope are dropped in the opposite order they are defined -error[E0597]: `short3` does not live long enough - --> $DIR/eager-by-ref-binding-for-guards.rs:23:69 +error[E0597]: `short4` does not live long enough + --> $DIR/eager-by-ref-binding-for-guards.rs:27:69 | -LL | (mut long3, Ok(short3) | &Err(short3)) if true => long3.0 = &short3, - | ------ ^^^^^^- - | | | | - | | | `short3` dropped here while still borrowed - | | | borrow might be used here, when `long3` is dropped and runs the `Drop` code for type `Struct` - | binding `short3` declared here borrowed value does not live long enough +LL | (mut long4, &Err(short4) | Ok(short4)) if true => long4.0 = &short4, + | ------ ^^^^^^- + | | | | + | | | `short4` dropped here while still borrowed + | | | borrow might be used here, when `long4` is dropped and runs the `Drop` code for type `Struct` + | binding `short4` declared here borrowed value does not live long enough | = note: values in a scope are dropped in the opposite order they are defined diff --git a/tests/ui/dropck/let-else-more-permissive.rs b/tests/ui/dropck/let-else-more-permissive.rs index 0020814aa81..6247b0eb5e2 100644 --- a/tests/ui/dropck/let-else-more-permissive.rs +++ b/tests/ui/dropck/let-else-more-permissive.rs @@ -1,5 +1,5 @@ -//! The drop check is currently more permissive when `let` statements have an `else` block, due to -//! scheduling drops for bindings' storage before pattern-matching (#142056). +//! Regression test for #142056. The drop check used to be more permissive for `let` statements with +//! `else` blocks, due to scheduling drops for bindings' storage before pattern-matching. struct Struct<T>(T); impl<T> Drop for Struct<T> { @@ -14,10 +14,11 @@ fn main() { //~^ ERROR `short1` does not live long enough } { - // This is OK: `short2`'s storage is live until after `long2`'s drop runs. + // This was OK: `short2`'s storage was live until after `long2`'s drop ran. #[expect(irrefutable_let_patterns)] let (mut long2, short2) = (Struct(&0), 1) else { unreachable!() }; long2.0 = &short2; + //~^ ERROR `short2` does not live long enough } { // Sanity check: `short3`'s drop is significant; it's dropped before `long3`: diff --git a/tests/ui/dropck/let-else-more-permissive.stderr b/tests/ui/dropck/let-else-more-permissive.stderr index 7c37e170afa..4f0c193a78d 100644 --- a/tests/ui/dropck/let-else-more-permissive.stderr +++ b/tests/ui/dropck/let-else-more-permissive.stderr @@ -14,8 +14,24 @@ LL | } | = note: values in a scope are dropped in the opposite order they are defined +error[E0597]: `short2` does not live long enough + --> $DIR/let-else-more-permissive.rs:20:19 + | +LL | let (mut long2, short2) = (Struct(&0), 1) else { unreachable!() }; + | ------ binding `short2` declared here +LL | long2.0 = &short2; + | ^^^^^^^ borrowed value does not live long enough +LL | +LL | } + | - + | | + | `short2` dropped here while still borrowed + | borrow might be used here, when `long2` is dropped and runs the `Drop` code for type `Struct` + | + = note: values in a scope are dropped in the opposite order they are defined + error[E0597]: `short3` does not live long enough - --> $DIR/let-else-more-permissive.rs:27:19 + --> $DIR/let-else-more-permissive.rs:28:19 | LL | let (mut long3, short3) = (Struct(&tmp), Box::new(1)) else { unreachable!() }; | ------ binding `short3` declared here @@ -30,6 +46,6 @@ LL | } | = note: values in a scope are dropped in the opposite order they are defined -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/explicit-tail-calls/drop-order.rs b/tests/ui/explicit-tail-calls/drop-order.rs index 242336be484..58e1afbdf0c 100644 --- a/tests/ui/explicit-tail-calls/drop-order.rs +++ b/tests/ui/explicit-tail-calls/drop-order.rs @@ -1,5 +1,3 @@ -// FIXME(explicit_tail_calls): enable this test once rustc_codegen_ssa supports tail calls -//@ ignore-test: tail calls are not implemented in rustc_codegen_ssa yet, so this causes 🧊 //@ run-pass #![expect(incomplete_features)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/explicit-tail-calls/indexer.rs b/tests/ui/explicit-tail-calls/indexer.rs new file mode 100644 index 00000000000..5644506b2f5 --- /dev/null +++ b/tests/ui/explicit-tail-calls/indexer.rs @@ -0,0 +1,22 @@ +//@ run-pass +// Indexing taken from +// https://github.com/phi-go/rfcs/blob/guaranteed-tco/text%2F0000-explicit-tail-calls.md#tail-call-elimination +// no other test has utilized the "function table" +// described in the RFC aside from this one at this point. +#![expect(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn f0(_: usize) {} +fn f1(_: usize) {} +fn f2(_: usize) {} + +fn indexer(idx: usize) { + let v: [fn(usize); 3] = [f0, f1, f2]; + become v[idx](idx) +} + +fn main() { + for idx in 0..3 { + indexer(idx); + } +} diff --git a/tests/ui/extern/issue-80074.rs b/tests/ui/extern/issue-80074.rs index ba7b55a450f..942b78916d6 100644 --- a/tests/ui/extern/issue-80074.rs +++ b/tests/ui/extern/issue-80074.rs @@ -11,7 +11,7 @@ extern crate issue_80074_2; fn main() { foo!(); - //~^ WARN: macro `foo` is private + //~^ ERROR: macro `foo` is private //~| WARN: it will become a hard error in a future release! bar!(); //~^ ERROR: cannot find macro `bar` in this scope diff --git a/tests/ui/extern/issue-80074.stderr b/tests/ui/extern/issue-80074.stderr index b30b761593e..510ca1be0a1 100644 --- a/tests/ui/extern/issue-80074.stderr +++ b/tests/ui/extern/issue-80074.stderr @@ -16,7 +16,7 @@ error: cannot find macro `m` in this scope LL | m!(); | ^ -warning: macro `foo` is private +error: macro `foo` is private --> $DIR/issue-80074.rs:13:5 | LL | foo!(); @@ -24,8 +24,19 @@ LL | foo!(); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #120192 <https://github.com/rust-lang/rust/issues/120192> - = note: `#[warn(private_macro_use)]` on by default + = note: `#[deny(private_macro_use)]` on by default -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0469`. +Future incompatibility report: Future breakage diagnostic: +error: macro `foo` is private + --> $DIR/issue-80074.rs:13:5 + | +LL | foo!(); + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120192 <https://github.com/rust-lang/rust/issues/120192> + = note: `#[deny(private_macro_use)]` on by default + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 8bac1f6155e..f2ae50b75a3 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -361,12 +361,6 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 - | -LL | #![should_panic] - | ^^^^^^^^^^^^^^^^ - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | @@ -409,6 +403,12 @@ warning: `#[proc_macro_derive]` only has an effect on functions LL | #![proc_macro_derive(Test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `#[should_panic]` only has an effect on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + | +LL | #![should_panic] + | ^^^^^^^^^^^^^^^^ + warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | diff --git a/tests/ui/imports/local-modularized-tricky-fail-2.stderr b/tests/ui/imports/local-modularized-tricky-fail-2.stderr index 49f5c72947f..ea4056b3d75 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-2.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-2.stderr @@ -41,3 +41,47 @@ LL | define_exported!(); error: aborting due to 2 previous errors +Future incompatibility report: Future breakage diagnostic: +error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + --> $DIR/local-modularized-tricky-fail-2.rs:13:9 + | +LL | use crate::exported; + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234> +note: the macro is defined here + --> $DIR/local-modularized-tricky-fail-2.rs:5:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------ in this macro invocation + = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default + = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + --> $DIR/local-modularized-tricky-fail-2.rs:19:5 + | +LL | crate::exported!(); + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234> +note: the macro is defined here + --> $DIR/local-modularized-tricky-fail-2.rs:5:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------ in this macro invocation + = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default + = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs index 05fbfec2ae5..8ec70a17864 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs @@ -1,9 +1,8 @@ -//@ check-pass -// Ensure that trailing semicolons cause warnings by default +// Ensure that trailing semicolons cause errors by default macro_rules! foo { () => { - true; //~ WARN trailing semicolon in macro + true; //~ ERROR trailing semicolon in macro //~| WARN this was previously } } diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr index 0fec4996f1a..99cdcafab39 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr @@ -1,5 +1,5 @@ -warning: trailing semicolon in macro used in expression position - --> $DIR/warn-semicolon-in-expressions-from-macros.rs:6:13 +error: trailing semicolon in macro used in expression position + --> $DIR/warn-semicolon-in-expressions-from-macros.rs:5:13 | LL | true; | ^ @@ -9,14 +9,14 @@ LL | _ => foo!() | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 1 warning emitted +error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: -warning: trailing semicolon in macro used in expression position - --> $DIR/warn-semicolon-in-expressions-from-macros.rs:6:13 +error: trailing semicolon in macro used in expression position + --> $DIR/warn-semicolon-in-expressions-from-macros.rs:5:13 | LL | true; | ^ @@ -26,6 +26,6 @@ LL | _ => foo!() | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index e277f5203c6..6c44e884ba5 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -16,19 +16,6 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:55:1 - | -LL | #[should_panic(expected = "values don't match")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:54:1 - | -LL | #[should_panic] - | ^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -error: unused attribute --> $DIR/unused-attr-duplicate.rs:14:1 | LL | #![crate_name = "unused_attr_duplicate2"] @@ -154,6 +141,19 @@ LL | #[ignore] | ^^^^^^^^^ error: unused attribute + --> $DIR/unused-attr-duplicate.rs:55:1 + | +LL | #[should_panic(expected = "values don't match")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:54:1 + | +LL | #[should_panic] + | ^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: unused attribute --> $DIR/unused-attr-duplicate.rs:60:1 | LL | #[must_use = "some message"] diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs index 78b861f1df1..25fa91062c4 100644 --- a/tests/ui/macros/lint-trailing-macro-call.rs +++ b/tests/ui/macros/lint-trailing-macro-call.rs @@ -1,12 +1,10 @@ -//@ check-pass -// // Ensures that we properly lint // a removed 'expression' resulting from a macro // in trailing expression position macro_rules! expand_it { () => { - #[cfg(false)] 25; //~ WARN trailing semicolon in macro + #[cfg(false)] 25; //~ ERROR trailing semicolon in macro //~| WARN this was previously } } diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr index 223b85e112e..3fd1ea81345 100644 --- a/tests/ui/macros/lint-trailing-macro-call.stderr +++ b/tests/ui/macros/lint-trailing-macro-call.stderr @@ -1,5 +1,5 @@ -warning: trailing semicolon in macro used in expression position - --> $DIR/lint-trailing-macro-call.rs:9:25 +error: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:7:25 | LL | #[cfg(false)] 25; | ^ @@ -11,14 +11,14 @@ LL | expand_it!() = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> = note: macro invocations at the end of a block are treated as expressions = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 1 warning emitted +error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: -warning: trailing semicolon in macro used in expression position - --> $DIR/lint-trailing-macro-call.rs:9:25 +error: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:7:25 | LL | #[cfg(false)] 25; | ^ @@ -30,6 +30,6 @@ LL | expand_it!() = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> = note: macro invocations at the end of a block are treated as expressions = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs index a31470263a0..e1c24ba8b57 100644 --- a/tests/ui/macros/macro-context.rs +++ b/tests/ui/macros/macro-context.rs @@ -6,7 +6,7 @@ macro_rules! m { //~| ERROR macro expansion ignores `;` //~| ERROR cannot find type `i` in this scope //~| ERROR cannot find value `i` in this scope - //~| WARN trailing semicolon in macro + //~| ERROR trailing semicolon in macro //~| WARN this was previously } diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index 4820a43f00c..6b49c05f360 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -64,7 +64,7 @@ LL | let i = m!(); | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: trailing semicolon in macro used in expression position +error: trailing semicolon in macro used in expression position --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); @@ -75,15 +75,15 @@ LL | let i = m!(); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 7 previous errors Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. Future incompatibility report: Future breakage diagnostic: -warning: trailing semicolon in macro used in expression position +error: trailing semicolon in macro used in expression position --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); @@ -94,6 +94,6 @@ LL | let i = m!(); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed index 7c830707ffd..52e1b429e48 100644 --- a/tests/ui/macros/macro-in-expression-context.fixed +++ b/tests/ui/macros/macro-in-expression-context.fixed @@ -3,12 +3,12 @@ macro_rules! foo { () => { assert_eq!("A", "A"); - //~^ WARN trailing semicolon in macro + //~^ ERROR trailing semicolon in macro //~| WARN this was previously //~| NOTE macro invocations at the end of a block //~| NOTE to ignore the value produced by the macro //~| NOTE for more information - //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default + //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs index da95017aa5f..5c560e78dad 100644 --- a/tests/ui/macros/macro-in-expression-context.rs +++ b/tests/ui/macros/macro-in-expression-context.rs @@ -3,12 +3,12 @@ macro_rules! foo { () => { assert_eq!("A", "A"); - //~^ WARN trailing semicolon in macro + //~^ ERROR trailing semicolon in macro //~| WARN this was previously //~| NOTE macro invocations at the end of a block //~| NOTE to ignore the value produced by the macro //~| NOTE for more information - //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default + //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr index 43419f2678c..b04348d7010 100644 --- a/tests/ui/macros/macro-in-expression-context.stderr +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -13,7 +13,7 @@ help: you might be missing a semicolon here LL | foo!(); | + -warning: trailing semicolon in macro used in expression position +error: trailing semicolon in macro used in expression position --> $DIR/macro-in-expression-context.rs:5:29 | LL | assert_eq!("A", "A"); @@ -26,13 +26,13 @@ LL | foo!() = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> = note: macro invocations at the end of a block are treated as expressions = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors Future incompatibility report: Future breakage diagnostic: -warning: trailing semicolon in macro used in expression position +error: trailing semicolon in macro used in expression position --> $DIR/macro-in-expression-context.rs:5:29 | LL | assert_eq!("A", "A"); @@ -45,6 +45,6 @@ LL | foo!() = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> = note: macro invocations at the end of a block are treated as expressions = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` - = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default - = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/methods/issues/issue-105732.stderr b/tests/ui/methods/issues/issue-105732.stderr index 6244f983550..93ce695f27b 100644 --- a/tests/ui/methods/issues/issue-105732.stderr +++ b/tests/ui/methods/issues/issue-105732.stderr @@ -4,7 +4,7 @@ error[E0380]: auto traits cannot have associated items LL | auto trait Foo { | --- auto traits cannot have associated items LL | fn g(&self); - | ---^-------- help: remove these associated items + | ^ error[E0599]: no method named `g` found for reference `&Self` in the current scope --> $DIR/issue-105732.rs:10:14 diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs index 1555da2fd1f..dd23acfa235 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs +++ b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.rs @@ -1,16 +1,15 @@ -//@ known-bug: unknown +//@ run-pass #![allow(unused)] struct A(u32); pub fn main() { - // The or-pattern bindings are lowered after `x`, which triggers the error. + // Bindings are lowered in the order they appear syntactically, so this works. let x @ (A(a) | A(a)) = A(10); - // ERROR: use of moved value assert!(x.0 == 10); assert!(a == 10); - // This works. + // This also works. let (x @ A(a) | x @ A(a)) = A(10); assert!(x.0 == 10); assert!(a == 10); diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr b/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr deleted file mode 100644 index 79808186358..00000000000 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy-or-pat.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0382]: use of moved value - --> $DIR/bind-by-copy-or-pat.rs:8:16 - | -LL | let x @ (A(a) | A(a)) = A(10); - | - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait - | | | - | | value used here after move - | value moved here - | -help: borrow this binding in the pattern to avoid moving the value - | -LL | let ref x @ (A(a) | A(a)) = A(10); - | +++ - -error[E0382]: use of moved value - --> $DIR/bind-by-copy-or-pat.rs:8:23 - | -LL | let x @ (A(a) | A(a)) = A(10); - | - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait - | | | - | | value used here after move - | value moved here - | -help: borrow this binding in the pattern to avoid moving the value - | -LL | let ref x @ (A(a) | A(a)) = A(10); - | +++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/proc-macro/derive-helper-shadowing.rs b/tests/ui/proc-macro/derive-helper-shadowing.rs index e774e464053..ee883be3352 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.rs +++ b/tests/ui/proc-macro/derive-helper-shadowing.rs @@ -17,7 +17,7 @@ macro_rules! gen_helper_use { } #[empty_helper] //~ ERROR `empty_helper` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[derive(Empty)] struct S { diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index 1206778bb23..65989375ab5 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -58,7 +58,7 @@ LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/derive-helper-shadowing.rs:19:3 | LL | #[empty_helper] @@ -69,8 +69,22 @@ LL | #[derive(Empty)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> - = note: `#[warn(legacy_derive_helpers)]` on by default + = note: `#[deny(legacy_derive_helpers)]` on by default -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0659`. +Future incompatibility report: Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/derive-helper-shadowing.rs:19:3 + | +LL | #[empty_helper] + | ^^^^^^^^^^^^ +... +LL | #[derive(Empty)] + | ----- the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + diff --git a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs index 1197dd7f3bf..97c81e9945d 100644 --- a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs +++ b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs @@ -5,7 +5,7 @@ extern crate test_macros; use test_macros::empty_attr as empty_helper; #[empty_helper] //~ ERROR `empty_helper` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[derive(Empty)] struct S; diff --git a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr index 1c12a2804c6..df7951464fb 100644 --- a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr +++ b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr @@ -17,7 +17,7 @@ LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3 | LL | #[empty_helper] @@ -28,8 +28,22 @@ LL | #[derive(Empty)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> - = note: `#[warn(legacy_derive_helpers)]` on by default + = note: `#[deny(legacy_derive_helpers)]` on by default -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. +Future incompatibility report: Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3 + | +LL | #[empty_helper] + | ^^^^^^^^^^^^ +... +LL | #[derive(Empty)] + | ----- the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs index f0851b31e9c..e8df1a66dd9 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs @@ -6,7 +6,7 @@ // Tests that we cfg-strip all targets before invoking // a derive macro // FIXME: We currently lose spans here (see issue #43081) - +#![warn(legacy_derive_helpers)] #![no_std] // Don't load unnecessary hygiene information from std extern crate std; diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr index df1e36d7390..906e9c6bf69 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr @@ -9,7 +9,11 @@ LL | #[derive(Print)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> - = note: `#[warn(legacy_derive_helpers)]` on by default +note: the lint level is defined here + --> $DIR/issue-75930-derive-cfg.rs:9:9 + | +LL | #![warn(legacy_derive_helpers)] + | ^^^^^^^^^^^^^^^^^^^^^ warning: derive helper attribute is used before it is introduced --> $DIR/issue-75930-derive-cfg.rs:46:3 @@ -26,3 +30,39 @@ LL | #[derive(Print)] warning: 2 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: derive helper attribute is used before it is introduced + --> $DIR/issue-75930-derive-cfg.rs:46:3 + | +LL | #[print_helper(a)] + | ^^^^^^^^^^^^ +... +LL | #[derive(Print)] + | ----- the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> +note: the lint level is defined here + --> $DIR/issue-75930-derive-cfg.rs:9:9 + | +LL | #![warn(legacy_derive_helpers)] + | ^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: derive helper attribute is used before it is introduced + --> $DIR/issue-75930-derive-cfg.rs:46:3 + | +LL | #[print_helper(a)] + | ^^^^^^^^^^^^ +... +LL | #[derive(Print)] + | ----- the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> +note: the lint level is defined here + --> $DIR/issue-75930-derive-cfg.rs:9:9 + | +LL | #![warn(legacy_derive_helpers)] + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/proc-macro/proc-macro-attributes.rs b/tests/ui/proc-macro/proc-macro-attributes.rs index 455fcc56e58..f1270b896aa 100644 --- a/tests/ui/proc-macro/proc-macro-attributes.rs +++ b/tests/ui/proc-macro/proc-macro-attributes.rs @@ -4,17 +4,17 @@ extern crate derive_b; #[B] //~ ERROR `B` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[C] //~ ERROR cannot find attribute `C` in this scope #[B(D)] //~ ERROR `B` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[B(E = "foo")] //~ ERROR `B` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous - //~| WARN derive helper attribute is used before it is introduced + //~| ERROR derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[derive(B)] struct B; diff --git a/tests/ui/proc-macro/proc-macro-attributes.stderr b/tests/ui/proc-macro/proc-macro-attributes.stderr index 140d8790690..2cc57383eb3 100644 --- a/tests/ui/proc-macro/proc-macro-attributes.stderr +++ b/tests/ui/proc-macro/proc-macro-attributes.stderr @@ -76,7 +76,7 @@ note: `B` could also refer to the derive macro imported here LL | #[macro_use] | ^^^^^^^^^^^^ -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/proc-macro-attributes.rs:6:3 | LL | #[B] @@ -87,9 +87,9 @@ LL | #[derive(B)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> - = note: `#[warn(legacy_derive_helpers)]` on by default + = note: `#[deny(legacy_derive_helpers)]` on by default -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/proc-macro-attributes.rs:10:3 | LL | #[B(D)] @@ -101,7 +101,7 @@ LL | #[derive(B)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/proc-macro-attributes.rs:13:3 | LL | #[B(E = "foo")] @@ -113,7 +113,7 @@ LL | #[derive(B)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> -warning: derive helper attribute is used before it is introduced +error: derive helper attribute is used before it is introduced --> $DIR/proc-macro-attributes.rs:16:3 | LL | #[B(arbitrary tokens)] @@ -125,6 +125,62 @@ LL | #[derive(B)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> -error: aborting due to 5 previous errors; 4 warnings emitted +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0659`. +Future incompatibility report: Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/proc-macro-attributes.rs:6:3 + | +LL | #[B] + | ^ +... +LL | #[derive(B)] + | - the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + +Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/proc-macro-attributes.rs:10:3 + | +LL | #[B(D)] + | ^ +... +LL | #[derive(B)] + | - the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + +Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/proc-macro-attributes.rs:13:3 + | +LL | #[B(E = "foo")] + | ^ +... +LL | #[derive(B)] + | - the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + +Future breakage diagnostic: +error: derive helper attribute is used before it is introduced + --> $DIR/proc-macro-attributes.rs:16:3 + | +LL | #[B(arbitrary tokens)] + | ^ +... +LL | #[derive(B)] + | - the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + = note: `#[deny(legacy_derive_helpers)]` on by default + diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 9244a98d82f..81ed8b3de76 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -6,6 +6,7 @@ // gate-test-arm_target_feature // gate-test-hexagon_target_feature // gate-test-mips_target_feature +// gate-test-nvptx_target_feature // gate-test-wasm_target_feature // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index 32d60ce4382..3e9374be73d 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `x87` is currently unstable - --> $DIR/gate.rs:29:18 + --> $DIR/gate.rs:30:18 | LL | #[target_feature(enable = "x87")] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/implied-features-nvptx.rs b/tests/ui/target-feature/implied-features-nvptx.rs new file mode 100644 index 00000000000..1550c99f67a --- /dev/null +++ b/tests/ui/target-feature/implied-features-nvptx.rs @@ -0,0 +1,28 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_80 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 +//@ build-pass +#![no_std] +#![allow(dead_code)] + +#[panic_handler] +pub fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +// -Ctarget-cpu=sm_80 directly enables sm_80 and ptx70 +#[cfg(not(all(target_feature = "sm_80", target_feature = "ptx70")))] +compile_error!("direct target features not enabled"); + +// -Ctarget-cpu=sm_80 implies all earlier sm_* and ptx* features. +#[cfg(not(all( + target_feature = "sm_60", + target_feature = "sm_70", + target_feature = "ptx50", + target_feature = "ptx60", +)))] +compile_error!("implied target features not enabled"); + +// -Ctarget-cpu=sm_80 implies all earlier sm_* and ptx* features. +#[cfg(target_feature = "ptx71")] +compile_error!("sm_80 requires only ptx70, but ptx71 enabled"); diff --git a/tests/ui/test-attrs/test-should-panic-attr.rs b/tests/ui/test-attrs/test-should-panic-attr.rs index df2893b63ed..af54689551c 100644 --- a/tests/ui/test-attrs/test-should-panic-attr.rs +++ b/tests/ui/test-attrs/test-should-panic-attr.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ compile-flags: --test #[test] @@ -9,28 +8,32 @@ fn test1() { #[test] #[should_panic(expected)] -//~^ WARN: argument must be of the form: +//~^ ERROR malformed `should_panic` attribute input +//~| NOTE expected this to be of the form `expected = "..."` fn test2() { panic!(); } #[test] #[should_panic(expect)] -//~^ WARN: argument must be of the form: +//~^ ERROR malformed `should_panic` attribute input +//~| NOTE the only valid argument here is "expected" fn test3() { panic!(); } #[test] #[should_panic(expected(foo, bar))] -//~^ WARN: argument must be of the form: +//~^ ERROR malformed `should_panic` attribute input +//~| NOTE expected this to be of the form `expected = "..."` fn test4() { panic!(); } #[test] #[should_panic(expected = "foo", bar)] -//~^ WARN: argument must be of the form: +//~^ ERROR malformed `should_panic` attribute input +//~| NOTE expected a single argument here fn test5() { panic!(); } diff --git a/tests/ui/test-attrs/test-should-panic-attr.stderr b/tests/ui/test-attrs/test-should-panic-attr.stderr index 492d1d5e03a..5dfc8e503e8 100644 --- a/tests/ui/test-attrs/test-should-panic-attr.stderr +++ b/tests/ui/test-attrs/test-should-panic-attr.stderr @@ -1,34 +1,82 @@ -warning: argument must be of the form: `expected = "error message"` - --> $DIR/test-should-panic-attr.rs:11:1 +error[E0539]: malformed `should_panic` attribute input + --> $DIR/test-should-panic-attr.rs:10:1 | LL | #[should_panic(expected)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^--------^^ + | | + | expected this to be of the form `expected = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[should_panic(expected)] +LL + #[should_panic = "reason"] + | +LL | #[should_panic(expected = "reason")] + | ++++++++++ +LL - #[should_panic(expected)] +LL + #[should_panic] | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release -warning: argument must be of the form: `expected = "error message"` +error[E0539]: malformed `should_panic` attribute input --> $DIR/test-should-panic-attr.rs:18:1 | LL | #[should_panic(expect)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^--------^ + | | + | the only valid argument here is "expected" + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[should_panic(expect)] +LL + #[should_panic = "reason"] + | +LL | #[should_panic(expected = "reason")] + | +++++++++++++ +LL - #[should_panic(expect)] +LL + #[should_panic] | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release -warning: argument must be of the form: `expected = "error message"` - --> $DIR/test-should-panic-attr.rs:25:1 +error[E0539]: malformed `should_panic` attribute input + --> $DIR/test-should-panic-attr.rs:26:1 | LL | #[should_panic(expected(foo, bar))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^------------------^^ + | | + | expected this to be of the form `expected = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[should_panic(expected(foo, bar))] +LL + #[should_panic = "reason"] + | +LL - #[should_panic(expected(foo, bar))] +LL + #[should_panic(expected = "reason")] + | +LL - #[should_panic(expected(foo, bar))] +LL + #[should_panic] | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release -warning: argument must be of the form: `expected = "error message"` - --> $DIR/test-should-panic-attr.rs:32:1 +error[E0805]: malformed `should_panic` attribute input + --> $DIR/test-should-panic-attr.rs:34:1 | LL | #[should_panic(expected = "foo", bar)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^-----------------------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[should_panic(expected = "foo", bar)] +LL + #[should_panic = "reason"] + | +LL - #[should_panic(expected = "foo", bar)] +LL + #[should_panic(expected = "reason")] + | +LL - #[should_panic(expected = "foo", bar)] +LL + #[should_panic] | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release -warning: 4 warnings emitted +error: aborting due to 4 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr index 3a3b99f6c5b..45602d676b3 100644 --- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr +++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr @@ -1,8 +1,8 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds - --> $DIR/supertrait-auto-trait.rs:8:17 + --> $DIR/supertrait-auto-trait.rs:8:19 | LL | auto trait Magic: Copy {} - | -----^^^^^^ help: remove the super traits or lifetime bounds + | ----- ^^^^ | | | auto traits cannot have super traits or lifetime bounds diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs index 9381cb82578..6a9f772e542 100644 --- a/tests/ui/type/type-name-basic.rs +++ b/tests/ui/type/type-name-basic.rs @@ -6,12 +6,85 @@ #![allow(dead_code)] use std::any::type_name; +use std::borrow::Cow; -struct Foo<T> { - x: T, +struct Foo<T>(T); + +struct Bar<'a>(&'a u32); + +struct Baz<'a, T>(&'a T); + +trait TrL<'a> {} +trait TrLA<'a> { + type A; +} +trait TrLT<'a, T> {} +trait TrLTA<'a, T> { + type A; +} + +macro_rules! t { + ($ty:ty, $str:literal) => { + assert_eq!(type_name::<$ty>(), $str); + } } pub fn main() { - assert_eq!(type_name::<isize>(), "isize"); - assert_eq!(type_name::<Foo<usize>>(), "type_name_basic::Foo<usize>"); + t!(bool, "bool"); + t!(char, "char"); + + t!(u8, "u8"); + t!(u16, "u16"); + t!(u32, "u32"); + t!(u64, "u64"); + t!(u128, "u128"); + t!(usize, "usize"); + + t!(i8, "i8"); + t!(i16, "i16"); + t!(i32, "i32"); + t!(i64, "i64"); + t!(i128, "i128"); + t!(isize, "isize"); + + t!(String, "alloc::string::String"); + t!(str, "str"); + t!(&str, "&str"); + t!(&'static str, "&str"); + + t!((u16, u32, u64), "(u16, u32, u64)"); + t!([usize; 4], "[usize; 4]"); + t!([usize], "[usize]"); + t!(&[usize], "&[usize]"); + + t!(*const bool, "*const bool"); + t!(*mut u64, "*mut u64"); + + t!(Vec<Vec<u32>>, "alloc::vec::Vec<alloc::vec::Vec<u32>>"); + t!(Foo<usize>, "type_name_basic::Foo<usize>"); + t!(Bar<'static>, "type_name_basic::Bar"); + t!(Baz<'static, u32>, "type_name_basic::Baz<u32>"); + + // FIXME: lifetime omission means these all print badly. + t!(dyn TrL<'static>, "dyn type_name_basic::TrL<>"); + t!(dyn TrLA<'static, A = u32>, "dyn type_name_basic::TrLA<, A = u32>"); + t!( + dyn TrLT<'static, Cow<'static, ()>>, + "dyn type_name_basic::TrLT<, alloc::borrow::Cow<()>>" + ); + t!( + dyn TrLTA<'static, u32, A = Cow<'static, ()>>, + "dyn type_name_basic::TrLTA<, u32, A = alloc::borrow::Cow<()>>" + ); + + t!(fn(i32) -> i32, "fn(i32) -> i32"); + t!(dyn for<'a> Fn(&'a u32), "dyn core::ops::function::Fn(&u32)"); + + struct S<'a, T>(&'a T); + impl<'a, T: Clone> S<'a, T> { + fn test() { + t!(Cow<'a, T>, "alloc::borrow::Cow<u32>"); + } + } + S::<u32>::test(); } |
