From 049bb266873ff98ce8219c7d2d5d56c7cbe3eaf3 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 23 Mar 2025 22:50:28 +0000 Subject: [PATCH 001/109] Add target-specific NaN payloads for the missing tier 2 targets --- library/core/src/primitive_docs.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 89c856fe1074..6c59e71194b4 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1309,10 +1309,12 @@ mod prim_f16 {} // FIXME: Is there a better place to put this? /// /// | `target_arch` | Extra payloads possible on this platform | -/// |---------------|---------| -/// | `x86`, `x86_64`, `arm`, `aarch64`, `riscv32`, `riscv64` | None | +/// |---------------|------------------------------------------| +// Sorted alphabetically +/// | `aarch64`, `arm`, `arm64ec`, `loongarch64`, `powerpc` (except when `target_abi = "spe"`), `powerpc64`, `riscv32`, `riscv64`, `s390x`, `x86`, `x86_64` | None | +/// | `nvptx64` | All payloads | /// | `sparc`, `sparc64` | The all-one payload | -/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.
Otherwise: all possible payloads. | +/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.
Otherwise: all payloads. | /// /// For targets not in this table, all payloads are possible. From 199ee4084349361ae44c6e4b0cbc9a5e72913b20 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:48:12 +0100 Subject: [PATCH 002/109] Move errors --- .../src/error_reporting/traits/mod.rs | 1 + .../traits/on_unimplemented.rs | 79 +---------------- .../traits/on_unimplemented_format.rs | 86 +++++++++++++++++++ 3 files changed, 89 insertions(+), 77 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 8ff7030717a8..7fd1c0d2743b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -2,6 +2,7 @@ pub mod ambiguity; pub mod call_kind; mod fulfillment_errors; pub mod on_unimplemented; +pub mod on_unimplemented_format; mod overflow; pub mod suggestions; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index f0c6e51f2a4c..9914e828a933 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -7,18 +7,18 @@ use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; -use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, kw, sym}; use tracing::{debug, info}; use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; +use crate::error_reporting::traits::on_unimplemented_format::errors::*; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; @@ -320,81 +320,6 @@ pub enum AppendConstMessage { Custom(Symbol, Span), } -#[derive(LintDiagnostic)] -#[diag(trait_selection_malformed_on_unimplemented_attr)] -#[help] -pub struct MalformedOnUnimplementedAttrLint { - #[label] - pub span: Span, -} - -impl MalformedOnUnimplementedAttrLint { - fn new(span: Span) -> Self { - Self { span } - } -} - -#[derive(LintDiagnostic)] -#[diag(trait_selection_missing_options_for_on_unimplemented_attr)] -#[help] -pub struct MissingOptionsForOnUnimplementedAttr; - -#[derive(LintDiagnostic)] -#[diag(trait_selection_ignored_diagnostic_option)] -pub struct IgnoredDiagnosticOption { - pub option_name: &'static str, - #[label] - pub span: Span, - #[label(trait_selection_other_label)] - pub prev_span: Span, -} - -impl IgnoredDiagnosticOption { - fn maybe_emit_warning<'tcx>( - tcx: TyCtxt<'tcx>, - item_def_id: DefId, - new: Option, - old: Option, - option_name: &'static str, - ) { - if let (Some(new_item), Some(old_item)) = (new, old) { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - new_item, - IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, - ); - } - } - } -} - -#[derive(LintDiagnostic)] -#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] -#[help] -pub struct UnknownFormatParameterForOnUnimplementedAttr { - argument_name: Symbol, - trait_name: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(trait_selection_disallowed_positional_argument)] -#[help] -pub struct DisallowedPositionalArgument; - -#[derive(LintDiagnostic)] -#[diag(trait_selection_invalid_format_specifier)] -#[help] -pub struct InvalidFormatSpecifier; - -#[derive(LintDiagnostic)] -#[diag(trait_selection_wrapped_parser_error)] -pub struct WrappedParserError { - description: String, - label: String, -} - impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs new file mode 100644 index 000000000000..40a47921fc11 --- /dev/null +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -0,0 +1,86 @@ +pub mod errors { + use rustc_macros::LintDiagnostic; + use rustc_middle::ty::TyCtxt; + use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; + use rustc_span::Ident; + + use super::*; + + #[derive(LintDiagnostic)] + #[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] + #[help] + pub struct UnknownFormatParameterForOnUnimplementedAttr { + pub argument_name: Symbol, + pub trait_name: Ident, + } + + #[derive(LintDiagnostic)] + #[diag(trait_selection_disallowed_positional_argument)] + #[help] + pub struct DisallowedPositionalArgument; + + #[derive(LintDiagnostic)] + #[diag(trait_selection_invalid_format_specifier)] + #[help] + pub struct InvalidFormatSpecifier; + + #[derive(LintDiagnostic)] + #[diag(trait_selection_wrapped_parser_error)] + pub struct WrappedParserError { + pub description: String, + pub label: String, + } + #[derive(LintDiagnostic)] + #[diag(trait_selection_malformed_on_unimplemented_attr)] + #[help] + pub struct MalformedOnUnimplementedAttrLint { + #[label] + pub span: Span, + } + + impl MalformedOnUnimplementedAttrLint { + pub fn new(span: Span) -> Self { + Self { span } + } + } + + #[derive(LintDiagnostic)] + #[diag(trait_selection_missing_options_for_on_unimplemented_attr)] + #[help] + pub struct MissingOptionsForOnUnimplementedAttr; + + #[derive(LintDiagnostic)] + #[diag(trait_selection_ignored_diagnostic_option)] + pub struct IgnoredDiagnosticOption { + pub option_name: &'static str, + #[label] + pub span: Span, + #[label(trait_selection_other_label)] + pub prev_span: Span, + } + + impl IgnoredDiagnosticOption { + pub fn maybe_emit_warning<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + new: Option, + old: Option, + option_name: &'static str, + ) { + if let (Some(new_item), Some(old_item)) = (new, old) { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + new_item, + IgnoredDiagnosticOption { + span: new_item, + prev_span: old_item, + option_name, + }, + ); + } + } + } + } +} From 2007c8994db6d46533f84f4697fea5734c6df53d Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 27 Mar 2025 15:39:23 +0100 Subject: [PATCH 003/109] Write the format string parserand split it from conditions parser --- compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/mod.rs | 1 + .../traits/on_unimplemented.rs | 399 ++++++------------ .../traits/on_unimplemented_condition.rs | 64 +++ .../traits/on_unimplemented_format.rs | 344 +++++++++++++++ .../on_unimplemented/broken_format.stderr | 48 +-- ...ons_of_the_internal_rustc_attribute.stderr | 80 ++-- ...t_fail_parsing_on_invalid_options_1.stderr | 8 +- tests/ui/on-unimplemented/bad-annotation.rs | 4 +- .../ui/on-unimplemented/bad-annotation.stderr | 22 +- tests/ui/on-unimplemented/impl-substs.stderr | 2 +- 11 files changed, 613 insertions(+), 360 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 31847ae3b465..0c458db0b23d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -372,6 +372,7 @@ symbols! { SyncUnsafeCell, T, Target, + This, ToOwned, ToString, TokenStream, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 7fd1c0d2743b..78f9287b407b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -2,6 +2,7 @@ pub mod ambiguity; pub mod call_kind; mod fulfillment_errors; pub mod on_unimplemented; +pub mod on_unimplemented_condition; pub mod on_unimplemented_format; mod overflow; pub mod suggestions; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 9914e828a933..6a7f32234213 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -1,7 +1,7 @@ use std::iter; use std::path::PathBuf; -use rustc_ast::MetaItemInner; +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; @@ -10,35 +10,21 @@ use rustc_hir::{AttrArgs, Attribute}; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; -use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; +use crate::error_reporting::traits::on_unimplemented_condition::Condition; use crate::error_reporting::traits::on_unimplemented_format::errors::*; +use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatString}; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; use crate::infer::InferCtxtExt; -/// The symbols which are always allowed in a format string -static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ - kw::SelfUpper, - sym::ItemContext, - sym::from_desugaring, - sym::direct, - sym::cause, - sym::integral, - sym::integer_, - sym::float, - sym::_Self, - sym::crate_local, - sym::Trait, -]; - impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, @@ -275,6 +261,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } })); + flags.push((sym::This, Some(self.tcx.def_path_str(trait_pred.trait_ref.def_id)))); + if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file) } else { @@ -283,19 +271,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } +/// Represents a format string in a on_unimplemented attribute, +/// like the "content" in `#[diagnostic::on_unimplemented(message = "content")]` #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString { - symbol: Symbol, - span: Span, - is_diagnostic_namespace_variant: bool, + /// Symbol of the format string, i.e. `"content"` + pub symbol: Symbol, + ///The span of the format string, i.e. `"content"` + pub span: Span, + pub is_diagnostic_namespace_variant: bool, } #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, + pub condition: Option, pub subcommands: Vec, - pub message: Option, - pub label: Option, + pub message: Option<(Span, OnUnimplementedFormatString)>, + pub label: Option<(Span, OnUnimplementedFormatString)>, pub notes: Vec, pub parent_label: Option, pub append_const_msg: Option, @@ -332,12 +324,12 @@ impl<'tcx> OnUnimplementedDirective { let mut errored = None; let mut item_iter = items.iter(); - let parse_value = |value_str, value_span| { + let parse_value = |value_str, span| { OnUnimplementedFormatString::try_parse( tcx, item_def_id, value_str, - value_span, + span, is_diagnostic_namespace_variant, ) .map(Some) @@ -359,7 +351,7 @@ impl<'tcx> OnUnimplementedDirective { } true }); - Some(cond.clone()) + Some(Condition { inner: cond.clone() }) }; let mut message = None; @@ -369,24 +361,36 @@ impl<'tcx> OnUnimplementedDirective { let mut subcommands = vec![]; let mut append_const_msg = None; + let get_value_and_span = |item: &_, key| { + if let MetaItemInner::MetaItem(MetaItem { + path, + kind: MetaItemKind::NameValue(MetaItemLit { span, kind: LitKind::Str(s, _), .. }), + .. + }) = item + && *path == key + { + Some((*s, *span)) + } else { + None + } + }; + for item in item_iter { - if item.has_name(sym::message) && message.is_none() { - if let Some(message_) = item.value_str() { - message = parse_value(message_, item.span())?; + if let Some((message_, span)) = get_value_and_span(item, sym::message) + && message.is_none() + { + message = parse_value(message_, span)?.map(|l| (item.span(), l)); + continue; + } else if let Some((label_, span)) = get_value_and_span(item, sym::label) + && label.is_none() + { + label = parse_value(label_, span)?.map(|l| (item.span(), l)); + continue; + } else if let Some((note_, span)) = get_value_and_span(item, sym::note) { + if let Some(note) = parse_value(note_, span)? { + notes.push(note); continue; } - } else if item.has_name(sym::label) && label.is_none() { - if let Some(label_) = item.value_str() { - label = parse_value(label_, item.span())?; - continue; - } - } else if item.has_name(sym::note) { - if let Some(note_) = item.value_str() { - if let Some(note) = parse_value(note_, item.span())? { - notes.push(note); - continue; - } - } } else if item.has_name(sym::parent_label) && parent_label.is_none() && !is_diagnostic_namespace_variant @@ -479,15 +483,15 @@ impl<'tcx> OnUnimplementedDirective { IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.message.as_ref().map(|f| f.span), - aggr.message.as_ref().map(|f| f.span), + directive.message.as_ref().map(|f| f.0), + aggr.message.as_ref().map(|f| f.0), "message", ); IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.label.as_ref().map(|f| f.span), - aggr.label.as_ref().map(|f| f.span), + directive.label.as_ref().map(|f| f.0), + aggr.label.as_ref().map(|f| f.0), "label", ); IgnoredDiagnosticOption::maybe_emit_warning( @@ -561,13 +565,16 @@ impl<'tcx> OnUnimplementedDirective { condition: None, message: None, subcommands: vec![], - label: Some(OnUnimplementedFormatString::try_parse( - tcx, - item_def_id, - value, + label: Some(( attr.span(), - is_diagnostic_namespace_variant, - )?), + OnUnimplementedFormatString::try_parse( + tcx, + item_def_id, + value, + attr.value_span().unwrap_or(attr.span()), + is_diagnostic_namespace_variant, + )?, + )), notes: Vec::new(), parent_label: None, append_const_msg: None, @@ -643,27 +650,7 @@ impl<'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { debug!(?command); if let Some(ref condition) = command.condition - && !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| { - let value = cfg.value.map(|v| { - // `with_no_visible_paths` is also used when generating the options, - // so we need to match it here. - ty::print::with_no_visible_paths!( - OnUnimplementedFormatString { - symbol: v, - span: cfg.span, - is_diagnostic_namespace_variant: false - } - .format( - tcx, - trait_ref, - &options_map, - long_ty_file - ) - ) - }); - - options.contains(&(cfg.name, value)) - }) + && !condition.matches_predicate(tcx, options, &options_map) { debug!("evaluate: skipping {:?} due to condition", command); continue; @@ -687,8 +674,8 @@ impl<'tcx> OnUnimplementedDirective { } OnUnimplementedNote { - label: label.map(|l| l.format(tcx, trait_ref, &options_map, long_ty_file)), - message: message.map(|m| m.format(tcx, trait_ref, &options_map, long_ty_file)), + label: label.map(|l| l.1.format(tcx, trait_ref, &options_map, long_ty_file)), + message: message.map(|m| m.1.format(tcx, trait_ref, &options_map, long_ty_file)), notes: notes .into_iter() .map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file)) @@ -705,144 +692,65 @@ impl<'tcx> OnUnimplementedFormatString { tcx: TyCtxt<'tcx>, item_def_id: DefId, from: Symbol, - value_span: Span, + span: Span, is_diagnostic_namespace_variant: bool, ) -> Result { - let result = OnUnimplementedFormatString { - symbol: from, - span: value_span, - is_diagnostic_namespace_variant, - }; + let result = + OnUnimplementedFormatString { symbol: from, span, is_diagnostic_namespace_variant }; result.verify(tcx, item_def_id)?; Ok(result) } fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> { - let trait_def_id = if tcx.is_trait(item_def_id) { - item_def_id + let trait_def_id = if tcx.is_trait(item_def_id) { item_def_id } else { return Ok(()) }; + + let ctx = if self.is_diagnostic_namespace_variant { + Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id } } else { - tcx.trait_id_of_impl(item_def_id) - .expect("expected `on_unimplemented` to correspond to a trait") + Ctx::RustcOnUnimplemented { tcx, trait_def_id } }; - let trait_name = tcx.item_ident(trait_def_id); - let generics = tcx.generics_of(item_def_id); - let s = self.symbol.as_str(); - let mut parser = Parser::new(s, None, None, false, ParseMode::Format); + let mut result = Ok(()); - for token in &mut parser { - match token { - Piece::Lit(_) => (), // Normal string, no need to check it - Piece::NextArgument(a) => { - let format_spec = a.format; - if self.is_diagnostic_namespace_variant - && (format_spec.ty_span.is_some() - || format_spec.width_span.is_some() - || format_spec.precision_span.is_some() - || format_spec.fill_span.is_some()) - { + + match FormatString::parse(self.symbol, self.span, &ctx) { + // Warnings about format specifiers, deprecated parameters, wrong parameters etc. + // In other words we'd like to let the author know, but we can still try to format the string later + Ok(FormatString { warnings, .. }) => { + for w in warnings { + w.emit_warning(tcx, trait_def_id) + } + } + // Errors from the underlying `rustc_parse_format::Parser` + Err(errors) => { + // we cannot return errors from processing the format string as hard error here + // as the diagnostic namespace guarantees that malformed input cannot cause an error + // + // if we encounter any error while processing we nevertheless want to show it as warning + // so that users are aware that something is not correct + for e in errors { + if self.is_diagnostic_namespace_variant { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), self.span, - InvalidFormatSpecifier, + WrappedParserError { description: e.description, label: e.label }, ); } - } - match a.position { - Position::ArgumentNamed(s) => { - match Symbol::intern(s) { - // `{ThisTraitsName}` is allowed - s if s == trait_name.name - && !self.is_diagnostic_namespace_variant => - { - () - } - s if ALLOWED_FORMAT_SYMBOLS.contains(&s) - && !self.is_diagnostic_namespace_variant => - { - () - } - // So is `{A}` if A is a type parameter - s if generics.own_params.iter().any(|param| param.name == s) => (), - s => { - if self.is_diagnostic_namespace_variant { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - self.span, - UnknownFormatParameterForOnUnimplementedAttr { - argument_name: s, - trait_name, - }, - ); - } - } else { - result = Err(struct_span_code_err!( - tcx.dcx(), - self.span, - E0230, - "there is no parameter `{}` on {}", - s, - if trait_def_id == item_def_id { - format!("trait `{trait_name}`") - } else { - "impl".to_string() - } - ) - .emit()); - } - } - } - } - // `{:1}` and `{}` are not to be used - Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { - if self.is_diagnostic_namespace_variant { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - self.span, - DisallowedPositionalArgument, - ); - } - } else { - let reported = struct_span_code_err!( - tcx.dcx(), - self.span, - E0231, - "only named generic parameters are allowed" - ) - .emit(); - result = Err(reported); - } - } + } else { + let reported = struct_span_code_err!( + tcx.dcx(), + self.span, + E0231, + "{}", + e.description, + ) + .emit(); + result = Err(reported); } } } } - // we cannot return errors from processing the format string as hard error here - // as the diagnostic namespace guarantees that malformed input cannot cause an error - // - // if we encounter any error while processing we nevertheless want to show it as warning - // so that users are aware that something is not correct - for e in parser.errors { - if self.is_diagnostic_namespace_variant { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - self.span, - WrappedParserError { description: e.description, label: e.label }, - ); - } - } else { - let reported = - struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit(); - result = Err(reported); - } - } result } @@ -854,95 +762,26 @@ impl<'tcx> OnUnimplementedFormatString { options: &FxHashMap, long_ty_file: &mut Option, ) -> String { - let name = tcx.item_name(trait_ref.def_id); - let trait_str = tcx.def_path_str(trait_ref.def_id); - let generics = tcx.generics_of(trait_ref.def_id); - let generic_map = generics - .own_params - .iter() - .filter_map(|param| { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - if let Some(ty) = trait_ref.args[param.index as usize].as_type() { - tcx.short_string(ty, long_ty_file) - } else { - trait_ref.args[param.index as usize].to_string() - } - } - GenericParamDefKind::Lifetime => return None, - }; - let name = param.name; - Some((name, value)) - }) - .collect::>(); - let empty_string = String::new(); - - let s = self.symbol.as_str(); - let mut parser = Parser::new(s, None, None, false, ParseMode::Format); - let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string); - let constructed_message = (&mut parser) - .map(|p| match p { - Piece::Lit(s) => s.to_owned(), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(arg) => { - let s = Symbol::intern(arg); - match generic_map.get(&s) { - Some(val) => val.to_string(), - None if self.is_diagnostic_namespace_variant => { - format!("{{{arg}}}") - } - None if s == name => trait_str.clone(), - None => { - if let Some(val) = options.get(&s) { - val.clone() - } else if s == sym::from_desugaring { - // don't break messages using these two arguments incorrectly - String::new() - } else if s == sym::ItemContext - && !self.is_diagnostic_namespace_variant - { - item_context.clone() - } else if s == sym::integral { - String::from("{integral}") - } else if s == sym::integer_ { - String::from("{integer}") - } else if s == sym::float { - String::from("{float}") - } else { - bug!( - "broken on_unimplemented {:?} for {:?}: \ - no argument matching {:?}", - self.symbol, - trait_ref, - s - ) - } - } - } - } - Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => { - String::from("{}") - } - Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => { - format!("{{{idx}}}") - } - _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol), - }, - }) - .collect(); - // we cannot return errors from processing the format string as hard error here - // as the diagnostic namespace guarantees that malformed input cannot cause an error - // - // if we encounter any error while processing the format string - // we don't want to show the potentially half assembled formatted string, - // therefore we fall back to just showing the input string in this case - // - // The actual parser errors are emitted earlier - // as lint warnings in OnUnimplementedFormatString::verify - if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() { - String::from(s) + let trait_def_id = trait_ref.def_id; + let ctx = if self.is_diagnostic_namespace_variant { + Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id } } else { - constructed_message + Ctx::RustcOnUnimplemented { tcx, trait_def_id } + }; + + if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { + s.format(tcx, trait_ref, options, long_ty_file) + } else { + // we cannot return errors from processing the format string as hard error here + // as the diagnostic namespace guarantees that malformed input cannot cause an error + // + // if we encounter any error while processing the format string + // we don't want to show the potentially half assembled formatted string, + // therefore we fall back to just showing the input string in this case + // + // The actual parser errors are emitted earlier + // as lint warnings in OnUnimplementedFormatString::verify + self.symbol.as_str().into() } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs new file mode 100644 index 000000000000..4c852c1023a1 --- /dev/null +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -0,0 +1,64 @@ +use rustc_ast::MetaItemInner; +use rustc_attr_parsing as attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_parse_format::{ParseMode, Parser, Piece, Position}; +use rustc_span::{Span, Symbol, sym}; + +pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[ + sym::from_desugaring, + sym::direct, + sym::cause, + sym::integral, + sym::integer_, + sym::float, + sym::_Self, + sym::crate_local, +]; + +#[derive(Debug)] +pub struct Condition { + pub inner: MetaItemInner, +} + +impl Condition { + pub fn span(&self) -> Span { + self.inner.span() + } + + pub fn matches_predicate<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + options: &[(Symbol, Option)], + options_map: &FxHashMap, + ) -> bool { + attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { + let value = cfg.value.map(|v| { + // `with_no_visible_paths` is also used when generating the options, + // so we need to match it here. + ty::print::with_no_visible_paths!({ + let mut parser = Parser::new(v.as_str(), None, None, false, ParseMode::Format); + let constructed_message = (&mut parser) + .map(|p| match p { + Piece::Lit(s) => s.to_owned(), + Piece::NextArgument(a) => match a.position { + Position::ArgumentNamed(arg) => { + let s = Symbol::intern(arg); + match options_map.get(&s) { + Some(val) => val.to_string(), + None => format!("{{{arg}}}"), + } + } + Position::ArgumentImplicitlyIs(_) => String::from("{}"), + Position::ArgumentIs(idx) => format!("{{{idx}}}"), + }, + }) + .collect(); + constructed_message + }) + }); + + options.contains(&(cfg.name, value)) + }) + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index 40a47921fc11..21db207496ca 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -1,3 +1,347 @@ +use std::fmt::Write; +use std::path::PathBuf; + +use errors::*; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::span_bug; +use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_parse_format::{ + Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, + Piece as RpfPiece, Position, +}; +use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_span::def_id::DefId; +use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; + +pub struct FormatString { + input: Symbol, + input_span: Span, + pieces: Vec, + // the formatting string was parsed succesfully but with warnings + pub warnings: Vec, +} + +enum Piece { + Lit(String), + Arg(FormatArg), +} + +pub enum FormatArg { + // A generic parameter, like `{T}` if we're on the `From` trait. + GenericParam { generic_param: Symbol, span: Span }, + // `{Self}` + SelfUpper, + This, + Trait, + ItemContext, + AsIs(String), +} + +pub enum Ctx<'tcx> { + // `#[rustc_on_unimplemented]` + RustcOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId }, + // `#[diagnostic::...]` + DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId }, +} + +pub enum FormatWarning { + UnknownParam { argument_name: Symbol, span: Span }, + PositionalArgument { span: Span, help: String }, + InvalidSpecifier { name: String, span: Span }, + FutureIncompat { span: Span, help: String }, +} + +impl FormatWarning { + pub fn emit_warning<'tcx>(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) { + match *self { + FormatWarning::UnknownParam { argument_name, span } => { + let this = tcx.item_ident(item_def_id); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + span, + UnknownFormatParameterForOnUnimplementedAttr { + argument_name, + trait_name: this, + }, + ); + } + } + FormatWarning::PositionalArgument { span, .. } => { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + span, + DisallowedPositionalArgument, + ); + } + } + FormatWarning::InvalidSpecifier { span, .. } => { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + span, + InvalidFormatSpecifier, + ); + } + } + FormatWarning::FutureIncompat { .. } => { + // We've never deprecated anything in diagnostic namespace format strings + // but if we do we will emit a warning here + + // FIXME(mejrs) in a couple releases, start emitting warnings for + // #[rustc_on_unimplemented] deprecated args + } + } + } +} + +impl FormatString { + pub fn parse(input: Symbol, input_span: Span, ctx: &Ctx<'_>) -> Result> { + let s = input.as_str(); + let mut parser = Parser::new(s, None, None, false, ParseMode::Format); + let mut pieces = Vec::new(); + let mut warnings = Vec::new(); + + for piece in &mut parser { + match piece { + RpfPiece::Lit(lit) => { + pieces.push(Piece::Lit(lit.into())); + } + RpfPiece::NextArgument(arg) => { + warn_on_format_spec(arg.format, &mut warnings, input_span); + let arg = parse_arg(&arg, ctx, &mut warnings, input_span); + pieces.push(Piece::Arg(arg)); + } + } + } + + if parser.errors.is_empty() { + Ok(FormatString { input, input_span, pieces, warnings }) + } else { + Err(parser.errors) + } + } + + pub fn format<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &FxHashMap, + long_ty_file: &mut Option, + ) -> String { + let generics = tcx.generics_of(trait_ref.def_id); + let generic_map = generics + .own_params + .iter() + .filter_map(|param| { + let value = match param.kind { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + if let Some(ty) = trait_ref.args[param.index as usize].as_type() { + tcx.short_string(ty, long_ty_file) + } else { + trait_ref.args[param.index as usize].to_string() + } + } + GenericParamDefKind::Lifetime => return None, + }; + let name = param.name; + Some((name, value)) + }) + .collect::>(); + + let mut ret = String::new(); + for piece in &self.pieces { + match piece { + Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s), + + // `A` if we have `trait Trait {}` and `note = "i'm the actual type of {A}"` + Piece::Arg(FormatArg::GenericParam { generic_param, span }) => { + // Should always be some but we can't raise errors here + if let Some(value) = generic_map.get(&generic_param) { + ret.push_str(value); + } else if cfg!(debug_assertions) { + span_bug!(*span, "invalid generic parameter"); + } else { + let _ = ret.write_fmt(format_args!("{{{}}}", generic_param.as_str())); + } + } + // `{Self}` + Piece::Arg(FormatArg::SelfUpper) => { + let Some(slf) = generic_map.get(&kw::SelfUpper) else { + span_bug!( + self.input_span, + "broken format string {:?} for {:?}: \ + no argument matching `Self`", + self.input, + trait_ref, + ) + }; + ret.push_str(&slf); + } + + // It's only `rustc_onunimplemented` from here + Piece::Arg(FormatArg::This) => { + let Some(this) = options.get(&sym::This) else { + span_bug!( + self.input_span, + "broken format string {:?} for {:?}: \ + no argument matching This", + self.input, + trait_ref, + ) + }; + ret.push_str(this); + } + Piece::Arg(FormatArg::Trait) => { + let Some(this) = options.get(&sym::Trait) else { + span_bug!( + self.input_span, + "broken format string {:?} for {:?}: \ + no argument matching Trait", + self.input, + trait_ref, + ) + }; + ret.push_str(this); + } + Piece::Arg(FormatArg::ItemContext) => { + let itemcontext = options.get(&sym::ItemContext); + ret.push_str(itemcontext.unwrap_or(&String::new())); + } + } + } + ret + } +} + +fn parse_arg( + arg: &Argument<'_>, + ctx: &Ctx<'_>, + warnings: &mut Vec, + input_span: Span, +) -> FormatArg { + let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } + | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; + let trait_name = tcx.item_ident(*trait_def_id); + let generics = tcx.generics_of(trait_def_id); + let span = slice_span(input_span, arg.position_span); + + match arg.position { + // Something like "hello {name}" + Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) { + // accepted, but deprecated + (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => { + warnings + .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") }); + FormatArg::SelfUpper + } + ( + Ctx::RustcOnUnimplemented { .. }, + sym::from_desugaring + | sym::crate_local + | sym::direct + | sym::cause + | sym::float + | sym::integer_ + | sym::integral, + ) => { + warnings.push(FormatWarning::FutureIncompat { + span, + help: String::from("don't use this in a format string"), + }); + FormatArg::AsIs(String::new()) + } + + // Only `#[rustc_on_unimplemented]` can use these + (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext, + (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This, + (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait, + // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}` + // because that'll be simpler to parse and extend in the future + (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => { + warnings + .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") }); + FormatArg::This + } + + // Any attribute can use these + ( + Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, + kw::SelfUpper, + ) => FormatArg::SelfUpper, + ( + Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, + generic_param, + ) if generics.own_params.iter().any(|param| param.name == generic_param) => { + FormatArg::GenericParam { generic_param, span } + } + + (_, argument_name) => { + warnings.push(FormatWarning::UnknownParam { argument_name, span }); + FormatArg::AsIs(format!("{{{}}}", argument_name.as_str())) + } + }, + + // `{:1}` and `{}` are ignored + Position::ArgumentIs(idx) => { + warnings.push(FormatWarning::PositionalArgument { + span, + help: format!("use `{{{idx}}}` to print a number in braces"), + }); + FormatArg::AsIs(format!("{{{idx}}}")) + } + Position::ArgumentImplicitlyIs(_) => { + warnings.push(FormatWarning::PositionalArgument { + span, + help: String::from("use `{{}}` to print empty braces"), + }); + FormatArg::AsIs(String::from("{}")) + } + } +} + +/// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything +/// with specifiers, so emit a warning if they are used. +fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec, input_span: Span) { + if !matches!( + spec, + FormatSpec { + fill: None, + fill_span: None, + align: Alignment::AlignUnknown, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, + precision: Count::CountImplied, + precision_span: None, + width: Count::CountImplied, + width_span: None, + ty: _, + ty_span: _, + }, + ) { + let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span); + warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) + } +} + +fn slice_span(input: Span, inner: InnerSpan) -> Span { + let InnerSpan { start, end } = inner; + let span = input.data(); + + Span::new( + span.lo + BytePos::from_usize(start), + span.lo + BytePos::from_usize(end), + span.ctxt, + span.parent, + ) +} + pub mod errors { use rustc_macros::LintDiagnostic; use rustc_middle::ty::TyCtxt; diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index 7fd51c7527f9..a82a1e78da0c 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -1,52 +1,52 @@ warning: unmatched `}` found - --> $DIR/broken_format.rs:2:32 + --> $DIR/broken_format.rs:2:42 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:7:32 + --> $DIR/broken_format.rs:7:49 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] - | ^^^^^^^^^^^^^^^^^^^ + | ^ | = help: only named format arguments with the name of one of the generic types are allowed in this context warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:12:32 + --> $DIR/broken_format.rs:12:49 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: only named format arguments with the name of one of the generic types are allowed in this context warning: invalid format specifier - --> $DIR/broken_format.rs:17:32 + --> $DIR/broken_format.rs:17:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = help: no format specifier are supported in this position warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:32 + --> $DIR/broken_format.rs:22:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:22:32 + --> $DIR/broken_format.rs:22:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:2:32 + --> $DIR/broken_format.rs:2:42 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -70,10 +70,10 @@ LL | fn check_1(_: impl ImportantTrait1) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_1` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:7:32 + --> $DIR/broken_format.rs:7:49 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] - | ^^^^^^^^^^^^^^^^^^^ + | ^ | = help: only named format arguments with the name of one of the generic types are allowed in this context = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -98,10 +98,10 @@ LL | fn check_2(_: impl ImportantTrait2) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_2` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:12:32 + --> $DIR/broken_format.rs:12:49 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: only named format arguments with the name of one of the generic types are allowed in this context = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -126,10 +126,10 @@ LL | fn check_3(_: impl ImportantTrait3) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_3` warning: invalid format specifier - --> $DIR/broken_format.rs:17:32 + --> $DIR/broken_format.rs:17:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = help: no format specifier are supported in this position = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -154,18 +154,18 @@ LL | fn check_4(_: impl ImportantTrait4) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_4` warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:32 + --> $DIR/broken_format.rs:22:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unmatched `}` found - --> $DIR/broken_format.rs:22:32 + --> $DIR/broken_format.rs:22:42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index bb455d929406..88816a98dcf0 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -39,82 +39,82 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -191,91 +191,91 @@ LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index 11263580b15e..4dd8c1afca02 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -47,10 +47,10 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -167,10 +167,10 @@ LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 3f0f69749bf7..0936b25847c4 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -20,12 +20,12 @@ trait BadAnnotation1 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] -//~^ ERROR there is no parameter `C` on trait `BadAnnotation2` +//~^ WARNING there is no parameter `C` on trait `BadAnnotation2` trait BadAnnotation2 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] -//~^ ERROR only named generic parameters are allowed +//~^ ERROR positional format arguments are not allowed here trait BadAnnotation3 {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 4ceea779b29d..1fefd93aa7ec 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -11,17 +11,22 @@ LL | #[rustc_on_unimplemented = "message"] LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -error[E0230]: there is no parameter `C` on trait `BadAnnotation2` - --> $DIR/bad-annotation.rs:22:1 +warning: there is no parameter `C` on trait `BadAnnotation2` + --> $DIR/bad-annotation.rs:22:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default -error[E0231]: only named generic parameters are allowed - --> $DIR/bad-annotation.rs:27:1 +warning: positional format arguments are not allowed here + --> $DIR/bad-annotation.rs:27:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ + | + = help: only named format arguments with the name of one of the generic types are allowed in this context error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:32:26 @@ -77,7 +82,6 @@ LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message | = note: eg `#[rustc_on_unimplemented(message="foo")]` -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0230, E0231, E0232. -For more information about an error, try `rustc --explain E0230`. +For more information about this error, try `rustc --explain E0232`. diff --git a/tests/ui/on-unimplemented/impl-substs.stderr b/tests/ui/on-unimplemented/impl-substs.stderr index b85d45eba5bb..0eabe9714922 100644 --- a/tests/ui/on-unimplemented/impl-substs.stderr +++ b/tests/ui/on-unimplemented/impl-substs.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(i32, i32, i32): Foo` is not satisfied --> $DIR/impl-substs.rs:13:23 | LL | Foo::::foo((1i32, 1i32, 1i32)); - | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _ + | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize {B} {C} | | | required by a bound introduced by this call | From ba9f51b05503a567cb637db03eaa943c59e36922 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 27 Mar 2025 23:09:44 +0100 Subject: [PATCH 004/109] Parse condition options into a struct --- .../traits/on_unimplemented.rs | 178 ++++++++++-------- .../traits/on_unimplemented_condition.rs | 45 +++-- .../traits/on_unimplemented_format.rs | 110 ++++------- 3 files changed, 168 insertions(+), 165 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 6a7f32234213..7d8ecba3b2e0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -2,14 +2,13 @@ use std::iter; use std::path::PathBuf; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; use rustc_middle::bug; -use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::print::PrintTraitRefExt; +use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; @@ -17,9 +16,9 @@ use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; -use crate::error_reporting::traits::on_unimplemented_condition::Condition; +use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; use crate::error_reporting::traits::on_unimplemented_format::errors::*; -use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatString}; +use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatArgs, FormatString}; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; @@ -107,86 +106,81 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args)); let trait_pred = trait_pred.skip_binder(); - let mut flags = vec![]; + let mut self_types = vec![]; + let mut generic_args: Vec<(Symbol, String)> = vec![]; + let mut crate_local = false; // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, // but I guess we could synthesize one here. We don't see any errors that rely on // that yet, though. - let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned()); - flags.push((sym::ItemContext, enclosure)); + let item_context = self + .describe_enclosure(obligation.cause.body_id) + .map(|t| t.to_owned()) + .unwrap_or(String::new()); - match obligation.cause.code() { + let direct = match obligation.cause.code() { ObligationCauseCode::BuiltinDerived(..) | ObligationCauseCode::ImplDerived(..) - | ObligationCauseCode::WellFormedDerived(..) => {} + | ObligationCauseCode::WellFormedDerived(..) => false, _ => { // this is a "direct", user-specified, rather than derived, // obligation. - flags.push((sym::direct, None)); + true } - } + }; - if let Some(k) = obligation.cause.span.desugaring_kind() { - flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(format!("{k:?}")))); - } + let from_desugaring = obligation.cause.span.desugaring_kind().map(|k| format!("{k:?}")); - if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { - flags.push((sym::cause, Some("MainFunctionType".to_string()))); - } - - flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string()))); + let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { + Some("MainFunctionType".to_string()) + } else { + None + }; // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ let generics = self.tcx.generics_of(def_id); let self_ty = trait_pred.self_ty(); - // This is also included through the generics list as `Self`, - // but the parser won't allow you to use it - flags.push((sym::_Self, Some(self_ty.to_string()))); + self_types.push(self_ty.to_string()); if let Some(def) = self_ty.ty_adt_def() { // We also want to be able to select self's original // signature with no type arguments resolved - flags.push(( - sym::_Self, - Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), - )); + self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string()); } - for param in generics.own_params.iter() { - let value = match param.kind { + for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() { + let value = match kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - args[param.index as usize].to_string() + args[*index as usize].to_string() } GenericParamDefKind::Lifetime => continue, }; - let name = param.name; - flags.push((name, Some(value))); + generic_args.push((*name, value)); - if let GenericParamDefKind::Type { .. } = param.kind { - let param_ty = args[param.index as usize].expect_ty(); + if let GenericParamDefKind::Type { .. } = kind { + let param_ty = args[*index as usize].expect_ty(); if let Some(def) = param_ty.ty_adt_def() { // We also want to be able to select the parameter's // original signature with no type arguments resolved - flags.push(( - name, - Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), + generic_args.push(( + *name, + self.tcx.type_of(def.did()).instantiate_identity().to_string(), )); } } } if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) { - flags.push((sym::crate_local, None)); + crate_local = true; } // Allow targeting all integers using `{integral}`, even if the exact type was resolved if self_ty.is_integral() { - flags.push((sym::_Self, Some("{integral}".to_owned()))); + self_types.push("{integral}".to_owned()); } if self_ty.is_array_slice() { - flags.push((sym::_Self, Some("&[]".to_owned()))); + self_types.push("&[]".to_owned()); } if self_ty.is_fn() { @@ -201,53 +195,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { hir::Safety::Unsafe => "unsafe fn", } }; - flags.push((sym::_Self, Some(shortname.to_owned()))); + self_types.push(shortname.to_owned()); } // Slices give us `[]`, `[{ty}]` if let ty::Slice(aty) = self_ty.kind() { - flags.push((sym::_Self, Some("[]".to_string()))); + self_types.push("[]".to_owned()); if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the slice's type's original // signature with no type arguments resolved - flags.push(( - sym::_Self, - Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())), - )); + self_types + .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())); } if aty.is_integral() { - flags.push((sym::_Self, Some("[{integral}]".to_string()))); + self_types.push("[{integral}]".to_string()); } } // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` if let ty::Array(aty, len) = self_ty.kind() { - flags.push((sym::_Self, Some("[]".to_string()))); + self_types.push("[]".to_string()); let len = len.try_to_target_usize(self.tcx); - flags.push((sym::_Self, Some(format!("[{aty}; _]")))); + self_types.push(format!("[{aty}; _]")); if let Some(n) = len { - flags.push((sym::_Self, Some(format!("[{aty}; {n}]")))); + self_types.push(format!("[{aty}; {n}]")); } if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the array's type's original // signature with no type arguments resolved let def_ty = self.tcx.type_of(def.did()).instantiate_identity(); - flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); + self_types.push(format!("[{def_ty}; _]")); if let Some(n) = len { - flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); + self_types.push(format!("[{def_ty}; {n}]")); } } if aty.is_integral() { - flags.push((sym::_Self, Some("[{integral}; _]".to_string()))); + self_types.push("[{integral}; _]".to_string()); if let Some(n) = len { - flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]")))); + self_types.push(format!("[{{integral}}; {n}]")); } } } if let ty::Dynamic(traits, _, _) = self_ty.kind() { for t in traits.iter() { if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { - flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + self_types.push(self.tcx.def_path_str(trait_ref.def_id)); } } } @@ -257,14 +249,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let ty::Slice(sty) = ref_ty.kind() && sty.is_integral() { - flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); + self_types.push("&[{integral}]".to_owned()); } })); - flags.push((sym::This, Some(self.tcx.def_path_str(trait_pred.trait_ref.def_id)))); + let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id).to_string(); + let trait_sugared = trait_pred.trait_ref.print_trait_sugared().to_string(); + + let condition_options = ConditionOptions { + self_types, + from_desugaring, + cause, + crate_local, + direct, + generic_args, + }; + + // Unlike the generic_args earlier, + // this one is *not* collected under `with_no_trimmed_paths!` + // for printing the type to the user + let generic_args = self + .tcx + .generics_of(trait_pred.trait_ref.def_id) + .own_params + .iter() + .filter_map(|param| { + let value = match param.kind { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type() + { + self.tcx.short_string(ty, long_ty_file) + } else { + trait_pred.trait_ref.args[param.index as usize].to_string() + } + } + GenericParamDefKind::Lifetime => return None, + }; + let name = param.name; + Some((name, value)) + }) + .collect(); + + let format_args = FormatArgs { this, trait_sugared, generic_args, item_context }; if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { - command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file) + command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args) } else { OnUnimplementedNote::default() } @@ -634,23 +663,23 @@ impl<'tcx> OnUnimplementedDirective { &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, - options: &[(Symbol, Option)], - long_ty_file: &mut Option, + condition_options: &ConditionOptions, + args: &FormatArgs, ) -> OnUnimplementedNote { let mut message = None; let mut label = None; let mut notes = Vec::new(); let mut parent_label = None; let mut append_const_msg = None; - info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); - - let options_map: FxHashMap = - options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect(); + info!( + "evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})", + self, trait_ref, condition_options, args + ); for command in self.subcommands.iter().chain(Some(self)).rev() { debug!(?command); if let Some(ref condition) = command.condition - && !condition.matches_predicate(tcx, options, &options_map) + && !condition.matches_predicate(tcx, condition_options) { debug!("evaluate: skipping {:?} due to condition", command); continue; @@ -674,14 +703,10 @@ impl<'tcx> OnUnimplementedDirective { } OnUnimplementedNote { - label: label.map(|l| l.1.format(tcx, trait_ref, &options_map, long_ty_file)), - message: message.map(|m| m.1.format(tcx, trait_ref, &options_map, long_ty_file)), - notes: notes - .into_iter() - .map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file)) - .collect(), - parent_label: parent_label - .map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)), + label: label.map(|l| l.1.format(tcx, trait_ref, args)), + message: message.map(|m| m.1.format(tcx, trait_ref, args)), + notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(), + parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)), append_const_msg, } } @@ -759,8 +784,7 @@ impl<'tcx> OnUnimplementedFormatString { &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, - options: &FxHashMap, - long_ty_file: &mut Option, + args: &FormatArgs, ) -> String { let trait_def_id = trait_ref.def_id; let ctx = if self.is_diagnostic_namespace_variant { @@ -770,7 +794,7 @@ impl<'tcx> OnUnimplementedFormatString { }; if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { - s.format(tcx, trait_ref, options, long_ty_file) + s.format(args) } else { // we cannot return errors from processing the format string as hard error here // as the diagnostic namespace guarantees that malformed input cannot cause an error diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 4c852c1023a1..491ba6d7ffc0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -1,9 +1,8 @@ use rustc_ast::MetaItemInner; use rustc_attr_parsing as attr; -use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::{self, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, kw, sym}; pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[ sym::from_desugaring, @@ -26,12 +25,7 @@ impl Condition { self.inner.span() } - pub fn matches_predicate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - options: &[(Symbol, Option)], - options_map: &FxHashMap, - ) -> bool { + pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool { attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { let value = cfg.value.map(|v| { // `with_no_visible_paths` is also used when generating the options, @@ -44,8 +38,8 @@ impl Condition { Piece::NextArgument(a) => match a.position { Position::ArgumentNamed(arg) => { let s = Symbol::intern(arg); - match options_map.get(&s) { - Some(val) => val.to_string(), + match options.generic_args.iter().find(|(k, _)| *k == s) { + Some((_, val)) => val.to_string(), None => format!("{{{arg}}}"), } } @@ -58,7 +52,36 @@ impl Condition { }) }); - options.contains(&(cfg.name, value)) + options.contains(cfg.name, &value) }) } } + +#[derive(Debug)] +pub struct ConditionOptions { + pub self_types: Vec, + pub from_desugaring: Option, + pub cause: Option, + pub crate_local: bool, + pub direct: bool, + pub generic_args: Vec<(Symbol, String)>, +} + +impl ConditionOptions { + pub fn contains(&self, key: Symbol, value: &Option) -> bool { + match (key, value) { + (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value), + // from_desugaring as a flag + (sym::from_desugaring, None) => self.from_desugaring.is_some(), + // from_desugaring as key == value + (sym::from_desugaring, v) => *v == self.from_desugaring, + (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), + (sym::crate_local, None) => self.crate_local, + (sym::direct, None) => self.direct, + (other, Some(value)) => { + self.generic_args.iter().any(|(k, v)| *k == other && v == value) + } + _ => false, + } + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index 21db207496ca..1bf15a345094 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -1,10 +1,5 @@ -use std::fmt::Write; -use std::path::PathBuf; - use errors::*; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::span_bug; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_parse_format::{ Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -13,6 +8,7 @@ use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; +#[allow(dead_code)] pub struct FormatString { input: Symbol, input_span: Span, @@ -99,6 +95,24 @@ impl FormatWarning { } } +#[derive(Debug)] +pub struct ConditionOptions { + pub self_types: Vec, + pub from_desugaring: Option, + pub cause: Option, + pub crate_local: bool, + pub direct: bool, + pub generic_args: Vec<(Symbol, String)>, +} + +#[derive(Debug)] +pub struct FormatArgs { + pub this: String, + pub trait_sugared: String, + pub item_context: String, + pub generic_args: Vec<(Symbol, String)>, +} + impl FormatString { pub fn parse(input: Symbol, input_span: Span, ctx: &Ctx<'_>) -> Result> { let s = input.as_str(); @@ -126,92 +140,34 @@ impl FormatString { } } - pub fn format<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - options: &FxHashMap, - long_ty_file: &mut Option, - ) -> String { - let generics = tcx.generics_of(trait_ref.def_id); - let generic_map = generics - .own_params - .iter() - .filter_map(|param| { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - if let Some(ty) = trait_ref.args[param.index as usize].as_type() { - tcx.short_string(ty, long_ty_file) - } else { - trait_ref.args[param.index as usize].to_string() - } - } - GenericParamDefKind::Lifetime => return None, - }; - let name = param.name; - Some((name, value)) - }) - .collect::>(); - + pub fn format(&self, args: &FormatArgs) -> String { let mut ret = String::new(); for piece in &self.pieces { match piece { Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s), // `A` if we have `trait Trait {}` and `note = "i'm the actual type of {A}"` - Piece::Arg(FormatArg::GenericParam { generic_param, span }) => { + Piece::Arg(FormatArg::GenericParam { generic_param, .. }) => { // Should always be some but we can't raise errors here - if let Some(value) = generic_map.get(&generic_param) { - ret.push_str(value); - } else if cfg!(debug_assertions) { - span_bug!(*span, "invalid generic parameter"); - } else { - let _ = ret.write_fmt(format_args!("{{{}}}", generic_param.as_str())); - } + let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) { + Some((_, val)) => val.to_string(), + None => generic_param.to_string(), + }; + ret.push_str(&value); } // `{Self}` Piece::Arg(FormatArg::SelfUpper) => { - let Some(slf) = generic_map.get(&kw::SelfUpper) else { - span_bug!( - self.input_span, - "broken format string {:?} for {:?}: \ - no argument matching `Self`", - self.input, - trait_ref, - ) + let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) { + Some((_, val)) => val.to_string(), + None => "Self".to_string(), }; ret.push_str(&slf); } // It's only `rustc_onunimplemented` from here - Piece::Arg(FormatArg::This) => { - let Some(this) = options.get(&sym::This) else { - span_bug!( - self.input_span, - "broken format string {:?} for {:?}: \ - no argument matching This", - self.input, - trait_ref, - ) - }; - ret.push_str(this); - } - Piece::Arg(FormatArg::Trait) => { - let Some(this) = options.get(&sym::Trait) else { - span_bug!( - self.input_span, - "broken format string {:?} for {:?}: \ - no argument matching Trait", - self.input, - trait_ref, - ) - }; - ret.push_str(this); - } - Piece::Arg(FormatArg::ItemContext) => { - let itemcontext = options.get(&sym::ItemContext); - ret.push_str(itemcontext.unwrap_or(&String::new())); - } + Piece::Arg(FormatArg::This) => ret.push_str(&args.this), + Piece::Arg(FormatArg::Trait) => ret.push_str(&args.trait_sugared), + Piece::Arg(FormatArg::ItemContext) => ret.push_str(&args.item_context), } } ret From c285fe7256b5de9fd1db211a6491b46326d81f9c Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Fri, 11 Apr 2025 12:12:46 +0300 Subject: [PATCH 005/109] Fix link to rustc_* TEST attributes in ui.md --- src/doc/rustc-dev-guide/src/tests/ui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index e862a07cae0a..41dc9299a45d 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -575,4 +575,4 @@ with "user-facing" Rust alone. Indeed, one could say that this slightly abuses the term "UI" (*user* interface) and turns such UI tests from black-box tests into white-box ones. Use them carefully and sparingly. -[compiler debugging]: ../compiler-debugging.md#rustc_test-attributes +[compiler debugging]: ../compiler-debugging.md#rustc_-test-attributes From b2fce61869e5656c37ba590538d4ab268fedca4d Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Tue, 8 Apr 2025 11:34:55 +0300 Subject: [PATCH 006/109] Update table of contents in about-this-guide.md 1. added two new parts: Bootstrapping and Supporting Infrastructure; 2. touched up names of pre-existing parts, to match actual names in sidebar; 3. syntactic nits (start description of Analysis with a capital letter); and 4. make numbered list use only 1. Co-authored-by: Tshepang Mbambo --- .../rustc-dev-guide/src/about-this-guide.md | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 781a5c51bf7a..057e4a4cceed 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -3,33 +3,41 @@ This guide is meant to help document how rustc – the Rust compiler – works, as well as to help new contributors get involved in rustc development. -There are seven parts to this guide: +There are several parts to this guide: -1. [Building `rustc`][p1]: +1. [Building and debugging `rustc`][p1]: Contains information that should be useful no matter how you are contributing, about building, debugging, profiling, etc. -2. [Contributing to `rustc`][p2]: +1. [Contributing to Rust][p2]: Contains information that should be useful no matter how you are contributing, about procedures for contribution, using git and Github, stabilizing features, etc. -3. [High-Level Compiler Architecture][p3]: +1. [Bootstrapping][p3]: + Describes how the Rust compiler builds itself using previous versions, including + an introduction to the bootstrap process and debugging methods. +1. [High-level Compiler Architecture][p4]: Discusses the high-level architecture of the compiler and stages of the compile process. -4. [Source Code Representation][p4]: +1. [Source Code Representation][p5]: Describes the process of taking raw source code from the user and transforming it into various forms that the compiler can work with easily. -5. [Analysis][p5]: - discusses the analyses that the compiler uses to check various properties of the code +1. [Supporting Infrastructure][p6]: + Covers command-line argument conventions, compiler entry points like rustc_driver and + rustc_interface, and the design and implementation of errors and lints. +1. [Analysis][p7]: + Discusses the analyses that the compiler uses to check various properties of the code and inform later stages of the compile process (e.g., type checking). -6. [From MIR to Binaries][p6]: How linked executable machine code is generated. -7. [Appendices][p7] at the end with useful reference information. +1. [MIR to Binaries][p8]: How linked executable machine code is generated. +1. [Appendices][p9] at the end with useful reference information. There are a few of these with different information, including a glossary. [p1]: ./building/how-to-build-and-run.html [p2]: ./contributing.md -[p3]: ./part-2-intro.md -[p4]: ./part-3-intro.md -[p5]: ./part-4-intro.md -[p6]: ./part-5-intro.md -[p7]: ./appendix/background.md +[p3]: ./building/bootstrapping/intro.md +[p4]: ./part-2-intro.md +[p5]: ./part-3-intro.md +[p6]: ./cli.md +[p7]: ./part-4-intro.md +[p8]: ./part-5-intro.md +[p9]: ./appendix/background.md ### Constant change From c5e23697c094b713b862f08e4bb074c88baa2750 Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Sat, 12 Apr 2025 00:05:26 +0200 Subject: [PATCH 007/109] Update "crater" link to actually point to crater.md --- src/doc/rustc-dev-guide/src/walkthrough.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/walkthrough.md b/src/doc/rustc-dev-guide/src/walkthrough.md index 6e07ceb7d737..48b3f8bb15d3 100644 --- a/src/doc/rustc-dev-guide/src/walkthrough.md +++ b/src/doc/rustc-dev-guide/src/walkthrough.md @@ -221,7 +221,7 @@ There are a couple of things that may happen for some PRs during the review proc some merge conflicts with other PRs that happen to get merged first. You should fix these merge conflicts using the normal git procedures. -[crater]: ./tests/intro.html#crater +[crater]: ./tests/crater.html If you are not doing a new feature or something like that (e.g. if you are fixing a bug), then that's it! Thanks for your contribution :) From e0a2250f2068bc3d6903d0885ed003af1f6cacf4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 06:14:37 +0200 Subject: [PATCH 008/109] ease copy-paste --- src/doc/rustc-dev-guide/src/tests/ecosystem.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ecosystem.md b/src/doc/rustc-dev-guide/src/tests/ecosystem.md index f4b93492e005..eee07dd079bb 100644 --- a/src/doc/rustc-dev-guide/src/tests/ecosystem.md +++ b/src/doc/rustc-dev-guide/src/tests/ecosystem.md @@ -15,9 +15,11 @@ CI. See the [Crater chapter](crater.md) for more details. `cargotest` is a small tool which runs `cargo test` on a few sample projects (such as `servo`, `ripgrep`, `tokei`, etc.). This runs as part of CI and ensures -there aren't any significant regressions. +there aren't any significant regressions: -> Example: `./x test src/tools/cargotest` +```console +./x test src/tools/cargotest +``` ### Large OSS Project builders From 3ae1c9df5b19bb43fe3fe05359f4b2ed2f56b49e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 09:39:13 +0200 Subject: [PATCH 009/109] use more simple language Not obvious what "sort by" means --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 09a7f912b988..1dcda962da08 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -346,7 +346,7 @@ function in the same way as other pull requests. [`src/doc`]: https://github.com/rust-lang/rust/tree/master/src/doc [std-root]: https://github.com/rust-lang/rust/blob/master/library/std/src/lib.rs#L1 -To find documentation-related issues, sort by the [A-docs label]. +To find documentation-related issues, use the [A-docs label]. You can find documentation style guidelines in [RFC 1574]. From 770a6fcb48cfbe1fff078013edebb58a0be9a997 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 10:21:10 +0200 Subject: [PATCH 010/109] remove implied text "how much to trust" implies the opposite --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 09a7f912b988..579a2439fb88 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -373,7 +373,7 @@ Just a few things to keep in mind: There is no strict limit on line lengths; let the sentence or part of the sentence flow to its proper end on the same line. - When contributing text to the guide, please contextualize the information with some time period - and/or a reason so that the reader knows how much to trust or mistrust the information. + and/or a reason so that the reader knows how much to trust the information. Aim to provide a reasonable amount of context, possibly including but not limited to: - A reason for why the data may be out of date other than "change", From 7ba53b7b7598f4d16c8543de5f2032293a6255e1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 10:24:31 +0200 Subject: [PATCH 011/109] add missing word --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 09a7f912b988..9e75d9d8a313 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -388,7 +388,7 @@ Just a few things to keep in mind: - january 2021 There is a CI action (in `~/.github/workflows/date-check.yml`) - that generates a monthly showing those that are over 6 months old + that generates a monthly report showing those that are over 6 months old ([example](https://github.com/rust-lang/rustc-dev-guide/issues/2052)). For the action to pick the date, From e33a6d6f60fdc647469a758c9fe62041ffd2d8e4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 10:28:15 +0200 Subject: [PATCH 012/109] date-check rdg contribution section --- src/doc/rustc-dev-guide/src/contributing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 73006de6b862..aeea45046589 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -395,20 +395,20 @@ Just a few things to keep in mind: add a special annotation before specifying the date: ```md - Sep 2024 + Apr 2025 ``` Example: ```md - As of Sep 2024, the foo did the bar. + As of Apr 2025, the foo did the bar. ``` For cases where the date should not be part of the visible rendered output, use the following instead: ```md - + ``` - A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide From 667aa2e952a8367863021782cad5fbad7b89dbff Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 10:41:48 +0200 Subject: [PATCH 013/109] fix path --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 7946c444d03d..0e622fff8df2 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -387,7 +387,7 @@ Just a few things to keep in mind: - jan 2021 - january 2021 - There is a CI action (in `~/.github/workflows/date-check.yml`) + There is a CI action (in `.github/workflows/date-check.yml`) that generates a monthly report showing those that are over 6 months old ([example](https://github.com/rust-lang/rustc-dev-guide/issues/2052)). From 2af7ec32be4b246545c6b6b824820b4feff441bf Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 12 Apr 2025 13:01:16 +0200 Subject: [PATCH 014/109] use consistent title capitalization --- src/doc/rustc-dev-guide/src/SUMMARY.md | 40 +++++++++---------- src/doc/rustc-dev-guide/src/ast-validation.md | 2 +- .../rustc-dev-guide/src/bug-fix-procedure.md | 2 +- .../rustc-dev-guide/src/building/suggested.md | 2 +- src/doc/rustc-dev-guide/src/coherence.md | 1 - src/doc/rustc-dev-guide/src/contributing.md | 2 +- src/doc/rustc-dev-guide/src/crates-io.md | 2 +- src/doc/rustc-dev-guide/src/diagnostics.md | 4 +- src/doc/rustc-dev-guide/src/feature-gates.md | 2 +- .../rustc-dev-guide/src/incrcomp-debugging.md | 2 +- src/doc/rustc-dev-guide/src/memory.md | 2 +- .../src/panic-implementation.md | 2 +- src/doc/rustc-dev-guide/src/parallel-rustc.md | 10 ++--- .../incremental-compilation-in-detail.md | 2 +- .../query-evaluation-model-in-detail.md | 2 +- src/doc/rustc-dev-guide/src/serialization.md | 2 +- .../src/test-implementation.md | 4 +- src/doc/rustc-dev-guide/src/the-parser.md | 4 +- .../rustc-dev-guide/src/unsafety-checking.md | 2 +- 19 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 95a3cd7c7909..05c43c83a9d9 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -10,9 +10,9 @@ - [How to build and run the compiler](./building/how-to-build-and-run.md) - [Quickstart](./building/quickstart.md) - [Prerequisites](./building/prerequisites.md) - - [Suggested Workflows](./building/suggested.md) + - [Suggested workflows](./building/suggested.md) - [Distribution artifacts](./building/build-install-distribution-artifacts.md) - - [Building Documentation](./building/compiler-documenting.md) + - [Building documentation](./building/compiler-documenting.md) - [Rustdoc overview](./rustdoc.md) - [Adding a new target](./building/new-target.md) - [Optimized build](./building/optimized-build.md) @@ -42,11 +42,11 @@ - [with the linux perf tool](./profiling/with_perf.md) - [with Windows Performance Analyzer](./profiling/wpa_profiling.md) - [with the Rust benchmark suite](./profiling/with_rustc_perf.md) -- [crates.io Dependencies](./crates-io.md) +- [crates.io dependencies](./crates-io.md) # Contributing to Rust -- [Contribution Procedures](./contributing.md) +- [Contribution procedures](./contributing.md) - [About the compiler team](./compiler-team.md) - [Using Git](./git.md) - [Mastering @rustbot](./rustbot.md) @@ -56,7 +56,7 @@ - [Stabilizing Features](./stabilization_guide.md) - [Feature Gates](./feature-gates.md) - [Coding conventions](./conventions.md) -- [Procedures for Breaking Changes](./bug-fix-procedure.md) +- [Procedures for breaking changes](./bug-fix-procedure.md) - [Using external repositories](./external-repos.md) - [Fuzzing](./fuzzing.md) - [Notification groups](notification-groups/about.md) @@ -88,14 +88,14 @@ - [Overview of the compiler](./overview.md) - [The compiler source code](./compiler-src.md) - [Queries: demand-driven compilation](./query.md) - - [The Query Evaluation Model in Detail](./queries/query-evaluation-model-in-detail.md) + - [The Query Evaluation Model in detail](./queries/query-evaluation-model-in-detail.md) - [Incremental compilation](./queries/incremental-compilation.md) - - [Incremental compilation In Detail](./queries/incremental-compilation-in-detail.md) - - [Debugging and Testing](./incrcomp-debugging.md) + - [Incremental compilation in detail](./queries/incremental-compilation-in-detail.md) + - [Debugging and testing](./incrcomp-debugging.md) - [Salsa](./queries/salsa.md) -- [Memory Management in Rustc](./memory.md) -- [Serialization in Rustc](./serialization.md) -- [Parallel Compilation](./parallel-rustc.md) +- [Memory management in rustc](./memory.md) +- [Serialization in rustc](./serialization.md) +- [Parallel compilation](./parallel-rustc.md) - [Rustdoc internals](./rustdoc-internals.md) - [Search](./rustdoc-internals/search.md) - [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md) @@ -103,14 +103,14 @@ - [Prologue](./part-3-intro.md) - [Syntax and the AST](./syntax-intro.md) - - [Lexing and Parsing](./the-parser.md) + - [Lexing and parsing](./the-parser.md) - [Macro expansion](./macro-expansion.md) - [Name resolution](./name-resolution.md) - [Attributes](./attributes.md) - - [`#[test]` Implementation](./test-implementation.md) - - [Panic Implementation](./panic-implementation.md) - - [AST Validation](./ast-validation.md) - - [Feature Gate Checking](./feature-gate-ck.md) + - [`#[test]` implementation](./test-implementation.md) + - [Panic implementation](./panic-implementation.md) + - [AST validation](./ast-validation.md) + - [Feature gate checking](./feature-gate-ck.md) - [Lang Items](./lang-items.md) - [The HIR (High-level IR)](./hir.md) - [Lowering AST to HIR](./ast-lowering.md) @@ -129,7 +129,7 @@ - [Example: Type checking](./rustc-driver/interacting-with-the-ast.md) - [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md) - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md) -- [Errors and Lints](diagnostics.md) +- [Errors and lints](diagnostics.md) - [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md) - [Translation](./diagnostics/translation.md) - [`LintStore`](./diagnostics/lintstore.md) @@ -175,14 +175,14 @@ - [Type checking](./type-checking.md) - [Method Lookup](./method-lookup.md) - [Variance](./variance.md) - - [Coherence Checking](./coherence.md) - - [Opaque Types](./opaque-types-type-alias-impl-trait.md) + - [Coherence checking](./coherence.md) + - [Opaque types](./opaque-types-type-alias-impl-trait.md) - [Inference details](./opaque-types-impl-trait-inference.md) - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) - [Region inference restrictions][opaque-infer] - [Const condition checking](./effects.md) - [Pattern and Exhaustiveness Checking](./pat-exhaustive-checking.md) -- [Unsafety Checking](./unsafety-checking.md) +- [Unsafety checking](./unsafety-checking.md) - [MIR dataflow](./mir/dataflow.md) - [Drop elaboration](./mir/drop-elaboration.md) - [The borrow checker](./borrow_check.md) diff --git a/src/doc/rustc-dev-guide/src/ast-validation.md b/src/doc/rustc-dev-guide/src/ast-validation.md index fa0f1d954f86..8f10bbecf21d 100644 --- a/src/doc/rustc-dev-guide/src/ast-validation.md +++ b/src/doc/rustc-dev-guide/src/ast-validation.md @@ -1,4 +1,4 @@ -# AST Validation +# AST validation _AST validation_ is a separate AST pass that visits each item in the tree and performs simple checks. This pass diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index e6a16df6d2a9..8e6725c54efa 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -1,4 +1,4 @@ -# Procedures for Breaking Changes +# Procedures for breaking changes diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 43ff2ba726f9..a70d9d88ec3e 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -1,4 +1,4 @@ -# Suggested Workflows +# Suggested workflows The full bootstrapping process takes quite a while. Here are some suggestions to make your life easier. diff --git a/src/doc/rustc-dev-guide/src/coherence.md b/src/doc/rustc-dev-guide/src/coherence.md index b3af101fb876..73f9213bf405 100644 --- a/src/doc/rustc-dev-guide/src/coherence.md +++ b/src/doc/rustc-dev-guide/src/coherence.md @@ -1,4 +1,3 @@ - # Coherence > NOTE: this is based on [notes by @lcnr](https://github.com/rust-lang/rust/pull/121848) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 0e622fff8df2..cc68c011d61d 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -1,4 +1,4 @@ -# Contribution Procedures +# Contribution procedures diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 403d61a81dad..4431585a2f02 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -1,4 +1,4 @@ -# crates.io Dependencies +# crates.io dependencies The Rust compiler supports building with some dependencies from `crates.io`. Examples are `log` and `env_logger`. diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 6f72ea902f5d..2f8f4b0ab8a0 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -1,4 +1,4 @@ -# Errors and Lints +# Errors and lints @@ -772,7 +772,7 @@ store.register_renamed("single_use_lifetime", "single_use_lifetimes"); [`store.register_removed`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_removed [`rustc_lint::register_builtins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html -### Lint Groups +### Lint groups Lints can be turned on in groups. These groups are declared in the [`register_builtins`][rbuiltins] function in [`rustc_lint::lib`][builtin]. The diff --git a/src/doc/rustc-dev-guide/src/feature-gates.md b/src/doc/rustc-dev-guide/src/feature-gates.md index 24ce9bb71bfd..9806f73c483c 100644 --- a/src/doc/rustc-dev-guide/src/feature-gates.md +++ b/src/doc/rustc-dev-guide/src/feature-gates.md @@ -1,4 +1,4 @@ -# Feature Gates +# Feature gates This chapter is intended to provide basic help for adding, removing, and modifying feature gates. diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md index 7045d3fa39d3..a548215cf0ce 100644 --- a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md +++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md @@ -1,4 +1,4 @@ -# Debugging and Testing Dependencies +# Debugging and testing dependencies ## Testing the dependency graph diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index 1e030ff45a78..eeb4a813980a 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -1,4 +1,4 @@ -# Memory Management in Rustc +# Memory management in rustc Generally rustc tries to be pretty careful how it manages memory. The compiler allocates _a lot_ of data structures throughout compilation, diff --git a/src/doc/rustc-dev-guide/src/panic-implementation.md b/src/doc/rustc-dev-guide/src/panic-implementation.md index f35874286671..468190ffccd5 100644 --- a/src/doc/rustc-dev-guide/src/panic-implementation.md +++ b/src/doc/rustc-dev-guide/src/panic-implementation.md @@ -1,4 +1,4 @@ -# Panicking in rust +# Panicking in Rust diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md index 690fb19c9f52..ce69b66c2daf 100644 --- a/src/doc/rustc-dev-guide/src/parallel-rustc.md +++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md @@ -1,4 +1,4 @@ -# Parallel Compilation +# Parallel compilation
As of November 2024, @@ -28,7 +28,7 @@ The following sections are kept for now but are quite outdated. [codegen]: backend/codegen.md -## Code Generation +## Code generation During monomorphization the compiler splits up all the code to be generated into smaller chunks called _codegen units_. These are then generated by @@ -38,7 +38,7 @@ occurs in the [`rustc_codegen_ssa::base`] module. [`rustc_codegen_ssa::base`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/index.html -## Data Structures +## Data structures The underlying thread-safe data-structures used in the parallel compiler can be found in the [`rustc_data_structures::sync`] module. These data structures @@ -83,7 +83,7 @@ can be accessed directly through `Deref::deref`. [`rustc_data_structures::sync::worker_local`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/worker_local/index.html [`WorkerLocal`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/worker_local/struct.WorkerLocal.html -## Parallel Iterator +## Parallel iterator The parallel iterators provided by the [`rayon`] crate are easy ways to implement parallelism. In the current implementation of the parallel compiler @@ -124,7 +124,7 @@ the parallel iterator function has been used are as follows: There are still many loops that have the potential to use parallel iterators. -## Query System +## Query system The query model has some properties that make it actually feasible to evaluate multiple queries in parallel without too much effort: diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 4133b196c0af..03c822d4feed 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -1,4 +1,4 @@ -# Incremental Compilation In Detail +# Incremental Compilation in detail diff --git a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md index f7f204bf79d3..444e20bc580e 100644 --- a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md @@ -1,4 +1,4 @@ -# The Query Evaluation Model in Detail +# The Query Evaluation Model in detail diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md index 0ff049901286..670a37ffb0a9 100644 --- a/src/doc/rustc-dev-guide/src/serialization.md +++ b/src/doc/rustc-dev-guide/src/serialization.md @@ -1,4 +1,4 @@ -# Serialization in Rustc +# Serialization in rustc rustc has to [serialize] and deserialize various data during compilation. Specifically: diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md index bee783c0fa66..e906dd29f25f 100644 --- a/src/doc/rustc-dev-guide/src/test-implementation.md +++ b/src/doc/rustc-dev-guide/src/test-implementation.md @@ -83,7 +83,7 @@ with your hand-written one, it will not share a [Symbol][Symbol]. This technique prevents name collision during code generation and is the foundation of Rust's [`macro`] hygiene. -## Step 2: Harness Generation +## Step 2: Harness generation Now that our tests are accessible from the root of our crate, we need to do something with them using [`rustc_ast`][ast] generates a module like so: @@ -106,7 +106,7 @@ called [`test`][test] that is part of Rust core, that implements all of the runtime for testing. [`test`][test]'s interface is unstable, so the only stable way to interact with it is through the `#[test]` macro. -## Step 3: Test Object Generation +## Step 3: Test object generation If you've written tests in Rust before, you may be familiar with some of the optional attributes available on test functions. For example, a test can be diff --git a/src/doc/rustc-dev-guide/src/the-parser.md b/src/doc/rustc-dev-guide/src/the-parser.md index 60a71ae3873f..601a81e2e485 100644 --- a/src/doc/rustc-dev-guide/src/the-parser.md +++ b/src/doc/rustc-dev-guide/src/the-parser.md @@ -1,4 +1,4 @@ -# Lexing and Parsing +# Lexing and parsing The very first thing the compiler does is take the program (in UTF-8 Unicode text) and turn it into a data format the compiler can work with more conveniently than strings. @@ -59,7 +59,7 @@ Note that while parsing, we may encounter macro definitions or invocations. We set these aside to be expanded (see [Macro Expansion](./macro-expansion.md)). Expansion itself may require parsing the output of a macro, which may reveal more macros to be expanded, and so on. -## More on Lexical Analysis +## More on lexical analysis Code for lexical analysis is split between two crates: diff --git a/src/doc/rustc-dev-guide/src/unsafety-checking.md b/src/doc/rustc-dev-guide/src/unsafety-checking.md index 1130878944d2..fbc19d8961c5 100644 --- a/src/doc/rustc-dev-guide/src/unsafety-checking.md +++ b/src/doc/rustc-dev-guide/src/unsafety-checking.md @@ -1,4 +1,4 @@ -# Unsafety Checking +# Unsafety checking Certain expressions in Rust can violate memory safety and as such need to be inside an `unsafe` block or function. The compiler will also warn if an unsafe From 40bfc14c7d1d6ffc0a10453ae94e32fd0307e001 Mon Sep 17 00:00:00 2001 From: Urgau <3616612+Urgau@users.noreply.github.com> Date: Sat, 12 Apr 2025 18:24:59 +0200 Subject: [PATCH 015/109] Enable [canonicalize-issue-links] and [no-mentions] in triagebot.toml --- src/doc/rustc-dev-guide/triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index 12aa0b7b8ff1..6232dbf05fd3 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -7,5 +7,9 @@ allow-unauthenticated = [ "blocked", ] +[no-mentions] + +[canonicalize-issue-links] + # Automatically close and reopen PRs made by bots to run CI on them [bot-pull-requests] From 330daad17f67b285959774d56d9f607f1c16b5a8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 13 Apr 2025 00:47:54 +0000 Subject: [PATCH 016/109] cargo update compiler & tools dependencies: Locking 11 packages to latest compatible versions Updating bstr v1.11.3 -> v1.12.0 Updating clap v4.5.35 -> v4.5.36 Updating clap_builder v4.5.35 -> v4.5.36 Updating crossbeam-channel v0.5.14 -> v0.5.15 Updating jiff v0.2.5 -> v0.2.6 Updating jiff-static v0.2.5 -> v0.2.6 Updating jsonpath-rust v1.0.0 -> v1.0.1 Updating linux-raw-sys v0.9.3 -> v0.9.4 Updating miniz_oxide v0.8.7 -> v0.8.8 Updating self_cell v1.1.0 -> v1.2.0 Updating winnow v0.7.4 -> v0.7.6 note: pass `--verbose` to see 38 unchanged dependencies behind latest library dependencies: Locking 1 package to latest compatible version Updating miniz_oxide v0.8.7 -> v0.8.8 note: pass `--verbose` to see 4 unchanged dependencies behind latest rustbook dependencies: Locking 9 packages to latest compatible versions Updating bstr v1.11.3 -> v1.12.0 Updating cc v1.2.18 -> v1.2.19 Updating clap v4.5.35 -> v4.5.36 Updating clap_builder v4.5.35 -> v4.5.36 Updating jiff v0.2.5 -> v0.2.6 Updating jiff-static v0.2.5 -> v0.2.6 Updating linux-raw-sys v0.9.3 -> v0.9.4 Updating miniz_oxide v0.8.7 -> v0.8.8 Updating winnow v0.7.4 -> v0.7.6 --- Cargo.lock | 50 +++++++++++++++++------------------ library/Cargo.lock | 4 +-- src/tools/rustbook/Cargo.lock | 36 ++++++++++++------------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41288c55fe59..b29fa13407f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.4", + "winnow 0.7.6", ] [[package]] @@ -303,9 +303,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -496,9 +496,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -516,9 +516,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -1221,7 +1221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.7", + "miniz_oxide 0.8.8", ] [[package]] @@ -1918,9 +1918,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" dependencies = [ "jiff-static", "log", @@ -1931,9 +1931,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" dependencies = [ "proc-macro2", "quote", @@ -1987,9 +1987,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b0231bb404a6cd6c8f0ab41b907049063a089fc02aa7636cc5cd9a4d87364c9" +checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9" dependencies = [ "pest", "pest_derive", @@ -2121,9 +2121,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -2291,9 +2291,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -4839,14 +4839,14 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" dependencies = [ - "self_cell 1.1.0", + "self_cell 1.2.0", ] [[package]] name = "self_cell" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" @@ -6476,9 +6476,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] diff --git a/library/Cargo.lock b/library/Cargo.lock index d035ca6c91f5..29e0e134da7f 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", "compiler_builtins", diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 09bbbd61de50..e43d9a64162b 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.18" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", @@ -775,9 +775,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" dependencies = [ "jiff-static", "log", @@ -788,9 +788,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" dependencies = [ "proc-macro2", "quote", @@ -840,9 +840,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -981,9 +981,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -2012,9 +2012,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] From 8c378f79904fc665516723a41f86cb2b971a70b6 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 10 Apr 2025 07:14:39 +0800 Subject: [PATCH 017/109] tests: document `-A {unused,internal_features}` ui test mode presets --- src/doc/rustc-dev-guide/src/tests/ui.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 41dc9299a45d..e10bc2daadd0 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -576,3 +576,26 @@ the term "UI" (*user* interface) and turns such UI tests from black-box tests into white-box ones. Use them carefully and sparingly. [compiler debugging]: ../compiler-debugging.md#rustc_-test-attributes + +## UI test mode preset lint levels + +By default, test suites under UI test mode (`tests/ui`, `tests/ui-fulldeps`, +but not `tests/rustdoc-ui`) will specify + +- `-A unused` +- `-A internal_features` + +If: + +- The ui test's pass mode is below `run` (i.e. check or build). +- No compare modes are specified. + +Since they can be very noisy in ui tests. + +You can override them with `compile-flags` lint level flags or +in-source lint level attributes as required. + +Note that the `rustfix` version will *not* have `-A unused` passed, +meaning that you may have to `#[allow(unused)]` to suppress `unused` +lints on the rustfix'd file (because we might be testing rustfix +on `unused` lints themselves). From c1f0498e656665df438178bfd39ce75e321f191f Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 03:01:00 -0700 Subject: [PATCH 018/109] Hermit: Unify std::env::args with Unix The only differences between these implementations are that Unix uses relaxed ordering, but Hermit uses acquire/release, and Unix truncates `argv` at the first null pointer, but Hermit doesn't. Since Hermit aims for Unix compatibility, unify it with Unix. --- library/std/src/sys/args/hermit.rs | 35 ------------------------------ library/std/src/sys/args/mod.rs | 8 +++---- library/std/src/sys/args/unix.rs | 6 ++++- 3 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 library/std/src/sys/args/hermit.rs diff --git a/library/std/src/sys/args/hermit.rs b/library/std/src/sys/args/hermit.rs deleted file mode 100644 index ddd644a55404..000000000000 --- a/library/std/src/sys/args/hermit.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::ffi::{CStr, OsString, c_char}; -use crate::os::hermit::ffi::OsStringExt; -use crate::ptr; -use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::atomic::{AtomicIsize, AtomicPtr}; - -#[path = "common.rs"] -mod common; -pub use common::Args; - -static ARGC: AtomicIsize = AtomicIsize::new(0); -static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { - ARGC.store(argc, Relaxed); - // Use release ordering here to broadcast writes by the OS. - ARGV.store(argv as *mut *const u8, Release); -} - -/// Returns the command line arguments -pub fn args() -> Args { - // Synchronize with the store above. - let argv = ARGV.load(Acquire); - // If argv has not been initialized yet, do not return any arguments. - let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) }; - let args: Vec = (0..argc) - .map(|i| unsafe { - let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char); - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }) - .collect(); - - Args::new(args) -} diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index f24d6eb123e0..6a37b32d2293 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -3,15 +3,15 @@ #![forbid(unsafe_op_in_unsafe_fn)] cfg_if::cfg_if! { - if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] { + if #[cfg(any( + all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), + target_os = "hermit", + ))] { mod unix; pub use unix::*; } else if #[cfg(target_family = "windows")] { mod windows; pub use windows::*; - } else if #[cfg(target_os = "hermit")] { - mod hermit; - pub use hermit::*; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::*; diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs index 7d7815c6dff2..c087fd629651 100644 --- a/library/std/src/sys/args/unix.rs +++ b/library/std/src/sys/args/unix.rs @@ -6,6 +6,9 @@ #![allow(dead_code)] // runtime init functions not used during testing use crate::ffi::CStr; +#[cfg(target_os = "hermit")] +use crate::os::hermit::ffi::OsStringExt; +#[cfg(not(target_os = "hermit"))] use crate::os::unix::ffi::OsStringExt; #[path = "common.rs"] @@ -73,6 +76,7 @@ pub fn args() -> Args { target_os = "illumos", target_os = "emscripten", target_os = "haiku", + target_os = "hermit", target_os = "l4re", target_os = "fuchsia", target_os = "redox", @@ -100,7 +104,7 @@ mod imp { unsafe fn really_init(argc: isize, argv: *const *const u8) { // These don't need to be ordered with each other or other stores, - // because they only hold the unmodified system-provide argv/argc. + // because they only hold the unmodified system-provided argv/argc. ARGC.store(argc, Ordering::Relaxed); ARGV.store(argv as *mut _, Ordering::Relaxed); } From 8586cad77c175a0c2ce11c0579c537aa195e6da2 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 29 Mar 2025 02:04:10 +0100 Subject: [PATCH 019/109] Documentation and finishing touches --- compiler/rustc_span/src/hygiene.rs | 19 +++ .../traits/on_unimplemented.rs | 76 ++++++++-- .../traits/on_unimplemented_condition.rs | 69 +++++++--- .../traits/on_unimplemented_format.rs | 130 +++++++++++------- 4 files changed, 215 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9be16f8ce0c9..f6d69da9951f 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1270,6 +1270,25 @@ impl DesugaringKind { DesugaringKind::PatTyRange => "pattern type", } } + + /// For use with `rustc_unimplemented` to support conditions + /// like `from_desugaring = "QuestionMark"` + pub fn matches(&self, value: &str) -> bool { + match self { + DesugaringKind::CondTemporary => value == "CondTemporary", + DesugaringKind::Async => value == "Async", + DesugaringKind::Await => value == "Await", + DesugaringKind::QuestionMark => value == "QuestionMark", + DesugaringKind::TryBlock => value == "TryBlock", + DesugaringKind::YeetExpr => value == "YeetExpr", + DesugaringKind::OpaqueTy => value == "OpaqueTy", + DesugaringKind::ForLoop => value == "ForLoop", + DesugaringKind::WhileLoop => value == "WhileLoop", + DesugaringKind::BoundModifier => value == "BoundModifier", + DesugaringKind::Contract => value == "Contract", + DesugaringKind::PatTyRange => value == "PatTyRange", + } + } } #[derive(Default)] diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 7d8ecba3b2e0..0478f3a7f112 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -6,6 +6,7 @@ use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; +use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt}; @@ -17,7 +18,6 @@ use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; -use crate::error_reporting::traits::on_unimplemented_format::errors::*; use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatArgs, FormatString}; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, @@ -112,10 +112,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, // but I guess we could synthesize one here. We don't see any errors that rely on // that yet, though. - let item_context = self - .describe_enclosure(obligation.cause.body_id) - .map(|t| t.to_owned()) - .unwrap_or(String::new()); + let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or(""); let direct = match obligation.cause.code() { ObligationCauseCode::BuiltinDerived(..) @@ -128,7 +125,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - let from_desugaring = obligation.cause.span.desugaring_kind().map(|k| format!("{k:?}")); + let from_desugaring = obligation.cause.span.desugaring_kind(); let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { Some("MainFunctionType".to_string()) @@ -253,8 +250,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } })); - let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id).to_string(); - let trait_sugared = trait_pred.trait_ref.print_trait_sugared().to_string(); + let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id); + let trait_sugared = trait_pred.trait_ref.print_trait_sugared(); let condition_options = ConditionOptions { self_types, @@ -268,6 +265,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Unlike the generic_args earlier, // this one is *not* collected under `with_no_trimmed_paths!` // for printing the type to the user + // + // This includes `Self`, as it is the first parameter in `own_params`. let generic_args = self .tcx .generics_of(trait_pred.trait_ref.def_id) @@ -341,6 +340,63 @@ pub enum AppendConstMessage { Custom(Symbol, Span), } +#[derive(LintDiagnostic)] +#[diag(trait_selection_malformed_on_unimplemented_attr)] +#[help] +pub struct MalformedOnUnimplementedAttrLint { + #[label] + pub span: Span, +} + +impl MalformedOnUnimplementedAttrLint { + pub fn new(span: Span) -> Self { + Self { span } + } +} + +#[derive(LintDiagnostic)] +#[diag(trait_selection_missing_options_for_on_unimplemented_attr)] +#[help] +pub struct MissingOptionsForOnUnimplementedAttr; + +#[derive(LintDiagnostic)] +#[diag(trait_selection_ignored_diagnostic_option)] +pub struct IgnoredDiagnosticOption { + pub option_name: &'static str, + #[label] + pub span: Span, + #[label(trait_selection_other_label)] + pub prev_span: Span, +} + +impl IgnoredDiagnosticOption { + pub fn maybe_emit_warning<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + new: Option, + old: Option, + option_name: &'static str, + ) { + if let (Some(new_item), Some(old_item)) = (new, old) { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + new_item, + IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, + ); + } + } + } +} + +#[derive(LintDiagnostic)] +#[diag(trait_selection_wrapped_parser_error)] +pub struct WrappedParserError { + pub description: String, + pub label: String, +} + impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -664,7 +720,7 @@ impl<'tcx> OnUnimplementedDirective { tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, condition_options: &ConditionOptions, - args: &FormatArgs, + args: &FormatArgs<'tcx>, ) -> OnUnimplementedNote { let mut message = None; let mut label = None; @@ -784,7 +840,7 @@ impl<'tcx> OnUnimplementedFormatString { &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, - args: &FormatArgs, + args: &FormatArgs<'tcx>, ) -> String { let trait_def_id = trait_ref.def_id; let ctx = if self.is_diagnostic_namespace_variant { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 491ba6d7ffc0..116cfb01cb63 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -2,19 +2,10 @@ use rustc_ast::MetaItemInner; use rustc_attr_parsing as attr; use rustc_middle::ty::{self, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; -use rustc_span::{Span, Symbol, kw, sym}; - -pub static ALLOWED_CONDITION_SYMBOLS: &[Symbol] = &[ - sym::from_desugaring, - sym::direct, - sym::cause, - sym::integral, - sym::integer_, - sym::float, - sym::_Self, - sym::crate_local, -]; +use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; +/// A predicate in an attribute using on, all, any, +/// similar to a cfg predicate. #[derive(Debug)] pub struct Condition { pub inner: MetaItemInner, @@ -31,8 +22,7 @@ impl Condition { // `with_no_visible_paths` is also used when generating the options, // so we need to match it here. ty::print::with_no_visible_paths!({ - let mut parser = Parser::new(v.as_str(), None, None, false, ParseMode::Format); - let constructed_message = (&mut parser) + Parser::new(v.as_str(), None, None, false, ParseMode::Format) .map(|p| match p { Piece::Lit(s) => s.to_owned(), Piece::NextArgument(a) => match a.position { @@ -47,8 +37,7 @@ impl Condition { Position::ArgumentIs(idx) => format!("{{{idx}}}"), }, }) - .collect(); - constructed_message + .collect() }) }); @@ -57,13 +46,57 @@ impl Condition { } } +/// Used with `Condition::matches_predicate` to test whether the condition applies +/// +/// For example, given a +/// ```rust,ignore (just an example) +/// #[rustc_on_unimplemented( +/// on(all(from_desugaring = "QuestionMark"), +/// message = "the `?` operator can only be used in {ItemContext} \ +/// that returns `Result` or `Option` \ +/// (or another type that implements `{FromResidual}`)", +/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", +/// parent_label = "this function should return `Result` or `Option` to accept `?`" +/// ), +/// )] +/// pub trait FromResidual::Residual> { +/// ... +/// } +/// +/// async fn an_async_function() -> u32 { +/// let x: Option = None; +/// x?; //~ ERROR the `?` operator +/// 22 +/// } +/// ``` +/// it will look like this: +/// +/// ```rust,ignore (just an example) +/// ConditionOptions { +/// self_types: ["u32", "{integral}"], +/// from_desugaring: Some("QuestionMark"), +/// cause: None, +/// crate_local: false, +/// direct: true, +/// generic_args: [("Self","u32"), +/// ("R", "core::option::Option"), +/// ("R", "core::option::Option" ), +/// ], +/// } +/// ``` #[derive(Debug)] pub struct ConditionOptions { + /// All the self types that may apply. + /// for example pub self_types: Vec, - pub from_desugaring: Option, + // The kind of compiler desugaring. + pub from_desugaring: Option, + /// Match on a variant of [rustc_infer::traits::ObligationCauseCode] pub cause: Option, pub crate_local: bool, + /// Is the obligation "directly" user-specified, rather than derived? pub direct: bool, + // A list of the generic arguments and their reified types pub generic_args: Vec<(Symbol, String)>, } @@ -74,7 +107,7 @@ impl ConditionOptions { // from_desugaring as a flag (sym::from_desugaring, None) => self.from_desugaring.is_some(), // from_desugaring as key == value - (sym::from_desugaring, v) => *v == self.from_desugaring, + (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v), (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), (sym::crate_local, None) => self.crate_local, (sym::direct, None) => self.direct, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index 1bf15a345094..f835406122b8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -1,5 +1,8 @@ +use std::fmt; + use errors::*; use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_parse_format::{ Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -8,28 +11,39 @@ use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; -#[allow(dead_code)] +/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces", +/// either as string pieces or dynamic arguments. +#[derive(Debug)] pub struct FormatString { + #[allow(dead_code, reason = "Debug impl")] input: Symbol, - input_span: Span, + span: Span, pieces: Vec, - // the formatting string was parsed succesfully but with warnings + /// The formatting string was parsed succesfully but with warnings pub warnings: Vec, } +#[derive(Debug)] enum Piece { Lit(String), Arg(FormatArg), } -pub enum FormatArg { +#[derive(Debug)] +enum FormatArg { // A generic parameter, like `{T}` if we're on the `From` trait. - GenericParam { generic_param: Symbol, span: Span }, + GenericParam { + generic_param: Symbol, + }, // `{Self}` SelfUpper, + /// `{This}` or `{TraitName}` This, + /// The sugared form of the trait Trait, + /// what we're in, like a function, method, closure etc. ItemContext, + /// What the user typed, if it doesn't match anything we can use. AsIs(String), } @@ -40,6 +54,7 @@ pub enum Ctx<'tcx> { DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId }, } +#[derive(Debug)] pub enum FormatWarning { UnknownParam { argument_name: Symbol, span: Span }, PositionalArgument { span: Span, help: String }, @@ -95,26 +110,58 @@ impl FormatWarning { } } +/// Arguments to fill a [FormatString] with. +/// +/// For example, given a +/// ```rust,ignore (just an example) +/// +/// #[rustc_on_unimplemented( +/// on(all(from_desugaring = "QuestionMark"), +/// message = "the `?` operator can only be used in {ItemContext} \ +/// that returns `Result` or `Option` \ +/// (or another type that implements `{FromResidual}`)", +/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", +/// parent_label = "this function should return `Result` or `Option` to accept `?`" +/// ), +/// )] +/// pub trait FromResidual::Residual> { +/// ... +/// } +/// +/// async fn an_async_function() -> u32 { +/// let x: Option = None; +/// x?; //~ ERROR the `?` operator +/// 22 +/// } +/// ``` +/// it will look like this: +/// +/// ```rust,ignore (just an example) +/// FormatArgs { +/// this: "FromResidual", +/// trait_sugared: "FromResidual>", +/// item_context: "an async function", +/// generic_args: [("Self", "u32"), ("R", "Option")], +/// } +/// ``` #[derive(Debug)] -pub struct ConditionOptions { - pub self_types: Vec, - pub from_desugaring: Option, - pub cause: Option, - pub crate_local: bool, - pub direct: bool, - pub generic_args: Vec<(Symbol, String)>, -} - -#[derive(Debug)] -pub struct FormatArgs { +pub struct FormatArgs<'tcx> { pub this: String, - pub trait_sugared: String, - pub item_context: String, + pub trait_sugared: TraitRefPrintSugared<'tcx>, + pub item_context: &'static str, pub generic_args: Vec<(Symbol, String)>, } impl FormatString { - pub fn parse(input: Symbol, input_span: Span, ctx: &Ctx<'_>) -> Result> { + pub fn span(&self) -> Span { + self.span + } + + pub fn parse<'tcx>( + input: Symbol, + span: Span, + ctx: &Ctx<'tcx>, + ) -> Result> { let s = input.as_str(); let mut parser = Parser::new(s, None, None, false, ParseMode::Format); let mut pieces = Vec::new(); @@ -126,28 +173,28 @@ impl FormatString { pieces.push(Piece::Lit(lit.into())); } RpfPiece::NextArgument(arg) => { - warn_on_format_spec(arg.format, &mut warnings, input_span); - let arg = parse_arg(&arg, ctx, &mut warnings, input_span); + warn_on_format_spec(arg.format, &mut warnings, span); + let arg = parse_arg(&arg, ctx, &mut warnings, span); pieces.push(Piece::Arg(arg)); } } } if parser.errors.is_empty() { - Ok(FormatString { input, input_span, pieces, warnings }) + Ok(FormatString { input, pieces, span, warnings }) } else { Err(parser.errors) } } - pub fn format(&self, args: &FormatArgs) -> String { + pub fn format(&self, args: &FormatArgs<'_>) -> String { let mut ret = String::new(); for piece in &self.pieces { match piece { Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s), // `A` if we have `trait Trait {}` and `note = "i'm the actual type of {A}"` - Piece::Arg(FormatArg::GenericParam { generic_param, .. }) => { + Piece::Arg(FormatArg::GenericParam { generic_param }) => { // Should always be some but we can't raise errors here let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) { Some((_, val)) => val.to_string(), @@ -166,17 +213,19 @@ impl FormatString { // It's only `rustc_onunimplemented` from here Piece::Arg(FormatArg::This) => ret.push_str(&args.this), - Piece::Arg(FormatArg::Trait) => ret.push_str(&args.trait_sugared), - Piece::Arg(FormatArg::ItemContext) => ret.push_str(&args.item_context), + Piece::Arg(FormatArg::Trait) => { + let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared)); + } + Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context), } } ret } } -fn parse_arg( +fn parse_arg<'tcx>( arg: &Argument<'_>, - ctx: &Ctx<'_>, + ctx: &Ctx<'tcx>, warnings: &mut Vec, input_span: Span, ) -> FormatArg { @@ -233,7 +282,7 @@ fn parse_arg( Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, generic_param, ) if generics.own_params.iter().any(|param| param.name == generic_param) => { - FormatArg::GenericParam { generic_param, span } + FormatArg::GenericParam { generic_param } } (_, argument_name) => { @@ -286,6 +335,7 @@ fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec, } } +/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other fn slice_span(input: Span, inner: InnerSpan) -> Span { let InnerSpan { start, end } = inner; let span = input.data(); @@ -300,8 +350,6 @@ fn slice_span(input: Span, inner: InnerSpan) -> Span { pub mod errors { use rustc_macros::LintDiagnostic; - use rustc_middle::ty::TyCtxt; - use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::Ident; use super::*; @@ -324,26 +372,6 @@ pub mod errors { #[help] pub struct InvalidFormatSpecifier; - #[derive(LintDiagnostic)] - #[diag(trait_selection_wrapped_parser_error)] - pub struct WrappedParserError { - pub description: String, - pub label: String, - } - #[derive(LintDiagnostic)] - #[diag(trait_selection_malformed_on_unimplemented_attr)] - #[help] - pub struct MalformedOnUnimplementedAttrLint { - #[label] - pub span: Span, - } - - impl MalformedOnUnimplementedAttrLint { - pub fn new(span: Span) -> Self { - Self { span } - } - } - #[derive(LintDiagnostic)] #[diag(trait_selection_missing_options_for_on_unimplemented_attr)] #[help] From 9abaa9d4dffeb897a1dbff97d32d3b6ac190be21 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 29 Mar 2025 11:46:03 +0100 Subject: [PATCH 020/109] Disable usage on trait impls and aliases --- .../traits/on_unimplemented.rs | 17 +++++++--- tests/crashes/130627.rs | 20 ------------ .../ui/diagnostic_namespace/on_impl_trait.rs | 17 ++++++++++ .../diagnostic_namespace/on_impl_trait.stderr | 31 +++++++++++++++++++ tests/ui/on-unimplemented/impl-substs.stderr | 2 +- .../ui/on-unimplemented/multiple-impls.stderr | 12 +++---- tests/ui/on-unimplemented/on-impl.stderr | 4 +-- 7 files changed, 68 insertions(+), 35 deletions(-) delete mode 100644 tests/crashes/130627.rs create mode 100644 tests/ui/diagnostic_namespace/on_impl_trait.rs create mode 100644 tests/ui/diagnostic_namespace/on_impl_trait.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 0478f3a7f112..ca51f177f964 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -553,6 +553,13 @@ impl<'tcx> OnUnimplementedDirective { } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { + if !tcx.is_trait(item_def_id) { + // It could be a trait_alias (`trait MyTrait = SomeOtherTrait`) + // or an implementation (`impl MyTrait for Foo {}`) + // + // We don't support those. + return Ok(None); + } if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { return Self::parse_attribute(attr, false, tcx, item_def_id); } else { @@ -782,8 +789,10 @@ impl<'tcx> OnUnimplementedFormatString { Ok(result) } - fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> { - let trait_def_id = if tcx.is_trait(item_def_id) { item_def_id } else { return Ok(()) }; + fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> { + if !tcx.is_trait(trait_def_id) { + return Ok(()); + }; let ctx = if self.is_diagnostic_namespace_variant { Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id } @@ -810,10 +819,10 @@ impl<'tcx> OnUnimplementedFormatString { // so that users are aware that something is not correct for e in errors { if self.is_diagnostic_namespace_variant { - if let Some(item_def_id) = item_def_id.as_local() { + if let Some(trait_def_id) = trait_def_id.as_local() { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), + tcx.local_def_id_to_hir_id(trait_def_id), self.span, WrappedParserError { description: e.description, label: e.label }, ); diff --git a/tests/crashes/130627.rs b/tests/crashes/130627.rs deleted file mode 100644 index 59d3606592bf..000000000000 --- a/tests/crashes/130627.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: #130627 - -#![feature(trait_alias)] - -trait Test {} - -#[diagnostic::on_unimplemented( - message="message", - label="label", - note="note" -)] -trait Alias = Test; - -// Use trait alias as bound on type parameter. -fn foo(v: &T) { -} - -pub fn main() { - foo(&1); -} diff --git a/tests/ui/diagnostic_namespace/on_impl_trait.rs b/tests/ui/diagnostic_namespace/on_impl_trait.rs new file mode 100644 index 000000000000..32a492c53a95 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_impl_trait.rs @@ -0,0 +1,17 @@ +// used to ICE, see +// Instead it should just ignore the diagnostic attribute +#![feature(trait_alias)] + +trait Test {} + +#[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] +//~^ WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions +trait Alias = Test; + +// Use trait alias as bound on type parameter. +fn foo(v: &T) {} + +pub fn main() { + foo(&1); + //~^ ERROR the trait bound `{integer}: Alias` is not satisfied +} diff --git a/tests/ui/diagnostic_namespace/on_impl_trait.stderr b/tests/ui/diagnostic_namespace/on_impl_trait.stderr new file mode 100644 index 000000000000..59b9c31bc53e --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_impl_trait.stderr @@ -0,0 +1,31 @@ +warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions + --> $DIR/on_impl_trait.rs:7:1 + | +LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +error[E0277]: the trait bound `{integer}: Alias` is not satisfied + --> $DIR/on_impl_trait.rs:15:9 + | +LL | foo(&1); + | --- ^^ the trait `Test` is not implemented for `{integer}` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/on_impl_trait.rs:5:1 + | +LL | trait Test {} + | ^^^^^^^^^^ + = note: required for `{integer}` to implement `Alias` +note: required by a bound in `foo` + --> $DIR/on_impl_trait.rs:12:11 + | +LL | fn foo(v: &T) {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/impl-substs.stderr b/tests/ui/on-unimplemented/impl-substs.stderr index 0eabe9714922..2d83845ecb82 100644 --- a/tests/ui/on-unimplemented/impl-substs.stderr +++ b/tests/ui/on-unimplemented/impl-substs.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(i32, i32, i32): Foo` is not satisfied --> $DIR/impl-substs.rs:13:23 | LL | Foo::::foo((1i32, 1i32, 1i32)); - | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize {B} {C} + | ----------------- ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(i32, i32, i32)` | | | required by a bound introduced by this call | diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index ba4e43ff3594..2afc9b1bf3b8 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -15,11 +15,10 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:33 | LL | Index::index(&[] as &[i32], Foo(2u32)); - | ------------ ^^^^^^^^^ on impl for Foo + | ------------ ^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` | | | required by a bound introduced by this call | - = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: `[i32]` implements `Index>` `[i32]` implements `Index>` @@ -28,11 +27,10 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:33 | LL | Index::index(&[] as &[i32], Bar(2u32)); - | ------------ ^^^^^^^^^ on impl for Bar + | ------------ ^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` | | | required by a bound introduced by this call | - = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: `[i32]` implements `Index>` `[i32]` implements `Index>` @@ -52,9 +50,8 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:5 | LL | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` | - = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: `[i32]` implements `Index>` `[i32]` implements `Index>` @@ -63,9 +60,8 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:5 | LL | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` | - = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: `[i32]` implements `Index>` `[i32]` implements `Index>` diff --git a/tests/ui/on-unimplemented/on-impl.stderr b/tests/ui/on-unimplemented/on-impl.stderr index 5e7e2c4ea774..922db9db116e 100644 --- a/tests/ui/on-unimplemented/on-impl.stderr +++ b/tests/ui/on-unimplemented/on-impl.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:22:47 | LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ------------------- ^^^^ a usize is required to index into a slice + | ------------------- ^^^^ the trait `Index` is not implemented for `[i32]` | | | required by a bound introduced by this call | @@ -14,7 +14,7 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:22:5 | LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index` is not implemented for `[i32]` | = help: the trait `Index` is not implemented for `[i32]` but trait `Index` is implemented for it From 10ec5cbe96b8b1ba96fbacc207d6a2f0d19ca9e2 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 29 Mar 2025 13:48:14 +0100 Subject: [PATCH 021/109] Raise errors on bad rustc_on_unimplemented format strings again --- .../traits/on_unimplemented.rs | 38 +++++++++++++++++-- tests/ui/on-unimplemented/bad-annotation.rs | 2 +- .../ui/on-unimplemented/bad-annotation.stderr | 14 +++---- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index ca51f177f964..4c4491269b75 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -18,7 +18,9 @@ use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; -use crate::error_reporting::traits::on_unimplemented_format::{Ctx, FormatArgs, FormatString}; +use crate::error_reporting::traits::on_unimplemented_format::{ + Ctx, FormatArgs, FormatString, FormatWarning, +}; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; @@ -806,8 +808,38 @@ impl<'tcx> OnUnimplementedFormatString { // Warnings about format specifiers, deprecated parameters, wrong parameters etc. // In other words we'd like to let the author know, but we can still try to format the string later Ok(FormatString { warnings, .. }) => { - for w in warnings { - w.emit_warning(tcx, trait_def_id) + if self.is_diagnostic_namespace_variant { + for w in warnings { + w.emit_warning(tcx, trait_def_id) + } + } else { + for w in warnings { + match w { + FormatWarning::UnknownParam { argument_name, span } => { + let reported = struct_span_code_err!( + tcx.dcx(), + span, + E0230, + "cannot find parameter {} on this trait", + argument_name, + ) + .emit(); + result = Err(reported); + } + FormatWarning::PositionalArgument { span, .. } => { + let reported = struct_span_code_err!( + tcx.dcx(), + span, + E0231, + "positional format arguments are not allowed here" + ) + .emit(); + result = Err(reported); + } + FormatWarning::InvalidSpecifier { .. } + | FormatWarning::FutureIncompat { .. } => {} + } + } } } // Errors from the underlying `rustc_parse_format::Parser` diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 0936b25847c4..f2b978657597 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -20,7 +20,7 @@ trait BadAnnotation1 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] -//~^ WARNING there is no parameter `C` on trait `BadAnnotation2` +//~^ ERROR cannot find parameter C on this trait trait BadAnnotation2 {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 1fefd93aa7ec..afd737dc85e6 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -11,22 +11,17 @@ LL | #[rustc_on_unimplemented = "message"] LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -warning: there is no parameter `C` on trait `BadAnnotation2` +error[E0230]: cannot find parameter C on this trait --> $DIR/bad-annotation.rs:22:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] | ^ - | - = help: expect either a generic argument name or `{Self}` as format argument - = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default -warning: positional format arguments are not allowed here +error[E0231]: positional format arguments are not allowed here --> $DIR/bad-annotation.rs:27:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] | ^ - | - = help: only named format arguments with the name of one of the generic types are allowed in this context error[E0232]: this attribute must have a valid value --> $DIR/bad-annotation.rs:32:26 @@ -82,6 +77,7 @@ LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message | = note: eg `#[rustc_on_unimplemented(message="foo")]` -error: aborting due to 8 previous errors; 2 warnings emitted +error: aborting due to 10 previous errors -For more information about this error, try `rustc --explain E0232`. +Some errors have detailed explanations: E0230, E0231, E0232. +For more information about an error, try `rustc --explain E0230`. From 40e76c157548442fce755ec9cc2274aef11454ba Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 1 Apr 2025 02:47:12 +0200 Subject: [PATCH 022/109] Test that `Self` properly works in filters --- .../ui/on-unimplemented/use_self_no_underscore.rs | 14 ++++++++++++++ .../use_self_no_underscore.stderr | 15 +++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/on-unimplemented/use_self_no_underscore.rs create mode 100644 tests/ui/on-unimplemented/use_self_no_underscore.stderr diff --git a/tests/ui/on-unimplemented/use_self_no_underscore.rs b/tests/ui/on-unimplemented/use_self_no_underscore.rs new file mode 100644 index 000000000000..045ef1a5d3ff --- /dev/null +++ b/tests/ui/on-unimplemented/use_self_no_underscore.rs @@ -0,0 +1,14 @@ +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented(on( + all(A = "{integer}", any(Self = "[{integral}; _]",)), + message = "an array of type `{Self}` cannot be built directly from an iterator", +))] +pub trait FromIterator: Sized { + fn from_iter>(iter: T) -> Self; +} +fn main() { + let iter = 0..42_8; + let x: [u8; 8] = FromIterator::from_iter(iter); + //~^ ERROR an array of type `[u8; 8]` cannot be built directly from an iterator +} diff --git a/tests/ui/on-unimplemented/use_self_no_underscore.stderr b/tests/ui/on-unimplemented/use_self_no_underscore.stderr new file mode 100644 index 000000000000..d01aee3485f4 --- /dev/null +++ b/tests/ui/on-unimplemented/use_self_no_underscore.stderr @@ -0,0 +1,15 @@ +error[E0277]: an array of type `[u8; 8]` cannot be built directly from an iterator + --> $DIR/use_self_no_underscore.rs:12:22 + | +LL | let x: [u8; 8] = FromIterator::from_iter(iter); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromIterator<{integer}>` is not implemented for `[u8; 8]` + | +help: this trait has no implementations, consider adding one + --> $DIR/use_self_no_underscore.rs:7:1 + | +LL | pub trait FromIterator: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 4a5369b476fb17aa2db05b5b551eca0cfa6b2c6b Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:06:59 +0200 Subject: [PATCH 023/109] Remove rustc_on_unimplemented on impl tests --- src/tools/tidy/src/issues.txt | 1 - tests/ui/on-unimplemented/impl-substs.rs | 15 ---- tests/ui/on-unimplemented/impl-substs.stderr | 15 ---- tests/ui/on-unimplemented/issue-104140.rs | 8 --- tests/ui/on-unimplemented/issue-104140.stderr | 15 ---- tests/ui/on-unimplemented/multiple-impls.rs | 42 ----------- .../ui/on-unimplemented/multiple-impls.stderr | 71 ------------------- tests/ui/on-unimplemented/on-impl.rs | 25 ------- tests/ui/on-unimplemented/on-impl.stderr | 25 ------- 9 files changed, 217 deletions(-) delete mode 100644 tests/ui/on-unimplemented/impl-substs.rs delete mode 100644 tests/ui/on-unimplemented/impl-substs.stderr delete mode 100644 tests/ui/on-unimplemented/issue-104140.rs delete mode 100644 tests/ui/on-unimplemented/issue-104140.stderr delete mode 100644 tests/ui/on-unimplemented/multiple-impls.rs delete mode 100644 tests/ui/on-unimplemented/multiple-impls.stderr delete mode 100644 tests/ui/on-unimplemented/on-impl.rs delete mode 100644 tests/ui/on-unimplemented/on-impl.stderr diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index d2ae9b1f6ef8..5fa4a9fc2e36 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3138,7 +3138,6 @@ ui/nll/user-annotations/issue-55241.rs ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs ui/numbers-arithmetic/issue-8460.rs -ui/on-unimplemented/issue-104140.rs ui/or-patterns/issue-64879-trailing-before-guard.rs ui/or-patterns/issue-67514-irrefutable-param.rs ui/or-patterns/issue-68785-irrefutable-param-with-at.rs diff --git a/tests/ui/on-unimplemented/impl-substs.rs b/tests/ui/on-unimplemented/impl-substs.rs deleted file mode 100644 index fe9c50ec3d4a..000000000000 --- a/tests/ui/on-unimplemented/impl-substs.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(rustc_attrs)] - -trait Foo { - fn foo(self); -} - -#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"] -impl Foo for (A, B, C) { - fn foo(self) {} -} - -fn main() { - Foo::::foo((1i32, 1i32, 1i32)); - //~^ ERROR the trait bound `(i32, i32, i32): Foo` is not satisfied -} diff --git a/tests/ui/on-unimplemented/impl-substs.stderr b/tests/ui/on-unimplemented/impl-substs.stderr deleted file mode 100644 index 2d83845ecb82..000000000000 --- a/tests/ui/on-unimplemented/impl-substs.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0277]: the trait bound `(i32, i32, i32): Foo` is not satisfied - --> $DIR/impl-substs.rs:13:23 - | -LL | Foo::::foo((1i32, 1i32, 1i32)); - | ----------------- ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(i32, i32, i32)` - | | - | required by a bound introduced by this call - | - = help: the trait `Foo` is not implemented for `(i32, i32, i32)` - but trait `Foo` is implemented for it - = help: for that trait implementation, expected `i32`, found `usize` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/issue-104140.rs b/tests/ui/on-unimplemented/issue-104140.rs deleted file mode 100644 index ade3f727004a..000000000000 --- a/tests/ui/on-unimplemented/issue-104140.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(rustc_attrs)] - -trait Foo {} - -#[rustc_on_unimplemented] //~ ERROR malformed `rustc_on_unimplemented` attribute input -impl Foo for u32 {} - -fn main() {} diff --git a/tests/ui/on-unimplemented/issue-104140.stderr b/tests/ui/on-unimplemented/issue-104140.stderr deleted file mode 100644 index 3c317135dd43..000000000000 --- a/tests/ui/on-unimplemented/issue-104140.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: malformed `rustc_on_unimplemented` attribute input - --> $DIR/issue-104140.rs:5:1 - | -LL | #[rustc_on_unimplemented] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[rustc_on_unimplemented = "message"] - | +++++++++++ -LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 1 previous error - diff --git a/tests/ui/on-unimplemented/multiple-impls.rs b/tests/ui/on-unimplemented/multiple-impls.rs deleted file mode 100644 index b74957ebcd40..000000000000 --- a/tests/ui/on-unimplemented/multiple-impls.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Test if the on_unimplemented message override works - -#![feature(rustc_attrs)] - - -struct Foo(T); -struct Bar(T); - -#[rustc_on_unimplemented = "trait message"] -trait Index { - type Output: ?Sized; - fn index(&self, index: Idx) -> &Self::Output; -} - -#[rustc_on_unimplemented = "on impl for Foo"] -impl Index> for [i32] { - type Output = i32; - fn index(&self, _index: Foo) -> &i32 { - loop {} - } -} - -#[rustc_on_unimplemented = "on impl for Bar"] -impl Index> for [i32] { - type Output = i32; - fn index(&self, _index: Bar) -> &i32 { - loop {} - } -} - - -fn main() { - Index::index(&[] as &[i32], 2u32); - //~^ ERROR E0277 - //~| ERROR E0277 - Index::index(&[] as &[i32], Foo(2u32)); - //~^ ERROR E0277 - //~| ERROR E0277 - Index::index(&[] as &[i32], Bar(2u32)); - //~^ ERROR E0277 - //~| ERROR E0277 -} diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr deleted file mode 100644 index 2afc9b1bf3b8..000000000000 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ /dev/null @@ -1,71 +0,0 @@ -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/multiple-impls.rs:33:33 - | -LL | Index::index(&[] as &[i32], 2u32); - | ------------ ^^^^ trait message - | | - | required by a bound introduced by this call - | - = help: the trait `Index` is not implemented for `[i32]` - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:36:33 - | -LL | Index::index(&[] as &[i32], Foo(2u32)); - | ------------ ^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` - | | - | required by a bound introduced by this call - | - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:39:33 - | -LL | Index::index(&[] as &[i32], Bar(2u32)); - | ------------ ^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` - | | - | required by a bound introduced by this call - | - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/multiple-impls.rs:33:5 - | -LL | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message - | - = help: the trait `Index` is not implemented for `[i32]` - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:36:5 - | -LL | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` - | - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:39:5 - | -LL | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index>` is not implemented for `[i32]` - | - = help: the following other types implement trait `Index`: - `[i32]` implements `Index>` - `[i32]` implements `Index>` - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/on-impl.rs b/tests/ui/on-unimplemented/on-impl.rs deleted file mode 100644 index ab3e67d01fe4..000000000000 --- a/tests/ui/on-unimplemented/on-impl.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Test if the on_unimplemented message override works - -#![feature(rustc_attrs)] - - -#[rustc_on_unimplemented = "invalid"] -trait Index { - type Output: ?Sized; - fn index(&self, index: Idx) -> &Self::Output; -} - -#[rustc_on_unimplemented = "a usize is required to index into a slice"] -impl Index for [i32] { - type Output = i32; - fn index(&self, index: usize) -> &i32 { - &self[index] - } -} - - -fn main() { - Index::::index(&[1, 2, 3] as &[i32], 2u32); - //~^ ERROR E0277 - //~| ERROR E0277 -} diff --git a/tests/ui/on-unimplemented/on-impl.stderr b/tests/ui/on-unimplemented/on-impl.stderr deleted file mode 100644 index 922db9db116e..000000000000 --- a/tests/ui/on-unimplemented/on-impl.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/on-impl.rs:22:47 - | -LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ------------------- ^^^^ the trait `Index` is not implemented for `[i32]` - | | - | required by a bound introduced by this call - | - = help: the trait `Index` is not implemented for `[i32]` - but trait `Index` is implemented for it - = help: for that trait implementation, expected `usize`, found `u32` - -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/on-impl.rs:22:5 - | -LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Index` is not implemented for `[i32]` - | - = help: the trait `Index` is not implemented for `[i32]` - but trait `Index` is implemented for it - = help: for that trait implementation, expected `usize`, found `u32` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. From 9e99fc3a73ba3e74cc1bd7413d4ef0335130c369 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 14 Apr 2025 08:41:22 +0200 Subject: [PATCH 024/109] clean "Coding conventions" chapter - use correct code block markers - add missing title - rustfmt can now use edition setting in its config ... and this is set in Rust repo - reduce visual noise - needless repetition - convention is to start sentence with upper case - sembr - whitespace - semi-heading not adding much value - fix grammar --- src/doc/rustc-dev-guide/src/conventions.md | 65 +++++++++++----------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 0e624a4566d2..4356cf246f89 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -1,3 +1,5 @@ +# Coding conventions + This file offers some tips on the coding conventions for rustc. This chapter covers [formatting](#formatting), [coding for correctness](#cc), [using crates from crates.io](#cio), and some tips on @@ -5,7 +7,7 @@ chapter covers [formatting](#formatting), [coding for correctness](#cc), -# Formatting and the tidy script +## Formatting and the tidy script rustc is moving towards the [Rust standard coding style][fmt]. @@ -20,44 +22,42 @@ Formatting is checked by the `tidy` script. It runs automatically when you do `./x test` and can be run in isolation with `./x fmt --check`. If you want to use format-on-save in your editor, the pinned version of -`rustfmt` is built under `build//stage0/bin/rustfmt`. You'll have to -pass the `--edition=2021` argument yourself when calling -`rustfmt` directly. +`rustfmt` is built under `build//stage0/bin/rustfmt`. [fmt]: https://github.com/rust-dev-tools/fmt-rfcs - [`rustfmt`]:https://github.com/rust-lang/rustfmt -## Formatting C++ code +### Formatting C++ code The compiler contains some C++ code for interfacing with parts of LLVM that don't have a stable C API. When modifying that code, use this command to format it: -```sh -./x test tidy --extra-checks=cpp:fmt --bless +```console +./x test tidy --extra-checks cpp:fmt --bless ``` This uses a pinned version of `clang-format`, to avoid relying on the local environment. -## Formatting and linting Python code +### Formatting and linting Python code The Rust repository contains quite a lot of Python code. We try to keep -it both linted and formatted by the [ruff][ruff] tool. +it both linted and formatted by the [ruff] tool. When modifying Python code, use this command to format it: -```sh -./x test tidy --extra-checks=py:fmt --bless + +```console +./x test tidy --extra-checks py:fmt --bless ``` -and the following command to run lints: -```sh -./x test tidy --extra-checks=py:lint +And, the following command to run lints: + +```console +./x test tidy --extra-checks py:lint ``` -This uses a pinned version of `ruff`, to avoid relying on the local -environment. +These use a pinned version of `ruff`, to avoid relying on the local environment. [ruff]: https://github.com/astral-sh/ruff @@ -65,7 +65,7 @@ environment. -## Copyright notice +### Copyright notice In the past, files began with a copyright and license notice. Please **omit** @@ -75,41 +75,42 @@ MIT/Apache-2.0). All of the copyright notices should be gone by now, but if you come across one in the rust-lang/rust repo, feel free to open a PR to remove it. -## Line length +### Line length Lines should be at most 100 characters. It's even better if you can keep things to 80. -**Ignoring the line length limit.** Sometimes – in particular for -tests – it can be necessary to exempt yourself from this limit. In -that case, you can add a comment towards the top of the file like so: +Sometimes, and particularly for tests, it can be necessary to exempt yourself from this limit. +In that case, you can add a comment towards the top of the file like so: ```rust // ignore-tidy-linelength ``` -## Tabs vs spaces +### Tabs vs spaces -Prefer 4-space indent. +Prefer 4-space indents. -# Coding for correctness +## Coding for correctness Beyond formatting, there are a few other tips that are worth following. -## Prefer exhaustive matches +### Prefer exhaustive matches Using `_` in a match is convenient, but it means that when new variants are added to the enum, they may not get handled correctly. Ask yourself: if a new variant were added to this enum, what's the chance that it would want to use the `_` code, versus having some other treatment? Unless the answer is "low", then prefer an -exhaustive match. (The same advice applies to `if let` and `while -let`, which are effectively tests for a single variant.) +exhaustive match. -## Use "TODO" comments for things you don't want to forget +The same advice applies to `if let` and `while let`, +which are effectively tests for a single variant. + +### Use "TODO" comments for things you don't want to forget As a useful tool to yourself, you can insert a `// TODO` comment for something that you want to get back to before you land your PR: @@ -136,13 +137,13 @@ if foo { -# Using crates from crates.io +## Using crates from crates.io See the [crates.io dependencies][crates] section. -# How to structure your PR +## How to structure your PR How you prepare the commits in your PR can make a big difference for the reviewer. Here are some tips. @@ -172,7 +173,7 @@ require that every intermediate commit successfully builds – we only expect to be able to bisect at a PR level. However, if you *can* make individual commits build, that is always helpful. -# Naming conventions +## Naming conventions Apart from normal Rust style/naming conventions, there are also some specific to the compiler. From 8dc773296cf743af20b1174050431c29ba6a7427 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 14 Apr 2025 13:36:06 +0200 Subject: [PATCH 025/109] Clarify why SGX code specifies linkage/symbol names for certain statics Also update the symbol names as items have moved around a bit. The actual name isn't that important, it just needs to be unique. But for debugging it can be useful for it to point to the right place. --- library/std/src/sys/alloc/sgx.rs | 4 +++- library/std/src/sys/args/sgx.rs | 1 + library/std/src/sys/pal/sgx/abi/tls/mod.rs | 6 ++++-- library/std/src/sys/pal/sgx/os.rs | 6 ++++-- library/std/src/sys/pal/sgx/thread.rs | 3 ++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/alloc/sgx.rs b/library/std/src/sys/alloc/sgx.rs index f5c27688fbc8..7a846e2376b9 100644 --- a/library/std/src/sys/alloc/sgx.rs +++ b/library/std/src/sys/alloc/sgx.rs @@ -10,8 +10,10 @@ use crate::sys::pal::waitqueue::SpinMutex; // The current allocator here is the `dlmalloc` crate which we've got included // in the rust-lang/rust repository as a submodule. The crate is a port of // dlmalloc.c from C to Rust. +// +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys5alloc3sgx8DLMALLOCE")] static DLMALLOC: SpinMutex> = SpinMutex::new(dlmalloc::Dlmalloc::new_with_allocator(Sgx {})); diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index efc4b7918522..0185a8a60009 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -8,6 +8,7 @@ use crate::sys::pal::abi::usercalls::raw::ByteBuffer; use crate::sys_common::FromInner; use crate::{fmt, slice}; +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] #[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE")] static ARGS: AtomicUsize = AtomicUsize::new(0); diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs index 8e2b271f1c97..f082d94614b4 100644 --- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs @@ -11,15 +11,17 @@ const USIZE_BITS: usize = 64; const TLS_KEYS: usize = 128; // Same as POSIX minimum const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS; +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_KEY_IN_USEE")] static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT; macro_rules! dup { ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* )); (() $($val:tt)*) => ([$($val),*]) } +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_DESTRUCTORE")] static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0))); unsafe extern "C" { diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index b1ec2afd764e..010634cf3106 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -73,11 +73,13 @@ pub fn current_exe() -> io::Result { unsupported() } +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx2os3ENVE")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")] static ENV: AtomicUsize = AtomicUsize::new(0); +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx2os8ENV_INITE")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")] static ENV_INIT: Once = Once::new(); type EnvStore = Mutex>; diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index b6932df431f4..219ef1b7a989 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -45,8 +45,9 @@ mod task_queue { } } + // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] - #[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE")] + #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx6thread10TASK_QUEUEE")] static TASK_QUEUE: Mutex> = Mutex::new(Vec::new()); pub(super) fn lock() -> MutexGuard<'static, Vec> { From 1c1febc59db038876d7fe78a1f056bf324fdff6a Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 1 Apr 2025 11:19:57 +0300 Subject: [PATCH 026/109] add new config option: `include` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 25 ++++++++++++++++++++++- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 25ec64f90b53..2e8810812901 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -701,6 +701,7 @@ pub(crate) struct TomlConfig { target: Option>, dist: Option, profile: Option, + include: Option>, } /// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. @@ -753,7 +754,7 @@ trait Merge { impl Merge for TomlConfig { fn merge( &mut self, - TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id }: Self, + TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, replace: ReplaceOpt, ) { fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { @@ -766,6 +767,17 @@ impl Merge for TomlConfig { } } + for include_path in include.clone().unwrap_or_default() { + let included_toml = Config::get_toml(&include_path).unwrap_or_else(|e| { + eprintln!( + "ERROR: Failed to parse default config profile at '{}': {e}", + include_path.display() + ); + exit!(2); + }); + self.merge(included_toml, ReplaceOpt::Override); + } + self.change_id.inner.merge(change_id.inner, replace); self.profile.merge(profile, replace); @@ -1600,6 +1612,17 @@ impl Config { toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate); } + for include_path in toml.include.clone().unwrap_or_default() { + let included_toml = get_toml(&include_path).unwrap_or_else(|e| { + eprintln!( + "ERROR: Failed to parse default config profile at '{}': {e}", + include_path.display() + ); + exit!(2); + }); + toml.merge(included_toml, ReplaceOpt::Override); + } + let mut override_toml = TomlConfig::default(); for option in flags.set.iter() { fn get_table(option: &str) -> Result { diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 48b6f77e8a58..3f1885a425f8 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -396,4 +396,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.", }, + ChangeInfo { + change_id: 138934, + severity: ChangeSeverity::Info, + summary: "Added new option `include` to create config extensions.", + }, ]; From 89e3befe63f35b7556614d85ce63214f62a9a771 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 25 Mar 2025 20:17:32 +0300 Subject: [PATCH 027/109] document config extensions Signed-off-by: onur-ozkan --- .../rustc-dev-guide/src/building/suggested.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 43ff2ba726f9..5d37a78af885 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -20,6 +20,42 @@ your `.git/hooks` folder as `pre-push` (without the `.sh` extension!). You can also install the hook as a step of running `./x setup`! +## Config extensions + +When working on different tasks, you might need to switch between different bootstrap configurations. +Sometimes you may want to keep an old configuration for future use. But saving raw config values in +random files and manually copying and pasting them can quickly become messy, especially if you have a +long history of different configurations. + +To simplify managing multiple configurations, you can create config extensions. + +For example, you can create a simple config file named `cross.toml`: + +```toml +[build] +build = "x86_64-unknown-linux-gnu" +host = ["i686-unknown-linux-gnu"] +target = ["i686-unknown-linux-gnu"] + + +[llvm] +download-ci-llvm = false + +[target.x86_64-unknown-linux-gnu] +llvm-config = "/path/to/llvm-19/bin/llvm-config" +``` + +Then, include this in your `bootstrap.toml`: + +```toml +include = ["cross.toml"] +``` + +You can also include extensions within extensions recursively. + +**Note:** In the `include` field, the overriding logic follows a right-to-left order. Also, the outer +extension/config always overrides the inner ones. + ## Configuring `rust-analyzer` for `rustc` ### Project-local rust-analyzer setup From 4e80659b32a794513646b93890c9a6eeb103de17 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 1 Apr 2025 11:44:33 +0300 Subject: [PATCH 028/109] implement cyclic inclusion handling Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 51 ++++++++++++++++++------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2e8810812901..86566d0eee17 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -6,6 +6,7 @@ use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::{self, Display}; +use std::hash::Hash; use std::io::IsTerminal; use std::path::{Path, PathBuf, absolute}; use std::process::Command; @@ -748,19 +749,25 @@ enum ReplaceOpt { } trait Merge { - fn merge(&mut self, other: Self, replace: ReplaceOpt); + fn merge( + &mut self, + included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt, + ); } impl Merge for TomlConfig { fn merge( &mut self, + included_extensions: &mut HashSet, TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, replace: ReplaceOpt, ) { fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { if let Some(new) = y { if let Some(original) = x { - original.merge(new, replace); + original.merge(&mut Default::default(), new, replace); } else { *x = Some(new); } @@ -775,11 +782,20 @@ impl Merge for TomlConfig { ); exit!(2); }); - self.merge(included_toml, ReplaceOpt::Override); + + assert!( + included_extensions.insert(include_path.clone()), + "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", + include_path.display() + ); + + self.merge(included_extensions, included_toml, ReplaceOpt::Override); + + included_extensions.remove(&include_path); } - self.change_id.inner.merge(change_id.inner, replace); - self.profile.merge(profile, replace); + self.change_id.inner.merge(&mut Default::default(), change_id.inner, replace); + self.profile.merge(&mut Default::default(), profile, replace); do_merge(&mut self.build, build, replace); do_merge(&mut self.install, install, replace); @@ -794,7 +810,7 @@ impl Merge for TomlConfig { (Some(original_target), Some(new_target)) => { for (triple, new) in new_target { if let Some(original) = original_target.get_mut(&triple) { - original.merge(new, replace); + original.merge(&mut Default::default(), new, replace); } else { original_target.insert(triple, new); } @@ -815,7 +831,7 @@ macro_rules! define_config { } impl Merge for $name { - fn merge(&mut self, other: Self, replace: ReplaceOpt) { + fn merge(&mut self, _included_extensions: &mut HashSet, other: Self, replace: ReplaceOpt) { $( match replace { ReplaceOpt::IgnoreDuplicate => { @@ -915,7 +931,12 @@ macro_rules! define_config { } impl Merge for Option { - fn merge(&mut self, other: Self, replace: ReplaceOpt) { + fn merge( + &mut self, + _included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt, + ) { match replace { ReplaceOpt::IgnoreDuplicate => { if self.is_none() { @@ -1609,7 +1630,7 @@ impl Config { ); exit!(2); }); - toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate); + toml.merge(&mut Default::default(), included_toml, ReplaceOpt::IgnoreDuplicate); } for include_path in toml.include.clone().unwrap_or_default() { @@ -1620,7 +1641,7 @@ impl Config { ); exit!(2); }); - toml.merge(included_toml, ReplaceOpt::Override); + toml.merge(&mut Default::default(), included_toml, ReplaceOpt::Override); } let mut override_toml = TomlConfig::default(); @@ -1631,7 +1652,7 @@ impl Config { let mut err = match get_table(option) { Ok(v) => { - override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); + override_toml.merge(&mut Default::default(), v, ReplaceOpt::ErrorOnDuplicate); continue; } Err(e) => e, @@ -1642,7 +1663,11 @@ impl Config { if !value.contains('"') { match get_table(&format!(r#"{key}="{value}""#)) { Ok(v) => { - override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); + override_toml.merge( + &mut Default::default(), + v, + ReplaceOpt::ErrorOnDuplicate, + ); continue; } Err(e) => err = e, @@ -1652,7 +1677,7 @@ impl Config { eprintln!("failed to parse override `{option}`: `{err}"); exit!(2) } - toml.merge(override_toml, ReplaceOpt::Override); + toml.merge(&mut Default::default(), override_toml, ReplaceOpt::Override); config.change_id = toml.change_id.inner; From 78cb4538ee203b08441382b5cd64b1989ed5b3b9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 1 Apr 2025 11:53:32 +0300 Subject: [PATCH 029/109] document `include` in `bootstrap.example.toml` Signed-off-by: onur-ozkan --- bootstrap.example.toml | 5 +++++ src/doc/rustc-dev-guide/src/building/suggested.md | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 0927f648635c..0a314f65ec22 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -19,6 +19,11 @@ # Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`). #profile = +# Inherits configuration values from different configuration files (a.k.a. config extensions). +# Supports absolute paths, and uses the current directory (where the bootstrap was invoked) +# as the base if the given path is not absolute. +#include = [] + # Keeps track of major changes made to this configuration. # # This value also represents ID of the PR that caused major changes. Meaning, diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 5d37a78af885..b2e258be079d 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -53,8 +53,9 @@ include = ["cross.toml"] You can also include extensions within extensions recursively. -**Note:** In the `include` field, the overriding logic follows a right-to-left order. Also, the outer -extension/config always overrides the inner ones. +**Note:** In the `include` field, the overriding logic follows a right-to-left order. For example, +in `include = ["a.toml", "b.toml"]`, extension `b.toml` overrides `a.toml`. Also, parent extensions +always overrides the inner ones. ## Configuring `rust-analyzer` for `rustc` From 3f70f197f2d131a1f57912f202072b2447d3e326 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 1 Apr 2025 21:56:58 +0000 Subject: [PATCH 030/109] apply nit notes Signed-off-by: onur-ozkan --- bootstrap.example.toml | 3 + src/bootstrap/src/core/config/config.rs | 95 ++++++++++++++++++------- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 0a314f65ec22..72c4492d465d 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -22,6 +22,9 @@ # Inherits configuration values from different configuration files (a.k.a. config extensions). # Supports absolute paths, and uses the current directory (where the bootstrap was invoked) # as the base if the given path is not absolute. +# +# The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`, +# extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones. #include = [] # Keeps track of major changes made to this configuration. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 86566d0eee17..e70ac74c7dae 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -751,6 +751,7 @@ enum ReplaceOpt { trait Merge { fn merge( &mut self, + parent_config_path: Option, included_extensions: &mut HashSet, other: Self, replace: ReplaceOpt, @@ -760,6 +761,7 @@ trait Merge { impl Merge for TomlConfig { fn merge( &mut self, + parent_config_path: Option, included_extensions: &mut HashSet, TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, replace: ReplaceOpt, @@ -767,19 +769,27 @@ impl Merge for TomlConfig { fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { if let Some(new) = y { if let Some(original) = x { - original.merge(&mut Default::default(), new, replace); + original.merge(None, &mut Default::default(), new, replace); } else { *x = Some(new); } } } - for include_path in include.clone().unwrap_or_default() { + let parent_dir = parent_config_path + .as_ref() + .and_then(|p| p.parent().map(ToOwned::to_owned)) + .unwrap_or_default(); + + for include_path in include.clone().unwrap_or_default().iter().rev() { + let include_path = parent_dir.join(include_path); + let include_path = include_path.canonicalize().unwrap_or_else(|e| { + eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); + exit!(2); + }); + let included_toml = Config::get_toml(&include_path).unwrap_or_else(|e| { - eprintln!( - "ERROR: Failed to parse default config profile at '{}': {e}", - include_path.display() - ); + eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); exit!(2); }); @@ -789,13 +799,20 @@ impl Merge for TomlConfig { include_path.display() ); - self.merge(included_extensions, included_toml, ReplaceOpt::Override); + self.merge( + Some(include_path.clone()), + included_extensions, + included_toml, + // Ensures that parent configuration always takes precedence + // over child configurations. + ReplaceOpt::IgnoreDuplicate, + ); included_extensions.remove(&include_path); } - self.change_id.inner.merge(&mut Default::default(), change_id.inner, replace); - self.profile.merge(&mut Default::default(), profile, replace); + self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); + self.profile.merge(None, &mut Default::default(), profile, replace); do_merge(&mut self.build, build, replace); do_merge(&mut self.install, install, replace); @@ -810,7 +827,7 @@ impl Merge for TomlConfig { (Some(original_target), Some(new_target)) => { for (triple, new) in new_target { if let Some(original) = original_target.get_mut(&triple) { - original.merge(&mut Default::default(), new, replace); + original.merge(None, &mut Default::default(), new, replace); } else { original_target.insert(triple, new); } @@ -831,7 +848,13 @@ macro_rules! define_config { } impl Merge for $name { - fn merge(&mut self, _included_extensions: &mut HashSet, other: Self, replace: ReplaceOpt) { + fn merge( + &mut self, + _parent_config_path: Option, + _included_extensions: &mut HashSet, + other: Self, + replace: ReplaceOpt + ) { $( match replace { ReplaceOpt::IgnoreDuplicate => { @@ -933,6 +956,7 @@ macro_rules! define_config { impl Merge for Option { fn merge( &mut self, + _parent_config_path: Option, _included_extensions: &mut HashSet, other: Self, replace: ReplaceOpt, @@ -1581,7 +1605,8 @@ impl Config { // but not if `bootstrap.toml` hasn't been created. let mut toml = if !using_default_path || toml_path.exists() { config.config = Some(if cfg!(not(test)) { - toml_path.canonicalize().unwrap() + toml_path = toml_path.canonicalize().unwrap(); + toml_path.clone() } else { toml_path.clone() }); @@ -1609,6 +1634,24 @@ impl Config { toml.profile = Some("dist".into()); } + // Reverse the list to ensure the last added config extension remains the most dominant. + // For example, given ["a.toml", "b.toml"], "b.toml" should take precedence over "a.toml". + // + // This must be handled before applying the `profile` since `include`s should always take + // precedence over `profile`s. + for include_path in toml.include.clone().unwrap_or_default().iter().rev() { + let included_toml = get_toml(include_path).unwrap_or_else(|e| { + eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); + exit!(2); + }); + toml.merge( + Some(toml_path.join(include_path)), + &mut Default::default(), + included_toml, + ReplaceOpt::IgnoreDuplicate, + ); + } + if let Some(include) = &toml.profile { // Allows creating alias for profile names, allowing // profiles to be renamed while maintaining back compatibility @@ -1630,18 +1673,12 @@ impl Config { ); exit!(2); }); - toml.merge(&mut Default::default(), included_toml, ReplaceOpt::IgnoreDuplicate); - } - - for include_path in toml.include.clone().unwrap_or_default() { - let included_toml = get_toml(&include_path).unwrap_or_else(|e| { - eprintln!( - "ERROR: Failed to parse default config profile at '{}': {e}", - include_path.display() - ); - exit!(2); - }); - toml.merge(&mut Default::default(), included_toml, ReplaceOpt::Override); + toml.merge( + Some(include_path), + &mut Default::default(), + included_toml, + ReplaceOpt::IgnoreDuplicate, + ); } let mut override_toml = TomlConfig::default(); @@ -1652,7 +1689,12 @@ impl Config { let mut err = match get_table(option) { Ok(v) => { - override_toml.merge(&mut Default::default(), v, ReplaceOpt::ErrorOnDuplicate); + override_toml.merge( + None, + &mut Default::default(), + v, + ReplaceOpt::ErrorOnDuplicate, + ); continue; } Err(e) => e, @@ -1664,6 +1706,7 @@ impl Config { match get_table(&format!(r#"{key}="{value}""#)) { Ok(v) => { override_toml.merge( + None, &mut Default::default(), v, ReplaceOpt::ErrorOnDuplicate, @@ -1677,7 +1720,7 @@ impl Config { eprintln!("failed to parse override `{option}`: `{err}"); exit!(2) } - toml.merge(&mut Default::default(), override_toml, ReplaceOpt::Override); + toml.merge(None, &mut Default::default(), override_toml, ReplaceOpt::Override); config.change_id = toml.change_id.inner; From 8e6f50bb4d30801d04619a4cd6406b320eb8919f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 15 Apr 2025 10:44:19 +0300 Subject: [PATCH 031/109] fix path and the ordering logic Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 54 +++++++++++++------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e70ac74c7dae..19ed442c500f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -776,6 +776,30 @@ impl Merge for TomlConfig { } } + self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); + self.profile.merge(None, &mut Default::default(), profile, replace); + + do_merge(&mut self.build, build, replace); + do_merge(&mut self.install, install, replace); + do_merge(&mut self.llvm, llvm, replace); + do_merge(&mut self.gcc, gcc, replace); + do_merge(&mut self.rust, rust, replace); + do_merge(&mut self.dist, dist, replace); + + match (self.target.as_mut(), target) { + (_, None) => {} + (None, Some(target)) => self.target = Some(target), + (Some(original_target), Some(new_target)) => { + for (triple, new) in new_target { + if let Some(original) = original_target.get_mut(&triple) { + original.merge(None, &mut Default::default(), new, replace); + } else { + original_target.insert(triple, new); + } + } + } + } + let parent_dir = parent_config_path .as_ref() .and_then(|p| p.parent().map(ToOwned::to_owned)) @@ -810,30 +834,6 @@ impl Merge for TomlConfig { included_extensions.remove(&include_path); } - - self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); - self.profile.merge(None, &mut Default::default(), profile, replace); - - do_merge(&mut self.build, build, replace); - do_merge(&mut self.install, install, replace); - do_merge(&mut self.llvm, llvm, replace); - do_merge(&mut self.gcc, gcc, replace); - do_merge(&mut self.rust, rust, replace); - do_merge(&mut self.dist, dist, replace); - - match (self.target.as_mut(), target) { - (_, None) => {} - (None, Some(target)) => self.target = Some(target), - (Some(original_target), Some(new_target)) => { - for (triple, new) in new_target { - if let Some(original) = original_target.get_mut(&triple) { - original.merge(None, &mut Default::default(), new, replace); - } else { - original_target.insert(triple, new); - } - } - } - } } } @@ -1640,12 +1640,14 @@ impl Config { // This must be handled before applying the `profile` since `include`s should always take // precedence over `profile`s. for include_path in toml.include.clone().unwrap_or_default().iter().rev() { - let included_toml = get_toml(include_path).unwrap_or_else(|e| { + let include_path = toml_path.parent().unwrap().join(include_path); + + let included_toml = get_toml(&include_path).unwrap_or_else(|e| { eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); exit!(2); }); toml.merge( - Some(toml_path.join(include_path)), + Some(include_path), &mut Default::default(), included_toml, ReplaceOpt::IgnoreDuplicate, From 7dfb457745d7f873eb5db1c3fb39d58fa768740d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 15 Apr 2025 11:53:21 +0300 Subject: [PATCH 032/109] add FIXME note in `TomlConfig::merge` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 19ed442c500f..b7afd81dfdb5 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -812,6 +812,8 @@ impl Merge for TomlConfig { exit!(2); }); + // FIXME: Similar to `Config::parse_inner`, allow passing a custom `get_toml` from the caller to + // improve testability since `Config::get_toml` does nothing when `cfg(test)` is enabled. let included_toml = Config::get_toml(&include_path).unwrap_or_else(|e| { eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); exit!(2); From 6d52b51d3e6321b7a1d24e5f995aa709057153e3 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 15 Apr 2025 19:10:31 +0300 Subject: [PATCH 033/109] add comment in `TomlConfig::merge` about the merge order Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b7afd81dfdb5..e15aab4ad506 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -805,6 +805,8 @@ impl Merge for TomlConfig { .and_then(|p| p.parent().map(ToOwned::to_owned)) .unwrap_or_default(); + // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to + // keep the upper-level configuration to take precedence. for include_path in include.clone().unwrap_or_default().iter().rev() { let include_path = parent_dir.join(include_path); let include_path = include_path.canonicalize().unwrap_or_else(|e| { From 855ecf9a9622db7d92e50f2dfd6d163ef059fa8c Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 16 Apr 2025 13:09:29 +0800 Subject: [PATCH 034/109] Remind to update dev branch while behind too many commits Signed-off-by: xizheyin --- src/doc/rustc-dev-guide/src/contributing.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 09a7f912b988..8c59ac6ef37a 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -150,6 +150,20 @@ when contributing to Rust under [the git section](./git.md). [t-compiler]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler [triagebot]: https://github.com/rust-lang/rust/blob/master/triagebot.toml +### Keeping your branch up-to-date + +The CI in rust-lang/rust applies your patches directly against the current master, +not against the commit your branch is based on. This can lead to unexpected failures +if your branch is outdated, even when there are no explicit merge conflicts. + +Before submitting or updating a PR, make sure to update your branch +as mentioned [here](git.md#keeping-things-up-to-date) if it's significantly +behind the master branch (e.g., more than 100 commits behind). +This fetches the latest master branch and rebases your changes on top of it, +ensuring your PR is tested against the latest code. + +After rebasing, it's recommended to [run the relevant tests locally](tests/intro.md) to catch any issues before CI runs. + ### r? All pull requests are reviewed by another person. We have a bot, From 2024e26881ea8bdfb41f53e257464be4332abc79 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 15 Apr 2025 01:01:51 +0000 Subject: [PATCH 035/109] Don't canonicalize crate paths --- compiler/rustc_metadata/src/locator.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 112954eca0df..f0a898d678ca 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -427,12 +427,21 @@ impl<'a> CrateLocator<'a> { let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default(); - let path = - try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.to_path_buf()); - if seen_paths.contains(&path) { - continue; - }; - seen_paths.insert(path.clone()); + { + // As a perforamnce optimisation we canonicalize the path and skip + // ones we've already seeen. This allows us to ignore crates + // we know are exactual equal to ones we've already found. + // Going to the same crate through different symlinks does not change the result. + let path = try_canonicalize(&spf.path) + .unwrap_or_else(|_| spf.path.to_path_buf()); + if seen_paths.contains(&path) { + continue; + }; + seen_paths.insert(path); + } + // Use the original path (potentially with unresolved symlinks), + // filesystem code should not care, but this is nicer for diagnostics. + let path = spf.path.to_path_buf(); match kind { CrateFlavor::Rlib => rlibs.insert(path, search_path.kind), CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind), From 52f35d013116559035621eb83d0e9680ecf74a49 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 15 Apr 2025 12:55:33 +0000 Subject: [PATCH 036/109] Test for relative paths in crate path diagnostics --- .../crateresolve1-1.rs | 6 ++++ .../crateresolve1-2.rs | 6 ++++ .../multiple-candidates.rs | 3 ++ .../multiple-candidates.stderr | 12 +++++++ .../rmake.rs | 34 +++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs create mode 100644 tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs create mode 100644 tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs create mode 100644 tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr create mode 100644 tests/run-make/crate-loading-multiple-candidates/rmake.rs diff --git a/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs new file mode 100644 index 000000000000..fe00f041a862 --- /dev/null +++ b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs @@ -0,0 +1,6 @@ +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { + 10 +} diff --git a/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs new file mode 100644 index 000000000000..0fb8591b3a52 --- /dev/null +++ b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs @@ -0,0 +1,6 @@ +#![crate_name = "crateresolve1"] +#![crate_type = "lib"] + +pub fn f() -> isize { + 20 +} diff --git a/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs new file mode 100644 index 000000000000..27cd7ca5c203 --- /dev/null +++ b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs @@ -0,0 +1,3 @@ +extern crate crateresolve1; + +fn main() {} diff --git a/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr new file mode 100644 index 000000000000..de7fc3b0feb9 --- /dev/null +++ b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr @@ -0,0 +1,12 @@ +error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found + --> multiple-candidates.rs:1:1 + | +LL | extern crate crateresolve1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidate #1: ./mylibs/libcrateresolve1-1.rlib + = note: candidate #2: ./mylibs/libcrateresolve1-2.rlib + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0464`. diff --git a/tests/run-make/crate-loading-multiple-candidates/rmake.rs b/tests/run-make/crate-loading-multiple-candidates/rmake.rs new file mode 100644 index 000000000000..ce090850500b --- /dev/null +++ b/tests/run-make/crate-loading-multiple-candidates/rmake.rs @@ -0,0 +1,34 @@ +//@ needs-symlink +//@ ignore-cross-compile + +// Tests that the multiple candidate dependencies diagnostic prints relative +// paths if a relative library path was passed in. + +use run_make_support::{bare_rustc, diff, rfs, rustc}; + +fn main() { + // Check that relative paths are preserved in the diagnostic + rfs::create_dir("mylibs"); + rustc().input("crateresolve1-1.rs").out_dir("mylibs").extra_filename("-1").run(); + rustc().input("crateresolve1-2.rs").out_dir("mylibs").extra_filename("-2").run(); + check("./mylibs"); + + // Check that symlinks aren't followed when printing the diagnostic + rfs::rename("mylibs", "original"); + rfs::symlink_dir("original", "mylibs"); + check("./mylibs"); +} + +fn check(library_path: &str) { + let out = rustc() + .input("multiple-candidates.rs") + .library_search_path(library_path) + .ui_testing() + .run_fail() + .stderr_utf8(); + diff() + .expected_file("multiple-candidates.stderr") + .normalize(r"\\", "/") + .actual_text("(rustc)", &out) + .run(); +} From 827047895a4c036f652b7105443f6305164f0e25 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 16 Apr 2025 20:53:51 +0300 Subject: [PATCH 037/109] resolve config include FIXME Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e15aab4ad506..0c221abc9698 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -814,9 +814,7 @@ impl Merge for TomlConfig { exit!(2); }); - // FIXME: Similar to `Config::parse_inner`, allow passing a custom `get_toml` from the caller to - // improve testability since `Config::get_toml` does nothing when `cfg(test)` is enabled. - let included_toml = Config::get_toml(&include_path).unwrap_or_else(|e| { + let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); exit!(2); }); @@ -1424,13 +1422,15 @@ impl Config { Self::get_toml(&builder_config_path) } - #[cfg(test)] - pub(crate) fn get_toml(_: &Path) -> Result { - Ok(TomlConfig::default()) + pub(crate) fn get_toml(file: &Path) -> Result { + #[cfg(test)] + return Ok(TomlConfig::default()); + + #[cfg(not(test))] + Self::get_toml_inner(file) } - #[cfg(not(test))] - pub(crate) fn get_toml(file: &Path) -> Result { + fn get_toml_inner(file: &Path) -> Result { let contents = t!(fs::read_to_string(file), format!("config file {} not found", file.display())); // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of From abf401df1c6326a5c701061aa49b9b64554d38c2 Mon Sep 17 00:00:00 2001 From: Kent Ross Date: Wed, 16 Apr 2025 18:53:40 -0700 Subject: [PATCH 038/109] fix missing word in comment --- library/core/src/any.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 10f2a11d558b..7aa3f3c6d743 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -772,8 +772,8 @@ impl hash::Hash for TypeId { // (especially given the previous point about the lower 64 bits being // high quality on their own). // - It is correct to do so -- only hashing a subset of `self` is still - // with an `Eq` implementation that considers the entire value, as - // ours does. + // compatible with an `Eq` implementation that considers the entire + // value, as ours does. self.t.1.hash(state); } } From 1236dcb9ce0a2c0dd228b1ba705bd4537925d6ae Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 16 Apr 2025 20:03:05 -0400 Subject: [PATCH 039/109] add a first version of autodiff docs --- src/doc/rustc-dev-guide/src/SUMMARY.md | 5 + .../rustc-dev-guide/src/autodiff/debugging.md | 113 ++++++++++++++++++ src/doc/rustc-dev-guide/src/autodiff/flags.md | 42 +++++++ .../rustc-dev-guide/src/autodiff/internals.md | 27 +++++ .../src/autodiff/limitations.md | 27 +++++ 5 files changed, 214 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/autodiff/debugging.md create mode 100644 src/doc/rustc-dev-guide/src/autodiff/flags.md create mode 100644 src/doc/rustc-dev-guide/src/autodiff/internals.md create mode 100644 src/doc/rustc-dev-guide/src/autodiff/limitations.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 95a3cd7c7909..d8c7243f693b 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -99,6 +99,11 @@ - [Rustdoc internals](./rustdoc-internals.md) - [Search](./rustdoc-internals/search.md) - [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md) +- [Autodiff internals](./autodiff/internals.md) + - [How to debug](./autodiff/debugging.md) + - [Autodiff flags](./autodiff/flags.md) + - [Current limitations](./autodiff/limitations.md) + # Source Code Representation - [Prologue](./part-3-intro.md) diff --git a/src/doc/rustc-dev-guide/src/autodiff/debugging.md b/src/doc/rustc-dev-guide/src/autodiff/debugging.md new file mode 100644 index 000000000000..bd46a66fade4 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/debugging.md @@ -0,0 +1,113 @@ +# Reporting backend crashes + +If after a compilation failure you are greeted by a large amount of llvm-ir code, then our enzyme backend likely failed to compile your code. These cases are harder to debug, so your help is highly appreciated. Please also keep in mind that release builds are usually much more likely to work at the moment. + +The final goal here is to reproduce your bug in the enzyme [compiler explorer](https://enzyme.mit.edu/explorer/), in order to create a bug report in the [Enzyme](https://github.com/enzymead/enzyme/issues) repository. + +We have an `autodiff` flag which you can pass to `rustflags` to help with this. it will print the whole llvm-ir module, along with some `__enzyme_fwddiff` or `__enzyme_autodiff` calls. A potential workflow on linux could look like: + +## Controlling llvm-ir generation + +Before generating the llvm-ir, keep in mind two techniques that can help ensure the relevant rust code is visible for debugging: + +- **`std::hint::black_box`**: wrap rust variables or expressions in `std::hint::black_box()` to prevent rust and llvm from optimizing them away. This is useful when you need to inspect or manually manipulate specific values in the llvm-ir. +- **`extern "rust"` or `extern "c"`**: if you want to see how a specific function declaration is lowered to llvm-ir, you can declare it as `extern "rust"` or `extern "c"`. You can also look for existing `__enzyme_autodiff` or similar declarations within the generated module for examples. + +## 1) Generate an llvm-ir reproducer + +```sh +rustflags="-z autodiff=enable,printmodbefore" cargo +enzyme build --release &> out.ll +``` + +This also captures a few warnings and info messages above and below your module. open out.ll and remove every line above `; moduleid = `. Now look at the end of the file and remove everything that's not part of llvm-ir, i.e. remove errors and warnings. The last line of your llvm-ir should now start with `! = `, i.e. `!40831 = !{i32 0, i32 1037508, i32 1037538, i32 1037559}` or `!43760 = !dilocation(line: 297, column: 5, scope: !43746)`. + +The actual numbers will depend on your code. + +## 2) Check your llvm-ir reproducer + +To confirm that your previous step worked, we will use llvm's `opt` tool. find your path to the opt binary, with a path similar to `/rust/build//build/bin/opt`. also find `llvmenzyme-19.` path, similar to `/rust/build/target-tripple/enzyme/build/enzyme/llvmenzyme-19`. Please keep in mind that llvm frequently updates it's llvm backend, so the version number might be higher (20, 21, ...). Once you have both, run the following command: + +```sh + out.ll -load-pass-plugin=/path/to/llvmenzyme-19.so -passes="enzyme" -s +``` + +If the previous step succeeded, you are going to see the same error that you saw when compiling your rust code with cargo. + +If you fail to get the same error, please open an issue in the rust repository. If you succeed, congrats! the file is still huge, so let's automatically minimize it. + +## 3) Minimize your llvm-ir reproducer + +First find your `llvm-extract` binary, it's in the same folder as your opt binary. then run: + +```sh + -s --func= --recursive --rfunc="enzyme_autodiff*" --rfunc="enzyme_fwddiff*" --rfunc= out.ll -o mwe.ll +``` + +This command creates `mwe.ll`, a minimal working example. + +Please adjust the name passed with the last `--func` flag. You can either apply the `#[no_mangle]` attribute to the function you differentiate, then you can replace it with the rust name. otherwise you will need to look up the mangled function name. To do that, open `out.ll` and search for `__enzyme_fwddiff` or `__enzyme_autodiff`. the first string in that function call is the name of your function. example: + +```llvm-ir +define double @enzyme_opt_helper_0(ptr %0, i64 %1, double %2) { + %4 = call double (...) @__enzyme_fwddiff(ptr @_zn2ad3_f217h3b3b1800bd39fde3e, metadata !"enzyme_const", ptr %0, metadata !"enzyme_const", i64 %1, metadata !"enzyme_dup", double %2, double %2) + ret double %4 +} +``` + +Here, `_zn2ad3_f217h3b3b1800bd39fde3e` is the correct name. make sure to not copy the leading `@`. redo step 2) by running the `opt` command again, but this time passing `mwe.ll` as the input file instead of `out.ll`. Check if this minimized example still reproduces the crash. + +## 4) (Optional) Minimize your llvm-ir reproducer further. + +After the previous step you should have an `mwe.ll` file with ~5k loc. let's try to get it down to 50. find your `llvm-reduce` binary next to `opt` and `llvm-extract`. Copy the first line of your error message, an example could be: + +```sh +opt: /home/manuel/prog/rust/src/llvm-project/llvm/lib/ir/instructions.cpp:686: void llvm::callinst::init(llvm::functiontype*, llvm::value*, llvm::arrayref, llvm::arrayref >, const llvm::twine&): assertion `(args.size() == fty->getnumparams() || (fty->isvararg() && args.size() > fty->getnumparams())) && "calling a function with bad signature!"' failed. +``` + +If you just get a `segfault` there is no sensible error message and not much to do automatically, so continue to 5). +otherwise, create a `script.sh` file containing + +```sh +#!/bin/bash + $1 -load-pass-plugin=/path/to/llvmenzyme-19.so -passes="enzyme" \ + |& grep "/some/path.cpp:686: void llvm::callinst::init" +``` + +Experiment a bit with which error message you pass to grep. it should be long enough to make sure that the error is unique. However, for longer errors including `(` or `)` you will need to escape them correctly which can become annoying. Run + +```sh + --test=script.sh mwe.ll +``` + +If you see `input isn't interesting! verify interesting-ness test`, you got the error message in script.sh wrong, you need to make sure that grep matches your actual error. If all works out, you will see a lot of iterations, ending with a new `reduced.ll` file. Verify with `opt` that you still get the same error. + +### Advanced debugging: manual llvm-ir investigation + +Once you have a minimized reproducer (`mwe.ll` or `reduced.ll`), you can delve deeper: + +- **manual editing:** try manually rewriting the llvm-ir. for certain issues, like those involving indirect calls, you might investigate enzyme-specific intrinsics like `__enzyme_virtualreverse`. Understanding how to use these might require consulting enzyme's documentation or source code. +- **enzyme test cases:** look for relevant test cases within the [enzyme repository](https://github.com/enzymead/enzyme/tree/main/enzyme/test) that might demonstrate the correct usage of features or intrinsics related to your problem. + +## 5) Report your bug. + +Afterwards, you should be able to copy and paste your `mwe.ll` (or `reduced.ll`) example into our [compiler explorer](https://enzyme.mit.edu/explorer/). + +- Select `llvm ir` as language and `opt 20` as compiler. +- Replace the field to the right of your compiler with `-passes="enzyme"`, if it is not already set. +- Hopefully, you will see once again your now familiar error. +- Please use the share button to copy links to them. +- Please create an issue on [https://github.com/enzymead/enzyme/issues](https://github.com/enzymead/enzyme/issues) and share `mwe.ll` and (if you have it) `reduced.ll`, as well as links to the compiler explorer. Please feel free to also add your rust code or a link to it. + +#### Documenting findings + +some enzyme errors, like `"attempting to call an indirect active function whose runtime value is inactive"`, have historically caused confusion. If you investigate such an issue, even if you don't find a complete solution, please consider documenting your findings. If the insights are general to enzyme and not specific to its rust usage, contributing them to the main [enzyme documentation](https://github.com/enzymead/www) is often the best first step. You can also mention your findings in the relevant enzyme github issue or propose updates to these docs if appropriate. This helps prevent others from starting from scratch. + +With a clear reproducer and documentation, hopefully an enzyme developer will be able to fix your bug. Once that happens, the enzyme submodule inside the rust compiler will be updated, which should allow you to differentiate your rust code. Thanks for helping us to improve rust-ad. + +# Minimize rust code + +Beyond having a minimal llvm-ir reproducer, it is also helpful to have a minimal rust reproducer without dependencies. This allows us to add it as a test case to ci once we fix it, which avoids regressions for the future. + +There are a few solutions to help you with minimizing the rust reproducer. This is probably the most simple automated approach: [cargo-minimize](https://github.com/nilstrieb/cargo-minimize). + +Otherwise we have various alternatives, including [`treereduce`](https://github.com/langston-barrett/treereduce), [`halfempty`](https://github.com/googleprojectzero/halfempty), or [`picireny`](https://github.com/renatahodovan/picireny), potentially also [`creduce`](https://github.com/csmith-project/creduce). diff --git a/src/doc/rustc-dev-guide/src/autodiff/flags.md b/src/doc/rustc-dev-guide/src/autodiff/flags.md new file mode 100644 index 000000000000..946ae1d03ae6 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/flags.md @@ -0,0 +1,42 @@ +# Supported `RUSTFLAGS` + +To support you while debugging or profiling, we have added support for an experimental `-Z autodiff` rustc flag (which can be passed to cargo via `RUSTFLAGS`), which allow changing the behaviour of Enzyme, without recompiling rustc. We currently support the following values for `autodiff`. + +### Debug Flags + +```text +PrintTA // Print TypeAnalysis information +PrintAA // Print ActivityAnalysis information +Print // Print differentiated functions while they are being generated and optimized +PrintPerf // Print AD related Performance warnings +PrintModBefore // Print the whole LLVM-IR module directly before running AD +PrintModAfter // Print the whole LLVM-IR module after running AD, before optimizations +PrintModFinal // Print the whole LLVM-IR module after running optimizations and AD +LooseTypes // Risk incorrect derivatives instead of aborting when missing Type Info +``` + +
+`LooseTypes` is often helpful to get rid of Enzyme errors stating `Can not deduce type of ` and to be able to run some code. But please keep in mind that this flag absolutely has the chance to cause incorrect gradients. Even worse, the gradients might be correct for certain input values, but not for others. So please create issues about such bugs and only use this flag temporarily while you wait for your bug to be fixed. +
+ +### Benchmark flags + +For performance experiments and benchmarking we also support + +```text +NoPostopt // We won't optimize the LLVM-IR Module after AD +RuntimeActivity // Enables the runtime activity feature from Enzyme +Inline // Instructs Enzyme to maximize inlining as far as possible, beyond LLVM's default +``` + +You can combine multiple `autodiff` values using a comma as separator: + +```bash +RUSTFLAGS="-Z autodiff=Enable,LooseTypes,PrintPerf" cargo +enzyme build +``` + +Using `-Zautodiff=Enable` will allow using autodiff and update your normal rustc compilation pipeline: + +1. Run your selected compilation pipeline. If you selected a release build, we will disable vectorization and loop unrolling. +2. Differentiate your functions. +3. Run your selected compilation pipeline again on the whole module. This time we do not disable vectorization or loop unrolling. diff --git a/src/doc/rustc-dev-guide/src/autodiff/internals.md b/src/doc/rustc-dev-guide/src/autodiff/internals.md new file mode 100644 index 000000000000..0093ef044c80 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/internals.md @@ -0,0 +1,27 @@ +The `std::autodiff` module in Rust allows differentiable programming: + +```rust +#![feature(autodiff)] +use std::autodiff::autodiff; + +// f(x) = x * x, f'(x) = 2.0 * x +// bar therefore returns (x * x, 2.0 * x) +#[autodiff(bar, Reverse, Active, Active)] +fn foo(x: f32) -> f32 { x * x } + +fn main() { + assert_eq!(bar(3.0, 1.0), (9.0, 6.0)); + assert_eq!(bar(4.0, 1.0), (16.0, 8.0)); +} +``` + +The detailed documentation for the `std::autodiff` module is available at [std::autodiff](https://doc.rust-lang.org/std/autodiff/index.html). + +Differentiable programing is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations. + +[ratel]: https://gitlab.com/micromorph/ratel +[molpipx]: https://arxiv.org/abs/2411.17011v +[waterlily]: https://github.com/WaterLily-jl/WaterLily.jl +[diffsol]: https://github.com/martinjrobins/diffsol +[libigl]: https://github.com/alecjacobson/libigl-enzyme-example?tab=readme-ov-file#run +[catalyst]: https://github.com/PennyLaneAI/catalyst diff --git a/src/doc/rustc-dev-guide/src/autodiff/limitations.md b/src/doc/rustc-dev-guide/src/autodiff/limitations.md new file mode 100644 index 000000000000..90afbd51f3fd --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/limitations.md @@ -0,0 +1,27 @@ +# Current limitations + +## Safety and Soundness + +Enzyme currently assumes that the user passes shadow arguments (`dx`, `dy`, ...) of appropriate size. Under Reverse Mode, we additionally assume that shadow arguments are mutable. In Reverse Mode we adjust the outermost pointer or reference to be mutable. Therefore `&f32` will receive the shadow type `&mut f32`. However, we do not check length for other types than slices (e.g. enums, Vec). We also do not enforce mutability of inner references, but will warn if we recognize them. We do intend to add additional checks over time. + +## ABI adjustments + +In some cases, a function parameter might get lowered in a way that we currently don't handle correctly, leading to a compile time type mismatch in the `rustc_codegen_llvm` backend. Here are some [examples](https://github.com/EnzymeAD/rust/issues/105). + +## Compile Times + +Enzyme will often achieve excellent runtime performance, but might increase your compile time by a large factor. For Rust, we already have made significant improvements and have a list of further improvements planed - please reach out if you have time to help here. + +### Type Analysis + +Most of the times, Type Analysis (TA) is the reason of large (>5x) compile time increases when using Enzyme. This poster explains why we need to run Type Analysis in the bottom left part: [Poster Link](https://c.wsmoses.com/posters/Enzyme-llvmdev.pdf). + +We intend to increase the number of locations where we pass down Type information based on Rust types, which in turn will reduce the number of locations where Enzyme has to run Type Analysis, which will help compile times. + +### Duplicated Optimizations + +The key reason for Enzyme offering often excellent performance is that Enzyme differentiates already optimized LLVM-IR. However, we also (have to) run LLVM's optimization pipeline after differentiating, to make sure that the code which Enzyme generates is optimized properly. As a result you should have excellent runtime performance (please fill an issue if not), but at a compile time cost for running optimizations twice. + +### Fat-LTO + +The usage of `#[autodiff(...)]` currently requires compiling your project with Fat-LTO. We technically only need LTO if the function being differentiated calls functions in other compilation units. Therefore, other solutions are possible, but this is the most simple one to get started. From d14df2652df492fe0f19c5e0ae5041b39b5a4d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 16 Apr 2025 13:24:01 +0200 Subject: [PATCH 040/109] Make `parent` in `download_auto_job_metrics` optional --- src/ci/citool/src/main.rs | 2 +- src/ci/citool/src/metrics.rs | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index a1956da352f5..0fee862f5721 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -180,7 +180,7 @@ fn postprocess_metrics( } fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> { - let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; + let metrics = download_auto_job_metrics(&db, Some(&parent), ¤t)?; println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index a816fb3c4f16..3d8b1ad84cf7 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -46,24 +46,25 @@ pub struct JobMetrics { /// `parent` and `current` should be commit SHAs. pub fn download_auto_job_metrics( job_db: &JobDatabase, - parent: &str, + parent: Option<&str>, current: &str, ) -> anyhow::Result> { let mut jobs = HashMap::default(); for job in &job_db.auto_jobs { eprintln!("Downloading metrics of job {}", job.name); - let metrics_parent = match download_job_metrics(&job.name, parent) { - Ok(metrics) => Some(metrics), - Err(error) => { - eprintln!( - r#"Did not find metrics for job `{}` at `{parent}`: {error:?}. + let metrics_parent = + parent.and_then(|parent| match download_job_metrics(&job.name, parent) { + Ok(metrics) => Some(metrics), + Err(error) => { + eprintln!( + r#"Did not find metrics for job `{}` at `{parent}`: {error:?}. Maybe it was newly added?"#, - job.name - ); - None - } - }; + job.name + ); + None + } + }); let metrics_current = download_job_metrics(&job.name, current)?; jobs.insert( job.name.clone(), From 111c15c48e618b30a0cf11d91b135d87d73053a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 16 Apr 2025 17:20:53 +0200 Subject: [PATCH 041/109] Extract function for normalizing path delimiters to `utils` --- src/ci/citool/src/analysis.rs | 13 ++++++------- src/ci/citool/src/utils.rs | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 9fc7c309bfbd..62974be2dbe8 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -8,9 +8,9 @@ use build_helper::metrics::{ }; use crate::github::JobInfoResolver; -use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; use crate::utils::{output_details, pluralize}; +use crate::{metrics, utils}; /// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations, /// and also a table with summarized information about executed tests. @@ -394,18 +394,17 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { // Poor man's detection of doctests based on the "(line XYZ)" suffix let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) && test.name.contains("(line"); - let test_entry = Test { name: generate_test_name(&test.name), stage, is_doctest }; + let test_entry = Test { + name: utils::normalize_path_delimiters(&test.name).to_string(), + stage, + is_doctest, + }; tests.insert(test_entry, test.outcome.clone()); } } TestSuiteData { tests } } -/// Normalizes Windows-style path delimiters to Unix-style paths. -fn generate_test_name(name: &str) -> String { - name.replace('\\', "/") -} - /// Prints test changes in Markdown format to stdout. fn report_test_diffs( diff: AggregatedTestDiffs, diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index a4c6ff85ef73..0367d349a1ef 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::Path; use anyhow::Context; @@ -28,3 +29,8 @@ where func(); println!("\n"); } + +/// Normalizes Windows-style path delimiters to Unix-style paths. +pub fn normalize_path_delimiters(name: &str) -> Cow { + if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() } +} From c8a882b7b58a7b8f6b276ab64117b55bbe2626e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 09:41:12 +0200 Subject: [PATCH 042/109] Add command to `citool` for generating a test dashboard --- src/ci/citool/Cargo.lock | 67 ++++++ src/ci/citool/Cargo.toml | 1 + src/ci/citool/src/main.rs | 16 +- src/ci/citool/src/test_dashboard/mod.rs | 239 +++++++++++++++++++++ src/ci/citool/templates/layout.askama | 71 ++++++ src/ci/citool/templates/test_group.askama | 22 ++ src/ci/citool/templates/test_suites.askama | 18 ++ 7 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 src/ci/citool/src/test_dashboard/mod.rs create mode 100644 src/ci/citool/templates/layout.askama create mode 100644 src/ci/citool/templates/test_group.askama create mode 100644 src/ci/citool/templates/test_suites.askama diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 2fe219f368b9..43321d12cafc 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -64,12 +64,63 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +[[package]] +name = "askama" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow", +] + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "build_helper" version = "0.1.0" @@ -104,6 +155,7 @@ name = "citool" version = "0.1.0" dependencies = [ "anyhow", + "askama", "build_helper", "clap", "csv", @@ -646,6 +698,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustls" version = "0.23.23" @@ -1026,6 +1084,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index f18436a12635..0e2aba3b9e3f 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] anyhow = "1" +askama = "0.13" clap = { version = "4.5", features = ["derive"] } csv = "1" diff = "0.1" diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 0fee862f5721..a7a289fc3d4b 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -4,6 +4,7 @@ mod datadog; mod github; mod jobs; mod metrics; +mod test_dashboard; mod utils; use std::collections::{BTreeMap, HashMap}; @@ -22,6 +23,7 @@ use crate::datadog::upload_datadog_metric; use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; +use crate::test_dashboard::generate_test_dashboard; use crate::utils::load_env_var; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); @@ -234,6 +236,14 @@ enum Args { /// Current commit that will be compared to `parent`. current: String, }, + /// Generate a directory containing a HTML dashboard of test results from a CI run. + TestDashboard { + /// Commit SHA that was tested on CI to analyze. + current: String, + /// Output path for the HTML directory. + #[clap(long)] + output_dir: PathBuf, + }, } #[derive(clap::ValueEnum, Clone)] @@ -275,7 +285,11 @@ fn main() -> anyhow::Result<()> { postprocess_metrics(metrics_path, parent, job_name)?; } Args::PostMergeReport { current, parent } => { - post_merge_report(load_db(default_jobs_file)?, current, parent)?; + post_merge_report(load_db(&default_jobs_file)?, current, parent)?; + } + Args::TestDashboard { current, output_dir } => { + let db = load_db(&default_jobs_file)?; + generate_test_dashboard(db, ¤t, &output_dir)?; } } diff --git a/src/ci/citool/src/test_dashboard/mod.rs b/src/ci/citool/src/test_dashboard/mod.rs new file mode 100644 index 000000000000..ad9fe029e15d --- /dev/null +++ b/src/ci/citool/src/test_dashboard/mod.rs @@ -0,0 +1,239 @@ +use std::collections::{BTreeMap, HashMap}; +use std::fs::File; +use std::io::BufWriter; +use std::path::{Path, PathBuf}; + +use askama::Template; +use build_helper::metrics::{TestOutcome, TestSuiteMetadata}; + +use crate::jobs::JobDatabase; +use crate::metrics::{JobMetrics, JobName, download_auto_job_metrics, get_test_suites}; +use crate::utils::normalize_path_delimiters; + +pub struct TestInfo { + name: String, + jobs: Vec, +} + +struct JobTestResult { + job_name: String, + outcome: TestOutcome, +} + +#[derive(Default)] +struct TestSuiteInfo { + name: String, + tests: BTreeMap, +} + +/// Generate a set of HTML files into a directory that contain a dashboard of test results. +pub fn generate_test_dashboard( + db: JobDatabase, + current: &str, + output_dir: &Path, +) -> anyhow::Result<()> { + let metrics = download_auto_job_metrics(&db, None, current)?; + + let suites = gather_test_suites(&metrics); + + std::fs::create_dir_all(output_dir)?; + + let test_count = suites.test_count(); + write_page(output_dir, "index.html", &TestSuitesPage { suites, test_count })?; + + Ok(()) +} + +fn write_page(dir: &Path, name: &str, template: &T) -> anyhow::Result<()> { + let mut file = BufWriter::new(File::create(dir.join(name))?); + Template::write_into(template, &mut file)?; + Ok(()) +} + +fn gather_test_suites(job_metrics: &HashMap) -> TestSuites { + struct CoarseTestSuite<'a> { + kind: TestSuiteKind, + tests: BTreeMap>, + } + + let mut suites: HashMap = HashMap::new(); + + // First, gather tests from all jobs, stages and targets, and aggregate them per suite + for (job, metrics) in job_metrics { + let test_suites = get_test_suites(&metrics.current); + for suite in test_suites { + let (suite_name, stage, target, kind) = match &suite.metadata { + TestSuiteMetadata::CargoPackage { crates, stage, target, .. } => { + (crates.join(","), *stage, target, TestSuiteKind::Cargo) + } + TestSuiteMetadata::Compiletest { suite, stage, target, .. } => { + (suite.clone(), *stage, target, TestSuiteKind::Compiletest) + } + }; + let suite_entry = suites + .entry(suite_name.clone()) + .or_insert_with(|| CoarseTestSuite { kind, tests: Default::default() }); + let test_metadata = TestMetadata { job, stage, target }; + + for test in &suite.tests { + let test_name = normalize_test_name(&test.name, &suite_name); + let test_entry = suite_entry + .tests + .entry(test_name.clone()) + .or_insert_with(|| Test { name: test_name, passed: vec![], ignored: vec![] }); + match test.outcome { + TestOutcome::Passed => { + test_entry.passed.push(test_metadata); + } + TestOutcome::Ignored { ignore_reason: _ } => { + test_entry.ignored.push(test_metadata); + } + TestOutcome::Failed => { + eprintln!("Warning: failed test"); + } + } + } + } + } + + // Then, split the suites per directory + let mut suites = suites.into_iter().collect::>(); + suites.sort_by(|a, b| a.1.kind.cmp(&b.1.kind).then_with(|| a.0.cmp(&b.0))); + + let mut target_suites = vec![]; + for (suite_name, suite) in suites { + let suite = match suite.kind { + TestSuiteKind::Compiletest => TestSuite { + name: suite_name.clone(), + kind: TestSuiteKind::Compiletest, + group: build_test_group(&suite_name, suite.tests), + }, + TestSuiteKind::Cargo => { + let mut tests: Vec<_> = suite.tests.into_iter().collect(); + tests.sort_by(|a, b| a.0.cmp(&b.0)); + TestSuite { + name: format!("[cargo] {}", suite_name.clone()), + kind: TestSuiteKind::Cargo, + group: TestGroup { + name: suite_name, + root_tests: tests.into_iter().map(|t| t.1).collect(), + groups: vec![], + }, + } + } + }; + target_suites.push(suite); + } + + TestSuites { suites: target_suites } +} + +/// Recursively expand a test group based on filesystem hierarchy. +fn build_test_group<'a>(name: &str, tests: BTreeMap>) -> TestGroup<'a> { + let mut root_tests = vec![]; + let mut subdirs: BTreeMap>> = Default::default(); + + // Split tests into root tests and tests located in subdirectories + for (name, test) in tests { + let mut components = Path::new(&name).components().peekable(); + let subdir = components.next().unwrap(); + + if components.peek().is_none() { + // This is a root test + root_tests.push(test); + } else { + // This is a test in a nested directory + let subdir_tests = + subdirs.entry(subdir.as_os_str().to_str().unwrap().to_string()).or_default(); + let test_name = + components.into_iter().collect::().to_str().unwrap().to_string(); + subdir_tests.insert(test_name, test); + } + } + let dirs = subdirs + .into_iter() + .map(|(name, tests)| { + let group = build_test_group(&name, tests); + (name, group) + }) + .collect(); + + TestGroup { name: name.to_string(), root_tests, groups: dirs } +} + +/// Compiletest tests start with `[suite] tests/[suite]/a/b/c...`. +/// Remove the `[suite] tests/[suite]/` prefix so that we can find the filesystem path. +/// Also normalizes path delimiters. +fn normalize_test_name(name: &str, suite_name: &str) -> String { + let name = normalize_path_delimiters(name); + let name = name.as_ref(); + let name = name.strip_prefix(&format!("[{suite_name}]")).unwrap_or(name).trim(); + let name = name.strip_prefix("tests/").unwrap_or(name); + let name = name.strip_prefix(suite_name).unwrap_or(name); + name.trim_start_matches("/").to_string() +} + +#[derive(serde::Serialize)] +struct TestSuites<'a> { + suites: Vec>, +} + +impl<'a> TestSuites<'a> { + fn test_count(&self) -> u64 { + self.suites.iter().map(|suite| suite.group.test_count()).sum::() + } +} + +#[derive(serde::Serialize)] +struct TestSuite<'a> { + name: String, + kind: TestSuiteKind, + group: TestGroup<'a>, +} + +#[derive(Debug, serde::Serialize)] +struct Test<'a> { + name: String, + passed: Vec>, + ignored: Vec>, +} + +#[derive(Clone, Copy, Debug, serde::Serialize)] +struct TestMetadata<'a> { + job: &'a str, + stage: u32, + target: &'a str, +} + +// We have to use a template for the TestGroup instead of a macro, because +// macros cannot be recursive in askama at the moment. +#[derive(Template, serde::Serialize)] +#[template(path = "test_group.askama")] +/// Represents a group of tests +struct TestGroup<'a> { + name: String, + /// Tests located directly in this directory + root_tests: Vec>, + /// Nested directories with additional tests + groups: Vec<(String, TestGroup<'a>)>, +} + +impl<'a> TestGroup<'a> { + fn test_count(&self) -> u64 { + let root = self.root_tests.len() as u64; + self.groups.iter().map(|(_, group)| group.test_count()).sum::() + root + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, serde::Serialize)] +enum TestSuiteKind { + Compiletest, + Cargo, +} + +#[derive(Template)] +#[template(path = "test_suites.askama")] +struct TestSuitesPage<'a> { + suites: TestSuites<'a>, + test_count: u64, +} diff --git a/src/ci/citool/templates/layout.askama b/src/ci/citool/templates/layout.askama new file mode 100644 index 000000000000..2e830aaa9f58 --- /dev/null +++ b/src/ci/citool/templates/layout.askama @@ -0,0 +1,71 @@ + + + + Rust CI Test Dashboard + + + + +{% block content %}{% endblock %} + + diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama new file mode 100644 index 000000000000..a0b7fa863e57 --- /dev/null +++ b/src/ci/citool/templates/test_group.askama @@ -0,0 +1,22 @@ +
  • +
    +{{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}) + +{% if !groups.is_empty() %} +
      + {% for (dir_name, subgroup) in groups %} + {{ subgroup|safe }} + {% endfor %} +
    +{% endif %} + +{% if !root_tests.is_empty() %} +
      + {% for test in root_tests %} +
    • {{ test.name }} ({{ test.passed.len() }} passed, {{ test.ignored.len() }} ignored)
    • + {% endfor %} +
    +{% endif %} + +
    +
  • diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama new file mode 100644 index 000000000000..a6f8d0e1abe0 --- /dev/null +++ b/src/ci/citool/templates/test_suites.askama @@ -0,0 +1,18 @@ +{% extends "layout.askama" %} + +{% block content %} +

    Rust CI Test Dashboard

    +
    +
    + Total tests: {{ test_count }} +
    + +
      + {% for suite in suites.suites %} + {% if suite.kind == TestSuiteKind::Compiletest %} + {{ suite.group|safe }} + {% endif %} + {% endfor %} +
    +
    +{% endblock %} From a326afd5dd810427c72ed81e705c0d903e74edcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 16:30:23 +0200 Subject: [PATCH 043/109] Add buttons for expanding and collapsing all test suites --- src/ci/citool/templates/layout.askama | 57 ++------------- src/ci/citool/templates/test_suites.askama | 81 +++++++++++++++++++++- 2 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/ci/citool/templates/layout.askama b/src/ci/citool/templates/layout.askama index 2e830aaa9f58..3b3b6f23741d 100644 --- a/src/ci/citool/templates/layout.askama +++ b/src/ci/citool/templates/layout.askama @@ -3,69 +3,20 @@ Rust CI Test Dashboard {% block content %}{% endblock %} +{% block scripts %}{% endblock %} diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama index a6f8d0e1abe0..a8cedc65f243 100644 --- a/src/ci/citool/templates/test_suites.askama +++ b/src/ci/citool/templates/test_suites.askama @@ -4,7 +4,11 @@

    Rust CI Test Dashboard

    - Total tests: {{ test_count }} + Total tests: {{ test_count }} +
    + + +
      @@ -16,3 +20,78 @@
    {% endblock %} + +{% block styles %} +h1 { + text-align: center; + color: #333333; + margin-bottom: 30px; +} + +.summary { + display: flex; + justify-content: space-between; +} + +.test-suites { + background: white; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 20px; +} + +ul { + padding-left: 0; +} + +li { + list-style: none; + padding-left: 20px; +} +summary { + margin-bottom: 5px; + padding: 6px; + background-color: #F4F4F4; + border: 1px solid #ddd; + border-radius: 4px; + cursor: pointer; +} +summary:hover { + background-color: #CFCFCF; +} + +/* Style the disclosure triangles */ +details > summary { + list-style: none; + position: relative; +} + +details > summary::before { + content: "▶"; + position: absolute; + left: -15px; + transform: rotate(0); + transition: transform 0.2s; +} + +details[open] > summary::before { + transform: rotate(90deg); +} +{% endblock %} + +{% block scripts %} + +{% endblock %} From 4b310338f8d2a67cbc863ee799206709e95da6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 16:35:34 +0200 Subject: [PATCH 044/109] Add a note about how to find tests that haven't been executed anywhere. --- src/ci/citool/src/test_dashboard/mod.rs | 60 ++++------------------ src/ci/citool/templates/test_suites.askama | 17 ++++-- 2 files changed, 22 insertions(+), 55 deletions(-) diff --git a/src/ci/citool/src/test_dashboard/mod.rs b/src/ci/citool/src/test_dashboard/mod.rs index ad9fe029e15d..163e9c1acea0 100644 --- a/src/ci/citool/src/test_dashboard/mod.rs +++ b/src/ci/citool/src/test_dashboard/mod.rs @@ -10,22 +10,6 @@ use crate::jobs::JobDatabase; use crate::metrics::{JobMetrics, JobName, download_auto_job_metrics, get_test_suites}; use crate::utils::normalize_path_delimiters; -pub struct TestInfo { - name: String, - jobs: Vec, -} - -struct JobTestResult { - job_name: String, - outcome: TestOutcome, -} - -#[derive(Default)] -struct TestSuiteInfo { - name: String, - tests: BTreeMap, -} - /// Generate a set of HTML files into a directory that contain a dashboard of test results. pub fn generate_test_dashboard( db: JobDatabase, @@ -33,7 +17,6 @@ pub fn generate_test_dashboard( output_dir: &Path, ) -> anyhow::Result<()> { let metrics = download_auto_job_metrics(&db, None, current)?; - let suites = gather_test_suites(&metrics); std::fs::create_dir_all(output_dir)?; @@ -52,27 +35,27 @@ fn write_page(dir: &Path, name: &str, template: &T) -> anyhow::Resu fn gather_test_suites(job_metrics: &HashMap) -> TestSuites { struct CoarseTestSuite<'a> { - kind: TestSuiteKind, tests: BTreeMap>, } let mut suites: HashMap = HashMap::new(); // First, gather tests from all jobs, stages and targets, and aggregate them per suite + // Only work with compiletest suites. for (job, metrics) in job_metrics { let test_suites = get_test_suites(&metrics.current); for suite in test_suites { - let (suite_name, stage, target, kind) = match &suite.metadata { - TestSuiteMetadata::CargoPackage { crates, stage, target, .. } => { - (crates.join(","), *stage, target, TestSuiteKind::Cargo) + let (suite_name, stage, target) = match &suite.metadata { + TestSuiteMetadata::CargoPackage { .. } => { + continue; } TestSuiteMetadata::Compiletest { suite, stage, target, .. } => { - (suite.clone(), *stage, target, TestSuiteKind::Compiletest) + (suite.clone(), *stage, target) } }; let suite_entry = suites .entry(suite_name.clone()) - .or_insert_with(|| CoarseTestSuite { kind, tests: Default::default() }); + .or_insert_with(|| CoarseTestSuite { tests: Default::default() }); let test_metadata = TestMetadata { job, stage, target }; for test in &suite.tests { @@ -98,29 +81,13 @@ fn gather_test_suites(job_metrics: &HashMap) -> TestSuites // Then, split the suites per directory let mut suites = suites.into_iter().collect::>(); - suites.sort_by(|a, b| a.1.kind.cmp(&b.1.kind).then_with(|| a.0.cmp(&b.0))); + suites.sort_by(|a, b| a.0.cmp(&b.0)); let mut target_suites = vec![]; for (suite_name, suite) in suites { - let suite = match suite.kind { - TestSuiteKind::Compiletest => TestSuite { - name: suite_name.clone(), - kind: TestSuiteKind::Compiletest, - group: build_test_group(&suite_name, suite.tests), - }, - TestSuiteKind::Cargo => { - let mut tests: Vec<_> = suite.tests.into_iter().collect(); - tests.sort_by(|a, b| a.0.cmp(&b.0)); - TestSuite { - name: format!("[cargo] {}", suite_name.clone()), - kind: TestSuiteKind::Cargo, - group: TestGroup { - name: suite_name, - root_tests: tests.into_iter().map(|t| t.1).collect(), - groups: vec![], - }, - } - } + let suite = TestSuite { + name: suite_name.clone(), + group: build_test_group(&suite_name, suite.tests), }; target_suites.push(suite); } @@ -187,7 +154,6 @@ impl<'a> TestSuites<'a> { #[derive(serde::Serialize)] struct TestSuite<'a> { name: String, - kind: TestSuiteKind, group: TestGroup<'a>, } @@ -225,12 +191,6 @@ impl<'a> TestGroup<'a> { } } -#[derive(PartialEq, Eq, PartialOrd, Ord, serde::Serialize)] -enum TestSuiteKind { - Compiletest, - Cargo, -} - #[derive(Template)] #[template(path = "test_suites.askama")] struct TestSuitesPage<'a> { diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama index a8cedc65f243..bb3d9e363911 100644 --- a/src/ci/citool/templates/test_suites.askama +++ b/src/ci/citool/templates/test_suites.askama @@ -1,10 +1,15 @@ {% extends "layout.askama" %} {% block content %} -

    Rust CI Test Dashboard

    +

    Rust CI test dashboard

    - Total tests: {{ test_count }} +
    +
    Total tests: {{ test_count }}
    +
    + To find tests that haven't been executed anywhere, click on "Open all" and search for "(0 passed". +
    +
    @@ -13,9 +18,7 @@
      {% for suite in suites.suites %} - {% if suite.kind == TestSuiteKind::Compiletest %} - {{ suite.group|safe }} - {% endif %} + {{ suite.group|safe }} {% endfor %}
    @@ -33,6 +36,10 @@ h1 { justify-content: space-between; } +.test-count { + font-size: 1.2em; +} + .test-suites { background: white; border-radius: 8px; From 1a6e0d52e5b008cfd48f78285bb3655ecfd5d73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 17:14:26 +0200 Subject: [PATCH 045/109] Render test revisions separately --- src/ci/citool/src/test_dashboard/mod.rs | 43 ++++++++++++++++++----- src/ci/citool/templates/test_group.askama | 13 ++++++- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/ci/citool/src/test_dashboard/mod.rs b/src/ci/citool/src/test_dashboard/mod.rs index 163e9c1acea0..c16385baa3ba 100644 --- a/src/ci/citool/src/test_dashboard/mod.rs +++ b/src/ci/citool/src/test_dashboard/mod.rs @@ -60,19 +60,27 @@ fn gather_test_suites(job_metrics: &HashMap) -> TestSuites for test in &suite.tests { let test_name = normalize_test_name(&test.name, &suite_name); - let test_entry = suite_entry - .tests - .entry(test_name.clone()) - .or_insert_with(|| Test { name: test_name, passed: vec![], ignored: vec![] }); + let (test_name, variant_name) = match test_name.rsplit_once('#') { + Some((name, variant)) => (name.to_string(), variant.to_string()), + None => (test_name, "".to_string()), + }; + let test_entry = suite_entry.tests.entry(test_name.clone()).or_insert_with(|| { + Test { name: test_name.clone(), revisions: Default::default() } + }); + let variant_entry = test_entry + .revisions + .entry(variant_name) + .or_insert_with(|| TestResults { passed: vec![], ignored: vec![] }); + match test.outcome { TestOutcome::Passed => { - test_entry.passed.push(test_metadata); + variant_entry.passed.push(test_metadata); } TestOutcome::Ignored { ignore_reason: _ } => { - test_entry.ignored.push(test_metadata); + variant_entry.ignored.push(test_metadata); } TestOutcome::Failed => { - eprintln!("Warning: failed test"); + eprintln!("Warning: failed test {test_name}"); } } } @@ -158,12 +166,29 @@ struct TestSuite<'a> { } #[derive(Debug, serde::Serialize)] -struct Test<'a> { - name: String, +struct TestResults<'a> { passed: Vec>, ignored: Vec>, } +#[derive(Debug, serde::Serialize)] +struct Test<'a> { + name: String, + revisions: BTreeMap>, +} + +impl<'a> Test<'a> { + /// If this is a test without revisions, it will have a single entry in `revisions` with + /// an empty string as the revision name. + fn single_test(&self) -> Option<&TestResults<'a>> { + if self.revisions.len() == 1 { + self.revisions.iter().next().take_if(|e| e.0.is_empty()).map(|e| e.1) + } else { + None + } + } +} + #[derive(Clone, Copy, Debug, serde::Serialize)] struct TestMetadata<'a> { job: &'a str, diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama index a0b7fa863e57..535d98e0c247 100644 --- a/src/ci/citool/templates/test_group.askama +++ b/src/ci/citool/templates/test_group.askama @@ -13,7 +13,18 @@ {% if !root_tests.is_empty() %}
      {% for test in root_tests %} -
    • {{ test.name }} ({{ test.passed.len() }} passed, {{ test.ignored.len() }} ignored)
    • +
    • + {% if let Some(result) = test.single_test() %} + {{ test.name }} ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored) + {% else %} + {{ test.name }} ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }}) +
        + {% for (revision, result) in test.revisions %} +
      • #{{ revision }} ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored)
      • + {% endfor %} +
      + {% endif %} +
    • {% endfor %}
    {% endif %} From d2c1763336080030a235dae56f6096e9deb2ec9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 17:18:38 +0200 Subject: [PATCH 046/109] Create a macro for rendering test results --- src/ci/citool/templates/test_group.askama | 8 ++++++-- src/ci/citool/templates/test_suites.askama | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama index 535d98e0c247..ba19d9258d8a 100644 --- a/src/ci/citool/templates/test_group.askama +++ b/src/ci/citool/templates/test_group.askama @@ -1,3 +1,7 @@ +{% macro test_result(r) -%} +passed: {{ r.passed.len() }}, ignored: {{ r.ignored.len() }} +{%- endmacro %} +
  • {{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}) @@ -15,12 +19,12 @@ {% for test in root_tests %}
  • {% if let Some(result) = test.single_test() %} - {{ test.name }} ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored) + {{ test.name }} ({% call test_result(result) %}) {% else %} {{ test.name }} ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }})
      {% for (revision, result) in test.revisions %} -
    • #{{ revision }} ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored)
    • +
    • #{{ revision }} ({% call test_result(result) %})
    • {% endfor %}
    {% endif %} diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama index bb3d9e363911..d36e85228e2b 100644 --- a/src/ci/citool/templates/test_suites.askama +++ b/src/ci/citool/templates/test_suites.askama @@ -7,7 +7,7 @@
    Total tests: {{ test_count }}
    - To find tests that haven't been executed anywhere, click on "Open all" and search for "(0 passed". + To find tests that haven't been executed anywhere, click on "Open all" and search for "passed: 0".
    From aa9cb70190bb38e466983abf0c53c6f26afab4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 17:25:12 +0200 Subject: [PATCH 047/109] Print number of root tests and subdirectories --- src/ci/citool/templates/test_group.askama | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama index ba19d9258d8a..bdf32d00f4a1 100644 --- a/src/ci/citool/templates/test_group.askama +++ b/src/ci/citool/templates/test_group.askama @@ -4,7 +4,12 @@ passed: {{ r.passed.len() }}, ignored: {{ r.ignored.len() }}
  • -{{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}) +{{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}{% if !root_tests.is_empty() && root_tests.len() as u64 != test_count() -%} + , {{ root_tests.len() }} root test{{ root_tests.len() | pluralize }} +{%- endif %}{% if !groups.is_empty() -%} + , {{ groups.len() }} subdir{{ groups.len() | pluralize }} +{%- endif %}) + {% if !groups.is_empty() %}
      From 08cb187d263ec91e8e6d35b4b235eee4ecad3357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 17:26:40 +0200 Subject: [PATCH 048/109] Turn `test_dashboard` into a file --- src/ci/citool/src/{test_dashboard/mod.rs => test_dashboard.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ci/citool/src/{test_dashboard/mod.rs => test_dashboard.rs} (100%) diff --git a/src/ci/citool/src/test_dashboard/mod.rs b/src/ci/citool/src/test_dashboard.rs similarity index 100% rename from src/ci/citool/src/test_dashboard/mod.rs rename to src/ci/citool/src/test_dashboard.rs From cecf16785f193c247c47e42524322aeccc96c8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 17 Apr 2025 17:38:15 +0200 Subject: [PATCH 049/109] Add a note about the test dashboard to the post-merge report --- src/ci/citool/src/main.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index a7a289fc3d4b..f4e671b609fa 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -24,7 +24,7 @@ use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::test_dashboard::generate_test_dashboard; -use crate::utils::load_env_var; +use crate::utils::{load_env_var, output_details}; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); @@ -188,6 +188,20 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow let mut job_info_resolver = JobInfoResolver::new(); output_test_diffs(&metrics, &mut job_info_resolver); + + output_details("Test dashboard", || { + println!( + r#"\nRun + +```bash +cargo run --manifest-path src/ci/citool/Cargo.toml -- \ + test-dashboard {current} --output-dir test-dashboard +``` +And then open `test-dashboard/index.html` in your browser to see an overview of all executed tests. +"# + ); + }); + output_largest_duration_changes(&metrics, &mut job_info_resolver); Ok(()) From 88bd1913f2804c9204b72f60b61aad4449d832c3 Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 17 Apr 2025 11:37:54 -0500 Subject: [PATCH 050/109] Point UNIX_EPOCH to associated constant in SystemTime docs --- library/std/src/time.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 5ab71413586d..6e28596e79b1 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -245,6 +245,7 @@ pub struct Instant(time::Instant); /// > structure cannot represent the new point in time. /// /// [`add`]: SystemTime::add +/// [`UNIX_EPOCH`]: SystemTime::UNIX_EPOCH #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[stable(feature = "time2", since = "1.8.0")] pub struct SystemTime(time::SystemTime); From 34573d683f604ce4d1ab9a845c5a8be4a587a91d Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 17 Apr 2025 11:42:53 -0500 Subject: [PATCH 051/109] Be more specific about the error in the SystemTime example --- library/std/src/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 6e28596e79b1..03af35e809c9 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -205,8 +205,8 @@ pub struct Instant(time::Instant); /// println!("{}", elapsed.as_secs()); /// } /// Err(e) => { -/// // an error occurred! -/// println!("Error: {e:?}"); +/// // the system clock went backwards! +/// println!("Great Scott! {e:?}"); /// } /// } /// } From 834dbf565ce1b29c05faa3b1a4894121c9a9a843 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Thu, 17 Apr 2025 20:52:07 -0400 Subject: [PATCH 052/109] upstream autodiff build instructions --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + .../src/autodiff/installation.md | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/autodiff/installation.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 6526e2f0e655..90fcde072805 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -100,6 +100,7 @@ - [Search](./rustdoc-internals/search.md) - [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md) - [Autodiff internals](./autodiff/internals.md) + - [Installation](./autodiff/installation.md) - [How to debug](./autodiff/debugging.md) - [Autodiff flags](./autodiff/flags.md) - [Current limitations](./autodiff/limitations.md) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md new file mode 100644 index 000000000000..dbea9dbe1445 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -0,0 +1,86 @@ +# Installation + +In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target. + +## Build instructions + +First you need to clone and configure the Rust repository: +```bash +git clone --depth=1 git@github.com:rust-lang/rust.git +cd rust +./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs +``` + +Afterwards you can build rustc using: +```bash +./x.py build --stage 1 library +``` + +Afterwards rustc toolchain link will allow you to use it through cargo: +``` +rustup toolchain link enzyme build/host/stage1 +rustup toolchain install nightly # enables -Z unstable-options +``` + +You can then run our test cases: + +```bash +./x.py test --stage 1 library tests/ui/autodiff +./x.py test --stage 1 library tests/codegen/autodiff +./x.py test --stage 1 library tests/pretty/autodiff* +``` + +Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml +and use `RUSTFLAGS="-Zautodiff=Enable" cargo +enzyme` instead of `cargo` or `cargo +nightly`. + +## Compiler Explorer and dist builds + +Our compiler explorer instance can be updated to a newer rustc in a similar way. First, prepare a docker instance. +```bash +docker run -it ubuntu:22.04 +export CC=clang CXX=clang++ +apt update +apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmake clang build-essential +``` +Then build rustc in a slightly altered way: +```bash +git clone --depth=1 https://github.com/EnzymeAD/rust.git +cd rust +./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs +./x dist +``` +We then copy the tarball to our host. The dockerid is the newest entry under `docker ps -a`. +```bash +docker cp :/rust/build/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz rust-nightly-x86_64-unknown-linux-gnu.tar.gz +``` +Afterwards we can create a new (pre-release) tag on the EnzymeAD/rust repository and make a PR against the EnzymeAD/enzyme-explorer repository to update the tag. +Remember to ping `tgymnich` on the PR to run his update script. + + +## Build instruction for Enzyme itself + +Following the Rust build instruction above will build LLVMEnzyme, LLDEnzyme, and ClangEnzyme along with the Rust compiler. +We recommend that approach, if you just want to use any of them and have no experience with cmake. +However, if you prefer to just build Enzyme without Rust, then these instructions might help. + +```bash +git clone --depth=1 git@github.com:llvm/llvm-project.git +cd llvm-project +mkdir build +cd build +cmake -G Ninja ../llvm -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_ENABLE_RUNTIMES="openmp" -DLLVM_ENABLE_PLUGINS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=. +ninja +ninja install +``` +This gives you a working LLVM build, now we can continue with building Enzyme. +Leave the `llvm-project` folder, and execute the following commands: +```bash +git clone git@github.com:EnzymeAD/Enzyme.git +cd Enzyme/enzyme +mkdir build +cd build +cmake .. -G Ninja -DLLVM_DIR=/llvm-project/build/lib/cmake/llvm/ -DLLVM_EXTERNAL_LIT=/llvm-project/llvm/utils/lit/lit.py -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=YES -DBUILD_SHARED_LIBS=ON +ninja +``` +This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/Enzyme.so`. (Endings might differ based on your OS). + From e882ff4e7ebc4653cdc69e57bc656fe558a4af88 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 17 Apr 2025 19:06:46 +0000 Subject: [PATCH 053/109] Don't assemble non-env/bound candidates if projection is rigid --- .../src/solve/assembly/mod.rs | 87 ++++++++++++------- .../src/solve/effect_goals.rs | 3 +- .../src/solve/normalizes_to/mod.rs | 3 +- .../src/solve/trait_goals.rs | 4 +- tests/ui/impl-unused-tps.stderr | 34 ++++---- .../next-solver/rpitit-cycle-due-to-rigid.rs | 32 +++++++ 6 files changed, 107 insertions(+), 56 deletions(-) create mode 100644 tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 83b2465d05aa..ecb57cc0ad71 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -288,6 +288,21 @@ where ) -> Vec>; } +/// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit +/// candidate assembly to param-env and alias-bound candidates. +/// +/// On top of being a micro-optimization, as it avoids doing unnecessary work when +/// a param-env trait bound candidate shadows impls for normalization, this is also +/// required to prevent query cycles due to RPITIT inference. See the issue at: +/// . +pub(super) enum AssembleCandidatesFrom { + All, + /// Only assemble candidates from the environment and alias bounds, ignoring + /// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound` + /// candidates to be assembled. + EnvAndBounds, +} + impl EvalCtxt<'_, D> where D: SolverDelegate, @@ -296,6 +311,7 @@ where pub(super) fn assemble_and_evaluate_candidates>( &mut self, goal: Goal, + assemble_from: AssembleCandidatesFrom, ) -> Vec> { let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) @@ -322,16 +338,18 @@ where } } - self.assemble_impl_candidates(goal, &mut candidates); - - self.assemble_builtin_impl_candidates(goal, &mut candidates); - self.assemble_alias_bound_candidates(goal, &mut candidates); - - self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_param_env_candidates(goal, &mut candidates); + match assemble_from { + AssembleCandidatesFrom::All => { + self.assemble_impl_candidates(goal, &mut candidates); + self.assemble_builtin_impl_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + } + AssembleCandidatesFrom::EnvAndBounds => {} + } + candidates } @@ -754,6 +772,9 @@ where }) } + /// Assemble and merge candidates for goals which are related to an underlying trait + /// goal. Right now, this is normalizes-to and host effect goals. + /// /// We sadly can't simply take all possible candidates for normalization goals /// and check whether they result in the same constraints. We want to make sure /// that trying to normalize an alias doesn't result in constraints which aren't @@ -782,47 +803,44 @@ where /// /// See trait-system-refactor-initiative#124 for more details. #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)] - pub(super) fn merge_candidates( + pub(super) fn assemble_and_merge_candidates>( &mut self, proven_via: Option, - candidates: Vec>, + goal: Goal, inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> QueryResult { let Some(proven_via) = proven_via else { // We don't care about overflow. If proving the trait goal overflowed, then // it's enough to report an overflow error for that, we don't also have to // overflow during normalization. - return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity)); + // + // We use `forced_ambiguity` here over `make_ambiguous_response_no_constraints` + // because the former will also record a built-in candidate in the inspector. + return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result); }; match proven_via { TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => { - let mut considered_candidates = Vec::new(); - considered_candidates.extend( - candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result), - ); - // Even when a trait bound has been proven using a where-bound, we // still need to consider alias-bounds for normalization, see - // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. - // + // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. + let candidates_from_env_and_bounds: Vec<_> = self + .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); + // We still need to prefer where-bounds over alias-bounds however. - // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs. - // - // FIXME(const_trait_impl): should this behavior also be used by - // constness checking. Doing so is *at least theoretically* breaking, - // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 - if considered_candidates.is_empty() { - considered_candidates.extend( - candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::AliasBound)) - .map(|c| c.result), - ); - } + // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. + let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds + .iter() + .any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + { + candidates_from_env_and_bounds + .into_iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect() + } else { + candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect() + }; // If the trait goal has been proven by using the environment, we want to treat // aliases as rigid if there are no applicable projection bounds in the environment. @@ -839,6 +857,9 @@ where } } TraitGoalProvenVia::Misc => { + let candidates = + self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); + // Prefer "orphaned" param-env normalization predicates, which are used // (for example, and ideally only) when proving item bounds for an impl. let candidates_from_env: Vec<_> = candidates diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0b61c368d8e8..7752a705cd14 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -399,12 +399,11 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let candidates = self.assemble_and_evaluate_candidates(goal); let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { let trait_goal: Goal> = goal.with(ecx.cx(), goal.predicate.trait_ref); ecx.compute_trait_goal(trait_goal) })?; - self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution)) + self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution)) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index fdeb276a58e6..9466901683e2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -32,14 +32,13 @@ where let cx = self.cx(); match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { - let candidates = self.assemble_and_evaluate_candidates(goal); let trait_ref = goal.predicate.alias.trait_ref(cx); let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { let trait_goal: Goal> = goal.with(cx, trait_ref); ecx.compute_trait_goal(trait_goal) })?; - self.merge_candidates(proven_via, candidates, |ecx| { + self.assemble_and_merge_candidates(proven_via, goal, |ecx| { ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| { this.structurally_instantiate_normalizes_to_term( goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 409af8568d7a..7bd1300f34ed 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -13,7 +13,7 @@ use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; -use crate::solve::assembly::{self, Candidate}; +use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, @@ -1365,7 +1365,7 @@ where &mut self, goal: Goal>, ) -> Result<(CanonicalResponse, Option), NoSolution> { - let candidates = self.assemble_and_evaluate_candidates(goal); + let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); self.merge_trait_candidates(goal, candidates) } } diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr index 09c3fce641cf..eff5ffff9b6a 100644 --- a/tests/ui/impl-unused-tps.stderr +++ b/tests/ui/impl-unused-tps.stderr @@ -7,23 +7,6 @@ LL | impl Foo for [isize; 0] { LL | impl Foo for U { | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` -error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:32:9 - | -LL | impl Bar for T { - | ^ unconstrained type parameter - -error[E0119]: conflicting implementations of trait `Bar` - --> $DIR/impl-unused-tps.rs:40:1 - | -LL | impl Bar for T { - | -------------------- first implementation here -... -LL | / impl Bar for T -LL | | where -LL | | T: Bar, - | |____________________^ conflicting implementation - error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]` --> $DIR/impl-unused-tps.rs:49:1 | @@ -52,6 +35,12 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self LL | impl Foo for [isize; 1] { | ^ unconstrained type parameter +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/impl-unused-tps.rs:32:9 + | +LL | impl Bar for T { + | ^ unconstrained type parameter + error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/impl-unused-tps.rs:40:9 | @@ -70,6 +59,17 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self LL | impl Foo for T | ^ unconstrained type parameter +error[E0119]: conflicting implementations of trait `Bar` + --> $DIR/impl-unused-tps.rs:40:1 + | +LL | impl Bar for T { + | -------------------- first implementation here +... +LL | / impl Bar for T +LL | | where +LL | | T: Bar, + | |____________________^ conflicting implementation + error: aborting due to 9 previous errors Some errors have detailed explanations: E0119, E0207. diff --git a/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs b/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs new file mode 100644 index 000000000000..ec3d710ef371 --- /dev/null +++ b/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass +//@ edition: 2024 + +// Ensure we don't end up in a query cycle due to trying to assemble an impl candidate +// for an RPITIT normalizes-to goal, even though that impl candidate would *necessarily* +// be made rigid by a where clause. This query cycle is thus avoidable by not assembling +// that impl candidate which we *know* we are going to throw away anyways. + +use std::future::Future; + +pub trait ReactiveFunction: Send { + type Output; + + fn invoke(self) -> Self::Output; +} + +trait AttributeValue { + fn resolve(self) -> impl Future + Send; +} + +impl AttributeValue for F +where + F: ReactiveFunction, + V: AttributeValue, +{ + async fn resolve(self) { + self.invoke().resolve().await + } +} + +fn main() {} From 65ce38a4c96da2f950fb6b181b2b83b0320d103d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 18 Apr 2025 12:32:19 +0200 Subject: [PATCH 054/109] Add a note that explains the counts --- src/ci/citool/templates/test_suites.askama | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama index d36e85228e2b..4997f6a3f1c9 100644 --- a/src/ci/citool/templates/test_suites.askama +++ b/src/ci/citool/templates/test_suites.askama @@ -2,6 +2,10 @@ {% block content %}

      Rust CI test dashboard

      +
      +Here's how to interpret the "passed" and "ignored" counts: +the count includes all combinations of "stage" x "target" x "CI job where the test was executed or ignored". +
      From b18e37305304780530224736ad55145063c7e8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 18 Apr 2025 12:44:39 +0200 Subject: [PATCH 055/109] Reduce duplicated test prefixes in nested subdirectories `assembly/asm` contained a test named `asm/aarch64-el2vmsa.rs`, while it should have been only `arch64-el2vmsa.rs`. --- src/ci/citool/src/test_dashboard.rs | 36 +++++++++-------------- src/ci/citool/templates/test_group.askama | 6 ++-- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/ci/citool/src/test_dashboard.rs b/src/ci/citool/src/test_dashboard.rs index c16385baa3ba..8fbd0d3f200d 100644 --- a/src/ci/citool/src/test_dashboard.rs +++ b/src/ci/citool/src/test_dashboard.rs @@ -64,9 +64,10 @@ fn gather_test_suites(job_metrics: &HashMap) -> TestSuites Some((name, variant)) => (name.to_string(), variant.to_string()), None => (test_name, "".to_string()), }; - let test_entry = suite_entry.tests.entry(test_name.clone()).or_insert_with(|| { - Test { name: test_name.clone(), revisions: Default::default() } - }); + let test_entry = suite_entry + .tests + .entry(test_name.clone()) + .or_insert_with(|| Test { revisions: Default::default() }); let variant_entry = test_entry .revisions .entry(variant_name) @@ -91,16 +92,12 @@ fn gather_test_suites(job_metrics: &HashMap) -> TestSuites let mut suites = suites.into_iter().collect::>(); suites.sort_by(|a, b| a.0.cmp(&b.0)); - let mut target_suites = vec![]; - for (suite_name, suite) in suites { - let suite = TestSuite { - name: suite_name.clone(), - group: build_test_group(&suite_name, suite.tests), - }; - target_suites.push(suite); - } + let suites = suites + .into_iter() + .map(|(suite_name, suite)| TestSuite { group: build_test_group(&suite_name, suite.tests) }) + .collect(); - TestSuites { suites: target_suites } + TestSuites { suites } } /// Recursively expand a test group based on filesystem hierarchy. @@ -115,7 +112,7 @@ fn build_test_group<'a>(name: &str, tests: BTreeMap>) -> TestGr if components.peek().is_none() { // This is a root test - root_tests.push(test); + root_tests.push((name, test)); } else { // This is a test in a nested directory let subdir_tests = @@ -148,7 +145,6 @@ fn normalize_test_name(name: &str, suite_name: &str) -> String { name.trim_start_matches("/").to_string() } -#[derive(serde::Serialize)] struct TestSuites<'a> { suites: Vec>, } @@ -159,21 +155,16 @@ impl<'a> TestSuites<'a> { } } -#[derive(serde::Serialize)] struct TestSuite<'a> { - name: String, group: TestGroup<'a>, } -#[derive(Debug, serde::Serialize)] struct TestResults<'a> { passed: Vec>, ignored: Vec>, } -#[derive(Debug, serde::Serialize)] struct Test<'a> { - name: String, revisions: BTreeMap>, } @@ -189,7 +180,8 @@ impl<'a> Test<'a> { } } -#[derive(Clone, Copy, Debug, serde::Serialize)] +#[derive(Clone, Copy)] +#[allow(dead_code)] struct TestMetadata<'a> { job: &'a str, stage: u32, @@ -198,13 +190,13 @@ struct TestMetadata<'a> { // We have to use a template for the TestGroup instead of a macro, because // macros cannot be recursive in askama at the moment. -#[derive(Template, serde::Serialize)] +#[derive(Template)] #[template(path = "test_group.askama")] /// Represents a group of tests struct TestGroup<'a> { name: String, /// Tests located directly in this directory - root_tests: Vec>, + root_tests: Vec<(String, Test<'a>)>, /// Nested directories with additional tests groups: Vec<(String, TestGroup<'a>)>, } diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama index bdf32d00f4a1..95731103f3b9 100644 --- a/src/ci/citool/templates/test_group.askama +++ b/src/ci/citool/templates/test_group.askama @@ -21,12 +21,12 @@ passed: {{ r.passed.len() }}, ignored: {{ r.ignored.len() }} {% if !root_tests.is_empty() %}
        - {% for test in root_tests %} + {% for (name, test) in root_tests %}
      • {% if let Some(result) = test.single_test() %} - {{ test.name }} ({% call test_result(result) %}) + {{ name }} ({% call test_result(result) %}) {% else %} - {{ test.name }} ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }}) + {{ name }} ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }})
          {% for (revision, result) in test.revisions %}
        • #{{ revision }} ({% call test_result(result) %})
        • From 0d56e3eed1c5f3edea5cae6171e7a706ad792463 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Fri, 18 Apr 2025 12:29:51 +0200 Subject: [PATCH 056/109] LocalKey: document that the dtor should not panic --- library/std/src/thread/local.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index d5a5d10205dd..7cd448733130 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -22,12 +22,16 @@ use crate::fmt; /// /// Initialization is dynamically performed on the first call to a setter (e.g. /// [`with`]) within a thread, and values that implement [`Drop`] get -/// destructed when a thread exits. Some caveats apply, which are explained below. +/// destructed when a thread exits. Some platform-specific caveats apply, which +/// are explained below. +/// Note that, should the destructor panics, the whole process will be [aborted]. /// /// A `LocalKey`'s initializer cannot recursively depend on itself. Using a /// `LocalKey` in this way may cause panics, aborts or infinite recursion on /// the first call to `with`. /// +/// [aborted]: crate::process::abort +/// /// # Single-thread Synchronization /// /// Though there is no potential race with other threads, it is still possible to From ac7d1be031ac08cc0910efa3ec2f4186d7943792 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 16 Apr 2025 20:54:15 +0300 Subject: [PATCH 057/109] add coverage on config include logic Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/tests.rs | 211 ++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index d8002ba8467b..c8a12c9072c9 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,8 +1,8 @@ use std::collections::BTreeSet; -use std::env; use std::fs::{File, remove_file}; use std::io::Write; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::{env, fs}; use build_helper::ci::CiEnv; use clap::CommandFactory; @@ -23,6 +23,27 @@ pub(crate) fn parse(config: &str) -> Config { ) } +fn get_toml(file: &Path) -> Result { + let contents = std::fs::read_to_string(file).unwrap(); + toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table)) +} + +/// Helps with debugging by using consistent test-specific directories instead of +/// random temporary directories. +fn prepare_test_specific_dir() -> PathBuf { + let current = std::thread::current(); + // Replace "::" with "_" to make it safe for directory names on Windows systems + let test_path = current.name().unwrap().replace("::", "_"); + + let testdir = parse("").tempdir().join(test_path); + + // clean up any old test files + let _ = fs::remove_dir_all(&testdir); + let _ = fs::create_dir_all(&testdir); + + testdir +} + #[test] fn download_ci_llvm() { let config = parse("llvm.download-ci-llvm = false"); @@ -539,3 +560,189 @@ fn test_ci_flag() { let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str("")); assert_eq!(config.is_running_on_ci, CiEnv::is_ci()); } + +#[test] +fn test_precedence_of_includes() { + let testdir = prepare_test_specific_dir(); + + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + include = ["./extension.toml"] + + [llvm] + link-jobs = 2 + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let extension = testdir.join("extension.toml"); + let extension_content = br#" + change-id=543 + include = ["./extension2.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("extension2.toml"); + let extension_content = br#" + change-id=742 + + [llvm] + link-jobs = 10 + + [build] + description = "Some creative description" + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); + + assert_eq!(config.change_id.unwrap(), ChangeId::Id(543)); + assert_eq!(config.llvm_link_jobs.unwrap(), 2); + assert_eq!(config.description.unwrap(), "Some creative description"); +} + +#[test] +#[should_panic(expected = "Cyclic inclusion detected")] +fn test_cyclic_include_direct() { + let testdir = prepare_test_specific_dir(); + + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + include = ["./extension.toml"] + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let extension = testdir.join("extension.toml"); + let extension_content = br#" + include = ["./config.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); +} + +#[test] +#[should_panic(expected = "Cyclic inclusion detected")] +fn test_cyclic_include_indirect() { + let testdir = prepare_test_specific_dir(); + + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + include = ["./extension.toml"] + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let extension = testdir.join("extension.toml"); + let extension_content = br#" + include = ["./extension2.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("extension2.toml"); + let extension_content = br#" + include = ["./extension3.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("extension3.toml"); + let extension_content = br#" + include = ["./extension.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); +} + +#[test] +fn test_include_absolute_paths() { + let testdir = prepare_test_specific_dir(); + + let extension = testdir.join("extension.toml"); + File::create(&extension).unwrap().write_all(&[]).unwrap(); + + let root_config = testdir.join("config.toml"); + let extension_absolute_path = + extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\"); + let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path); + File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); +} + +#[test] +fn test_include_relative_paths() { + let testdir = prepare_test_specific_dir(); + + let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir")); + + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + include = ["./subdir/extension.toml"] + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let extension = testdir.join("subdir/extension.toml"); + let extension_content = br#" + include = ["../extension2.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("extension2.toml"); + let extension_content = br#" + include = ["./subdir/another_subdir/extension3.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("subdir/another_subdir/extension3.toml"); + let extension_content = br#" + include = ["../../extension4.toml"] + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let extension = testdir.join("extension4.toml"); + File::create(extension).unwrap().write_all(&[]).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); +} + +#[test] +fn test_include_precedence_over_profile() { + let testdir = prepare_test_specific_dir(); + + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + profile = "dist" + include = ["./extension.toml"] + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let extension = testdir.join("extension.toml"); + let extension_content = br#" + [rust] + channel = "dev" + "#; + File::create(extension).unwrap().write_all(extension_content).unwrap(); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), + get_toml, + ); + + // "dist" profile would normally set the channel to "auto-detect", but includes should + // override profile settings, so we expect this to be "dev" here. + assert_eq!(config.channel, "dev"); +} From 17b7d63fd787699dac3fffbf9930dc799291a5f2 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Fri, 18 Apr 2025 15:02:22 +0200 Subject: [PATCH 058/109] rtprintpanic: clarify that the error is aborting the process --- library/std/src/rt.rs | 2 +- .../miri/tests/fail/panic/tls_macro_const_drop_panic.stderr | 2 +- src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr | 2 +- tests/ui/runtime/rt-explody-panic-payloads.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 3a22a16cb165..9737b2f5bfe6 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -46,7 +46,7 @@ macro_rules! rtprintpanic { macro_rules! rtabort { ($($t:tt)*) => { { - rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); + rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); crate::sys::abort_internal(); } } diff --git a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr index aadb9976609c..1dcdb4a39968 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr @@ -1,7 +1,7 @@ thread $NAME panicked at tests/fail/panic/tls_macro_const_drop_panic.rs:LL:CC: ow -fatal runtime error: thread local panicked on drop +fatal runtime error: thread local panicked on drop, aborting error: abnormal termination: the program aborted execution error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr index 546ee7e1ed21..7e4907abd933 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr @@ -1,7 +1,7 @@ thread $NAME panicked at tests/fail/panic/tls_macro_drop_panic.rs:LL:CC: ow -fatal runtime error: thread local panicked on drop +fatal runtime error: thread local panicked on drop, aborting error: abnormal termination: the program aborted execution error: aborting due to 1 previous error diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs index c177fd260ed4..d564a26ca737 100644 --- a/tests/ui/runtime/rt-explody-panic-payloads.rs +++ b/tests/ui/runtime/rt-explody-panic-payloads.rs @@ -27,6 +27,6 @@ fn main() { // by QEMU in the stderr whenever a core dump happens. Remove it before the check. v.strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n").unwrap_or(v) }) - .map(|v| { v.ends_with("fatal runtime error: drop of the panic payload panicked\n") }) + .map(|v| v.ends_with("fatal runtime error: drop of the panic payload panicked, aborting\n")) .unwrap_or(false)); } From f727b3622bf69f44500e708f387160d5afbb39db Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Apr 2025 10:15:11 -0400 Subject: [PATCH 059/109] Invert `::deref` and `CString::as_c_str` This is consistent with the style of `ByteString`. --- library/alloc/src/ffi/c_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index f6743c657109..7e863f13f434 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -574,7 +574,7 @@ impl CString { #[stable(feature = "as_c_str", since = "1.20.0")] #[rustc_diagnostic_item = "cstring_as_c_str"] pub fn as_c_str(&self) -> &CStr { - &*self + unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } /// Converts this `CString` into a boxed [`CStr`]. @@ -705,14 +705,14 @@ impl ops::Deref for CString { #[inline] fn deref(&self) -> &CStr { - unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } + self.as_c_str() } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) + fmt::Debug::fmt(self.as_c_str(), f) } } From 9058bab9a9e88b90596019f686cce1f21ac19ef8 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Apr 2025 10:30:38 -0400 Subject: [PATCH 060/109] Move `` test to coretests --- library/alloctests/tests/c_str2.rs | 6 ------ library/coretests/tests/ffi/cstr.rs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/alloctests/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs index 0f4c27fa1232..fe7686bd1c59 100644 --- a/library/alloctests/tests/c_str2.rs +++ b/library/alloctests/tests/c_str2.rs @@ -33,12 +33,6 @@ fn build_with_zero2() { assert!(CString::new(vec![0]).is_err()); } -#[test] -fn formatted() { - let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); -} - #[test] fn borrowed() { unsafe { diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index 9bf4c21a9ab9..0d85b22c585a 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs @@ -13,3 +13,9 @@ fn compares_as_u8s() { assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes)); assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes)); } + +#[test] +fn debug() { + let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); +} From 87072c1d2ec0b5efbcc23eea838357fc629bcf99 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Apr 2025 11:20:14 -0400 Subject: [PATCH 061/109] Remove errant doc comment lines --- library/core/src/bstr/mod.rs | 1 - library/core/src/ffi/c_str.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index c8d0c701ba8b..07d4fd911d3a 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -37,7 +37,6 @@ use crate::ops::{Deref, DerefMut, DerefPure}; /// /// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a /// `str`, with invalid UTF-8 presented as the Unicode replacement character: � -/// #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[doc(alias = "BStr")] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 080c0cef5330..85e87445a1b4 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -150,7 +150,6 @@ impl Error for FromBytesWithNulError { /// within the slice. /// /// This error is created by the [`CStr::from_bytes_until_nul`] method. -/// #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub struct FromBytesUntilNulError(()); From 41ddf8672231c1f8cfa0fc754c1653f151030b19 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 29 Mar 2025 17:30:11 +0100 Subject: [PATCH 062/109] Make `#[naked]` an unsafe attribute --- compiler/rustc_builtin_macros/messages.ftl | 4 +- .../example/mini_core_hello_world.rs | 6 +- .../src/error_codes/E0736.md | 2 +- .../src/error_codes/E0787.md | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 8 ++- compiler/rustc_parse/src/validate_attr.rs | 6 -- compiler/rustc_passes/messages.ftl | 8 +-- .../src/compiler-flags/sanitizer.md | 37 +++++------ .../aarch64-naked-fn-no-bti-prolog.rs | 4 +- tests/assembly/naked-functions/aix.rs | 4 +- tests/assembly/naked-functions/wasm32.rs | 60 +++++++++--------- .../x86_64-naked-fn-no-cet-prolog.rs | 4 +- tests/codegen/cffi/c-variadic-naked.rs | 6 +- tests/codegen/naked-asan.rs | 4 +- tests/codegen/naked-fn/aligned.rs | 6 +- tests/codegen/naked-fn/generics.rs | 46 +++++++------- tests/codegen/naked-fn/instruction-set.rs | 12 ++-- .../naked-fn/min-function-alignment.rs | 16 ++--- tests/codegen/naked-fn/naked-functions.rs | 16 ++--- .../naked-symbol-visibility/a_rust_dylib.rs | 20 +++--- tests/ui/asm/naked-asm-outside-naked-fn.rs | 16 ++--- .../ui/asm/naked-asm-outside-naked-fn.stderr | 24 +++---- tests/ui/asm/naked-functions-ffi.rs | 6 +- tests/ui/asm/naked-functions-inline.rs | 20 +++--- tests/ui/asm/naked-functions-inline.stderr | 32 +++++----- .../ui/asm/naked-functions-instruction-set.rs | 8 +-- tests/ui/asm/naked-functions-rustic-abi.rs | 12 ++-- .../ui/asm/naked-functions-target-feature.rs | 12 ++-- tests/ui/asm/naked-functions-testattrs.rs | 16 ++--- tests/ui/asm/naked-functions-testattrs.stderr | 24 +++---- tests/ui/asm/naked-functions-unused.rs | 30 +++------ tests/ui/asm/naked-functions.rs | 62 +++++++++---------- tests/ui/asm/naked-functions.stderr | 50 +++++++-------- tests/ui/asm/naked-invalid-attr.rs | 28 ++++----- tests/ui/asm/naked-invalid-attr.stderr | 20 +++--- tests/ui/asm/naked-with-invalid-repr-attr.rs | 20 +++--- .../asm/naked-with-invalid-repr-attr.stderr | 12 ++-- tests/ui/asm/named-asm-labels.rs | 16 ++--- tests/ui/asm/named-asm-labels.stderr | 18 +++--- .../feature-gate-naked_functions.rs | 6 +- .../feature-gate-naked_functions.stderr | 45 ++++++++------ ...feature-gate-naked_functions_rustic_abi.rs | 6 +- ...ure-gate-naked_functions_target_feature.rs | 2 +- .../rfc-2091-track-caller/error-with-naked.rs | 4 +- .../error-with-naked.stderr | 16 ++--- 46 files changed, 375 insertions(+), 403 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 5316e90847ac..73be954cefd7 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -247,9 +247,9 @@ builtin_macros_multiple_defaults = multiple declared defaults .suggestion = make `{$ident}` default builtin_macros_naked_functions_testing_attribute = - cannot use `#[naked]` with testing attributes + cannot use `#[unsafe(naked)]` with testing attributes .label = function marked with testing attribute here - .naked_attribute = `#[naked]` is incompatible with testing attributes + .naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]` .label = this enum needs a unit variant marked with `#[default]` diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 09d5b73fd3d9..0b3a7281d5a0 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -387,11 +387,9 @@ global_asm! { } #[cfg(all(not(jit), target_arch = "x86_64"))] -#[naked] +#[unsafe(naked)] extern "C" fn naked_test() { - unsafe { - naked_asm!("ret"); - } + naked_asm!("ret") } #[repr(C)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index cb7633b7068a..66d5fbb80cf2 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -11,7 +11,7 @@ Erroneous code example: ```compile_fail,E0736 #[inline] -#[naked] +#[unsafe(naked)] fn foo() {} ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md index f5c5faa066b6..47b56ac17f4f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0787.md +++ b/compiler/rustc_error_codes/src/error_codes/E0787.md @@ -5,7 +5,7 @@ Erroneous code example: ```compile_fail,E0787 #![feature(naked_functions)] -#[naked] +#[unsafe(naked)] pub extern "C" fn f() -> u32 { 42 } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3b441729d755..713e460e507f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -517,7 +517,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Linking: gated!( - naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, + unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, naked_functions, experimental!(naked) ), diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b6a856a6eb4d..adfce99a9b53 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -564,13 +564,17 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } } ExprKind::InlineAsm(box InlineAsmExpr { - asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, + asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm), ref operands, template: _, options: _, line_spans: _, }) => { - self.requires_unsafe(expr.span, UseOfInlineAssembly); + // The `naked` attribute and the `naked_asm!` block form one atomic unit of + // unsafety, and `naked_asm!` does not itself need to be wrapped in an unsafe block. + if let AsmMacro::Asm = asm_macro { + self.requires_unsafe(expr.span, UseOfInlineAssembly); + } // For inline asm, do not use `walk_expr`, since we want to handle the label block // specially. diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b518fca7a658..6a1c2af48ed5 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -194,12 +194,6 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: } } } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - // Allow (but don't require) `#[unsafe(naked)]` so that compiler-builtins can upgrade to it. - // FIXME(#139797): remove this special case when compiler-builtins has upgraded. - if attr.has_name(sym::naked) { - return; - } - psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 99789b74488c..413726ddd82d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -508,7 +508,7 @@ passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} passes_naked_asm_outside_naked_fn = - the `naked_asm!` macro can only be used in functions marked with `#[naked]` + the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` passes_naked_functions_asm_block = naked functions must contain a single `naked_asm!` invocation @@ -516,9 +516,9 @@ passes_naked_functions_asm_block = .label_non_asm = not allowed in naked functions passes_naked_functions_incompatible_attribute = - attribute incompatible with `#[naked]` - .label = the `{$attr}` attribute is incompatible with `#[naked]` - .naked_attribute = function marked with `#[naked]` here + attribute incompatible with `#[unsafe(naked)]` + .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` + .naked_attribute = function marked with `#[unsafe(naked)]` here passes_naked_functions_must_naked_asm = the `asm!` macro is not allowed in naked functions diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 4679acf0a6a1..f2e1bb80cb26 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -247,34 +247,31 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. ```rust,ignore (making doc tests pass cross-platform is hard) #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; use std::mem; fn add_one(x: i32) -> i32 { x + 1 } -#[naked] +#[unsafe(naked)] pub extern "C" fn add_two(x: i32) { // x + 2 preceded by a landing pad/nop block - unsafe { - asm!( - " - nop - nop - nop - nop - nop - nop - nop - nop - nop - lea eax, [rdi+2] - ret - ", - options(noreturn) - ); - } + naked_asm!( + " + nop + nop + nop + nop + nop + nop + nop + nop + nop + lea eax, [rdi+2] + ret + " + ); } fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { diff --git a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs index 46e627eaa00b..46acf7c6501a 100644 --- a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs +++ b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs @@ -13,8 +13,8 @@ use std::arch::naked_asm; // LLVM implements this via making sure of that, even for functions with the naked attribute. // So, we must emit an appropriate instruction instead! #[no_mangle] -#[naked] -pub unsafe extern "C" fn _hlt() -> ! { +#[unsafe(naked)] +pub extern "C" fn _hlt() -> ! { // CHECK-NOT: hint #34 // CHECK: hlt #0x1 naked_asm!("hlt #1") diff --git a/tests/assembly/naked-functions/aix.rs b/tests/assembly/naked-functions/aix.rs index cc0825b37387..9aa9edc39e78 100644 --- a/tests/assembly/naked-functions/aix.rs +++ b/tests/assembly/naked-functions/aix.rs @@ -29,7 +29,7 @@ use minicore::*; // CHECK-LABEL: blr: // CHECK: blr #[no_mangle] -#[naked] -unsafe extern "C" fn blr() { +#[unsafe(naked)] +extern "C" fn blr() { naked_asm!("blr") } diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs index 4911a6bd08f6..c114cb385be1 100644 --- a/tests/assembly/naked-functions/wasm32.rs +++ b/tests/assembly/naked-functions/wasm32.rs @@ -22,8 +22,8 @@ use minicore::*; // CHECK-NOT: .size // CHECK: end_function #[no_mangle] -#[naked] -unsafe extern "C" fn nop() { +#[unsafe(naked)] +extern "C" fn nop() { naked_asm!("nop") } @@ -34,11 +34,11 @@ unsafe extern "C" fn nop() { // CHECK-NOT: .size // CHECK: end_function #[no_mangle] -#[naked] +#[unsafe(naked)] #[linkage = "weak"] // wasm functions cannot be aligned, so this has no effect #[repr(align(32))] -unsafe extern "C" fn weak_aligned_nop() { +extern "C" fn weak_aligned_nop() { naked_asm!("nop") } @@ -51,48 +51,48 @@ unsafe extern "C" fn weak_aligned_nop() { // // CHECK-NEXT: end_function #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 { +#[unsafe(naked)] +extern "C" fn fn_i8_i8(num: i8) -> i8 { naked_asm!("local.get 0", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_i8_i8_i8: // CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { +#[unsafe(naked)] +extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { naked_asm!("local.get 1", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_unit_i8: // CHECK: .functype fn_unit_i8 () -> (i32) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_unit_i8() -> i8 { +#[unsafe(naked)] +extern "C" fn fn_unit_i8() -> i8 { naked_asm!("i32.const 42") } // CHECK-LABEL: fn_i8_unit: // CHECK: .functype fn_i8_unit (i32) -> () #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i8_unit(_: i8) { +#[unsafe(naked)] +extern "C" fn fn_i8_unit(_: i8) { naked_asm!("nop") } // CHECK-LABEL: fn_i32_i32: // CHECK: .functype fn_i32_i32 (i32) -> (i32) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 { +#[unsafe(naked)] +extern "C" fn fn_i32_i32(num: i32) -> i32 { naked_asm!("local.get 0", "local.get 0", "i32.mul") } // CHECK-LABEL: fn_i64_i64: // CHECK: .functype fn_i64_i64 (i64) -> (i64) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { +#[unsafe(naked)] +extern "C" fn fn_i64_i64(num: i64) -> i64 { naked_asm!("local.get 0", "local.get 0", "i64.mul") } @@ -101,8 +101,8 @@ unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () #[allow(improper_ctypes_definitions)] #[no_mangle] -#[naked] -unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { +#[unsafe(naked)] +extern "C" fn fn_i128_i128(num: i128) -> i128 { naked_asm!( "local.get 0", "local.get 2", @@ -117,8 +117,8 @@ unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { // wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () #[no_mangle] -#[naked] -unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 { +#[unsafe(naked)] +extern "C" fn fn_f128_f128(num: f128) -> f128 { naked_asm!( "local.get 0", "local.get 2", @@ -139,8 +139,8 @@ struct Compound { // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () #[no_mangle] -#[naked] -unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound { +#[unsafe(naked)] +extern "C" fn fn_compound_compound(_: Compound) -> Compound { // this is the wasm32-wasip1 assembly naked_asm!( "local.get 0", @@ -160,8 +160,8 @@ struct WrapperI32(i32); // CHECK-LABEL: fn_wrapperi32_wrapperi32: // CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { +#[unsafe(naked)] +extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { naked_asm!("local.get 0") } @@ -171,8 +171,8 @@ struct WrapperI64(i64); // CHECK-LABEL: fn_wrapperi64_wrapperi64: // CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { +#[unsafe(naked)] +extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { naked_asm!("local.get 0") } @@ -182,8 +182,8 @@ struct WrapperF32(f32); // CHECK-LABEL: fn_wrapperf32_wrapperf32: // CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { +#[unsafe(naked)] +extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { naked_asm!("local.get 0") } @@ -193,7 +193,7 @@ struct WrapperF64(f64); // CHECK-LABEL: fn_wrapperf64_wrapperf64: // CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) #[no_mangle] -#[naked] -unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { +#[unsafe(naked)] +extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { naked_asm!("local.get 0") } diff --git a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs index 54e1d93c68bd..df6a2e91c51e 100644 --- a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs +++ b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs @@ -13,8 +13,8 @@ use std::arch::naked_asm; // works by using an instruction for each possible landing site, // and LLVM implements this via making sure of that. #[no_mangle] -#[naked] -pub unsafe extern "sysv64" fn will_halt() -> ! { +#[unsafe(naked)] +pub extern "sysv64" fn will_halt() -> ! { // CHECK-NOT: endbr{{32|64}} // CHECK: hlt naked_asm!("hlt") diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs index 24b69c5f59e2..05d48e52dc00 100644 --- a/tests/codegen/cffi/c-variadic-naked.rs +++ b/tests/codegen/cffi/c-variadic-naked.rs @@ -8,11 +8,9 @@ #![feature(naked_functions)] #![no_std] -#[naked] +#[unsafe(naked)] pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { // CHECK-NOT: va_start // CHECK-NOT: alloca - core::arch::naked_asm! { - "ret", - } + core::arch::naked_asm!("ret") } diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index 8efedab6ea55..52b3e709cd35 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -13,10 +13,10 @@ pub fn caller() { } // CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]] -#[naked] +#[unsafe(naked)] #[no_mangle] pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { - unsafe { core::arch::naked_asm!("ud2") }; + core::arch::naked_asm!("ud2") } // CHECK: #[[ATTRS]] = diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index d9dcd7f6c3ef..6183461fedae 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -10,8 +10,8 @@ use std::arch::naked_asm; // CHECK-LABEL: naked_empty: #[repr(align(16))] #[no_mangle] -#[naked] -pub unsafe extern "C" fn naked_empty() { +#[unsafe(naked)] +pub extern "C" fn naked_empty() { // CHECK: ret - naked_asm!("ret"); + naked_asm!("ret") } diff --git a/tests/codegen/naked-fn/generics.rs b/tests/codegen/naked-fn/generics.rs index 64998df64ddb..442758677716 100644 --- a/tests/codegen/naked-fn/generics.rs +++ b/tests/codegen/naked-fn/generics.rs @@ -28,21 +28,19 @@ fn test(x: u64) { // CHECK: add rax, 1 // CHECK: add rax, 42 -#[naked] +#[unsafe(naked)] pub extern "C" fn using_const_generics(x: u64) -> u64 { const M: u64 = 42; - unsafe { - naked_asm!( - "xor rax, rax", - "add rax, rdi", - "add rax, {}", - "add rax, {}", - "ret", - const N, - const M, - ) - } + naked_asm!( + "xor rax, rax", + "add rax, rdi", + "add rax, {}", + "add rax, {}", + "ret", + const N, + const M, + ) } trait Invert { @@ -60,16 +58,14 @@ impl Invert for i64 { // CHECK: call // CHECK: ret -#[naked] +#[unsafe(naked)] #[no_mangle] pub extern "C" fn generic_function(x: i64) -> i64 { - unsafe { - naked_asm!( - "call {}", - "ret", - sym ::invert, - ) - } + naked_asm!( + "call {}", + "ret", + sym ::invert, + ) } #[derive(Copy, Clone)] @@ -81,10 +77,10 @@ struct Foo(u64); // CHECK: mov rax, rdi impl Foo { - #[naked] + #[unsafe(naked)] #[no_mangle] extern "C" fn method(self) -> u64 { - unsafe { naked_asm!("mov rax, rdi", "ret") } + naked_asm!("mov rax, rdi", "ret") } } @@ -97,10 +93,10 @@ trait Bar { } impl Bar for Foo { - #[naked] + #[unsafe(naked)] #[no_mangle] extern "C" fn trait_method(self) -> u64 { - unsafe { naked_asm!("mov rax, rdi", "ret") } + naked_asm!("mov rax, rdi", "ret") } } @@ -109,7 +105,7 @@ impl Bar for Foo { // CHECK: lea rax, [rdi + rsi] // this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375 -#[naked] +#[unsafe(naked)] #[no_mangle] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { naked_asm!("lea rax, [rdi + rsi]", "ret"); diff --git a/tests/codegen/naked-fn/instruction-set.rs b/tests/codegen/naked-fn/instruction-set.rs index a7b4c22a59bf..2ccd47d64585 100644 --- a/tests/codegen/naked-fn/instruction-set.rs +++ b/tests/codegen/naked-fn/instruction-set.rs @@ -20,8 +20,8 @@ use minicore::*; // arm-mode: .arm // thumb-mode: .thumb #[no_mangle] -#[naked] -unsafe extern "C" fn test_unspecified() { +#[unsafe(naked)] +extern "C" fn test_unspecified() { naked_asm!("bx lr"); } @@ -33,9 +33,9 @@ unsafe extern "C" fn test_unspecified() { // arm-mode: .arm // thumb-mode: .thumb #[no_mangle] -#[naked] +#[unsafe(naked)] #[instruction_set(arm::t32)] -unsafe extern "C" fn test_thumb() { +extern "C" fn test_thumb() { naked_asm!("bx lr"); } @@ -46,8 +46,8 @@ unsafe extern "C" fn test_thumb() { // arm-mode: .arm // thumb-mode: .thumb #[no_mangle] -#[naked] +#[unsafe(naked)] #[instruction_set(arm::a32)] -unsafe extern "C" fn test_arm() { +extern "C" fn test_arm() { naked_asm!("bx lr"); } diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs index 1330d796d397..4a9142288248 100644 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ b/tests/codegen/naked-fn/min-function-alignment.rs @@ -9,24 +9,24 @@ // // CHECK: .balign 16 #[no_mangle] -#[naked] -pub unsafe extern "C" fn naked_no_explicit_align() { +#[unsafe(naked)] +pub extern "C" fn naked_no_explicit_align() { core::arch::naked_asm!("ret") } // CHECK: .balign 16 #[no_mangle] #[repr(align(8))] -#[naked] -pub unsafe extern "C" fn naked_lower_align() { +#[unsafe(naked)] +pub extern "C" fn naked_lower_align() { core::arch::naked_asm!("ret") } // CHECK: .balign 32 #[no_mangle] #[repr(align(32))] -#[naked] -pub unsafe extern "C" fn naked_higher_align() { +#[unsafe(naked)] +pub extern "C" fn naked_higher_align() { core::arch::naked_asm!("ret") } @@ -38,7 +38,7 @@ pub unsafe extern "C" fn naked_higher_align() { // CHECK: .balign 16 #[no_mangle] #[cold] -#[naked] -pub unsafe extern "C" fn no_explicit_align_cold() { +#[unsafe(naked)] +pub extern "C" fn no_explicit_align_cold() { core::arch::naked_asm!("ret") } diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 3fe795178b70..1bcdd6de373e 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -60,8 +60,8 @@ use minicore::*; // linux,win: .att_syntax #[no_mangle] -#[naked] -pub unsafe extern "C" fn naked_empty() { +#[unsafe(naked)] +pub extern "C" fn naked_empty() { #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] naked_asm!("ret"); @@ -114,8 +114,8 @@ pub unsafe extern "C" fn naked_empty() { // linux,win: .att_syntax #[no_mangle] -#[naked] -pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { +#[unsafe(naked)] +pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { #[cfg(any(target_os = "windows", target_os = "linux"))] { naked_asm!("lea rax, [rdi + rsi]", "ret") @@ -138,9 +138,9 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits // CHECK-LABEL: test_link_section: #[no_mangle] -#[naked] +#[unsafe(naked)] #[link_section = ".text.some_different_name"] -pub unsafe extern "C" fn test_link_section() { +pub extern "C" fn test_link_section() { #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] naked_asm!("ret"); @@ -159,7 +159,7 @@ pub unsafe extern "C" fn test_link_section() { // win_i686-LABEL: @fastcall_cc@4: #[cfg(target_os = "windows")] #[no_mangle] -#[naked] -pub unsafe extern "fastcall" fn fastcall_cc(x: i32) -> i32 { +#[unsafe(naked)] +pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 { naked_asm!("ret"); } diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs index f98a2036544c..ae7551952536 100644 --- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs +++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs @@ -26,9 +26,9 @@ extern "C" fn private_vanilla() -> u32 { 42 } -#[naked] +#[unsafe(naked)] extern "C" fn private_naked() -> u32 { - unsafe { naked_asm!("mov rax, 42", "ret") } + naked_asm!("mov rax, 42", "ret") } #[no_mangle] @@ -36,19 +36,19 @@ pub extern "C" fn public_vanilla() -> u32 { 42 } -#[naked] +#[unsafe(naked)] #[no_mangle] pub extern "C" fn public_naked_nongeneric() -> u32 { - unsafe { naked_asm!("mov rax, 42", "ret") } + naked_asm!("mov rax, 42", "ret") } pub extern "C" fn public_vanilla_generic() -> u32 { T::COUNT } -#[naked] +#[unsafe(naked)] pub extern "C" fn public_naked_generic() -> u32 { - unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) } + naked_asm!("mov rax, {}", "ret", const T::COUNT) } #[linkage = "external"] @@ -56,10 +56,10 @@ extern "C" fn vanilla_external_linkage() -> u32 { 42 } -#[naked] +#[unsafe(naked)] #[linkage = "external"] extern "C" fn naked_external_linkage() -> u32 { - unsafe { naked_asm!("mov rax, 42", "ret") } + naked_asm!("mov rax, 42", "ret") } #[cfg(not(windows))] @@ -68,11 +68,11 @@ extern "C" fn vanilla_weak_linkage() -> u32 { 42 } -#[naked] +#[unsafe(naked)] #[cfg(not(windows))] #[linkage = "weak"] extern "C" fn naked_weak_linkage() -> u32 { - unsafe { naked_asm!("mov rax, 42", "ret") } + naked_asm!("mov rax, 42", "ret") } // functions that are declared in an `extern "C"` block are currently not exported diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.rs b/tests/ui/asm/naked-asm-outside-naked-fn.rs index 1696008f3397..a7680cc63ae0 100644 --- a/tests/ui/asm/naked-asm-outside-naked-fn.rs +++ b/tests/ui/asm/naked-asm-outside-naked-fn.rs @@ -12,24 +12,24 @@ fn main() { test1(); } -#[naked] +#[unsafe(naked)] extern "C" fn test1() { - unsafe { naked_asm!("") } + naked_asm!("") } extern "C" fn test2() { - unsafe { naked_asm!("") } - //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` + naked_asm!("") + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` } extern "C" fn test3() { - unsafe { (|| naked_asm!(""))() } - //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` + (|| naked_asm!(""))() + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` } fn test4() { async move { - unsafe { naked_asm!("") } ; - //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` + naked_asm!(""); + //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` }; } diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.stderr b/tests/ui/asm/naked-asm-outside-naked-fn.stderr index 6e91359669ca..85a50a49fecf 100644 --- a/tests/ui/asm/naked-asm-outside-naked-fn.stderr +++ b/tests/ui/asm/naked-asm-outside-naked-fn.stderr @@ -1,20 +1,20 @@ -error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` - --> $DIR/naked-asm-outside-naked-fn.rs:21:14 +error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` + --> $DIR/naked-asm-outside-naked-fn.rs:21:5 | -LL | unsafe { naked_asm!("") } - | ^^^^^^^^^^^^^^ +LL | naked_asm!("") + | ^^^^^^^^^^^^^^ -error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` - --> $DIR/naked-asm-outside-naked-fn.rs:26:18 +error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` + --> $DIR/naked-asm-outside-naked-fn.rs:26:9 | -LL | unsafe { (|| naked_asm!(""))() } - | ^^^^^^^^^^^^^^ +LL | (|| naked_asm!(""))() + | ^^^^^^^^^^^^^^ -error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` - --> $DIR/naked-asm-outside-naked-fn.rs:32:19 +error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` + --> $DIR/naked-asm-outside-naked-fn.rs:32:9 | -LL | unsafe { naked_asm!("") } ; - | ^^^^^^^^^^^^^^ +LL | naked_asm!(""); + | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index b78d1e6a0d1c..8fd0da01d72a 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -5,11 +5,9 @@ use std::arch::naked_asm; -#[naked] +#[unsafe(naked)] pub extern "C" fn naked(p: char) -> u128 { //~^ WARN uses type `char` //~| WARN uses type `u128` - unsafe { - naked_asm!(""); - } + naked_asm!("") } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 74049e8ecbc7..261401be6451 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -4,35 +4,35 @@ use std::arch::naked_asm; -#[naked] -pub unsafe extern "C" fn inline_none() { +#[unsafe(naked)] +pub extern "C" fn inline_none() { naked_asm!(""); } -#[naked] +#[unsafe(naked)] #[inline] //~^ ERROR [E0736] -pub unsafe extern "C" fn inline_hint() { +pub extern "C" fn inline_hint() { naked_asm!(""); } -#[naked] +#[unsafe(naked)] #[inline(always)] //~^ ERROR [E0736] -pub unsafe extern "C" fn inline_always() { +pub extern "C" fn inline_always() { naked_asm!(""); } -#[naked] +#[unsafe(naked)] #[inline(never)] //~^ ERROR [E0736] -pub unsafe extern "C" fn inline_never() { +pub extern "C" fn inline_never() { naked_asm!(""); } -#[naked] +#[unsafe(naked)] #[cfg_attr(all(), inline(never))] //~^ ERROR [E0736] -pub unsafe extern "C" fn conditional_inline_never() { +pub extern "C" fn conditional_inline_never() { naked_asm!(""); } diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 84a688f6f538..6df5b08ae853 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -1,34 +1,34 @@ -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-functions-inline.rs:13:1 | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline] - | ^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-functions-inline.rs:20:1 | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-functions-inline.rs:27:1 | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-functions-inline.rs:34:19 | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here LL | #[cfg_attr(all(), inline(never))] - | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error: aborting due to 4 previous errors diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index 28241badf5f8..6fd34b035edd 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -12,15 +12,15 @@ extern crate minicore; use minicore::*; #[no_mangle] -#[naked] +#[unsafe(naked)] #[instruction_set(arm::t32)] -unsafe extern "C" fn test_thumb() { +extern "C" fn test_thumb() { naked_asm!("bx lr"); } #[no_mangle] -#[naked] +#[unsafe(naked)] #[instruction_set(arm::a32)] -unsafe extern "C" fn test_arm() { +extern "C" fn test_arm() { naked_asm!("bx lr"); } diff --git a/tests/ui/asm/naked-functions-rustic-abi.rs b/tests/ui/asm/naked-functions-rustic-abi.rs index b654d38ccc1a..99b8d2e19fe4 100644 --- a/tests/ui/asm/naked-functions-rustic-abi.rs +++ b/tests/ui/asm/naked-functions-rustic-abi.rs @@ -11,17 +11,17 @@ use std::arch::{asm, naked_asm}; -#[naked] -pub unsafe fn rust_implicit() { +#[unsafe(naked)] +pub fn rust_implicit() { naked_asm!("ret"); } -#[naked] -pub unsafe extern "Rust" fn rust_explicit() { +#[unsafe(naked)] +pub extern "Rust" fn rust_explicit() { naked_asm!("ret"); } -#[naked] -pub unsafe extern "rust-cold" fn rust_cold() { +#[unsafe(naked)] +pub extern "rust-cold" fn rust_cold() { naked_asm!("ret"); } diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs index afe1a3891472..d8dc2104c76e 100644 --- a/tests/ui/asm/naked-functions-target-feature.rs +++ b/tests/ui/asm/naked-functions-target-feature.rs @@ -8,14 +8,14 @@ use std::arch::{asm, naked_asm}; #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] -#[naked] -pub unsafe extern "C" fn compatible_target_feature() { - naked_asm!(""); +#[unsafe(naked)] +pub extern "C" fn compatible_target_feature() { + naked_asm!("ret"); } #[cfg(target_arch = "aarch64")] #[target_feature(enable = "neon")] -#[naked] -pub unsafe extern "C" fn compatible_target_feature() { - naked_asm!(""); +#[unsafe(naked)] +pub extern "C" fn compatible_target_feature() { + naked_asm!("ret"); } diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index ad31876a77a5..c8539e806408 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -8,31 +8,31 @@ use std::arch::naked_asm; #[test] -#[naked] +#[unsafe(naked)] //~^ ERROR [E0736] extern "C" fn test_naked() { - unsafe { naked_asm!("") }; + naked_asm!("") } #[should_panic] #[test] -#[naked] +#[unsafe(naked)] //~^ ERROR [E0736] extern "C" fn test_naked_should_panic() { - unsafe { naked_asm!("") }; + naked_asm!("") } #[ignore] #[test] -#[naked] +#[unsafe(naked)] //~^ ERROR [E0736] extern "C" fn test_naked_ignore() { - unsafe { naked_asm!("") }; + naked_asm!("") } #[bench] -#[naked] +#[unsafe(naked)] //~^ ERROR [E0736] extern "C" fn bench_naked() { - unsafe { naked_asm!("") }; + naked_asm!("") } diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr index 0f0bb91b9541..ad2041ec118b 100644 --- a/tests/ui/asm/naked-functions-testattrs.stderr +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -1,34 +1,34 @@ -error[E0736]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes --> $DIR/naked-functions-testattrs.rs:11:1 | LL | #[test] | ------- function marked with testing attribute here -LL | #[naked] - | ^^^^^^^^ `#[naked]` is incompatible with testing attributes +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes -error[E0736]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes --> $DIR/naked-functions-testattrs.rs:19:1 | LL | #[test] | ------- function marked with testing attribute here -LL | #[naked] - | ^^^^^^^^ `#[naked]` is incompatible with testing attributes +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes -error[E0736]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes --> $DIR/naked-functions-testattrs.rs:27:1 | LL | #[test] | ------- function marked with testing attribute here -LL | #[naked] - | ^^^^^^^^ `#[naked]` is incompatible with testing attributes +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes -error[E0736]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes --> $DIR/naked-functions-testattrs.rs:34:1 | LL | #[bench] | -------- function marked with testing attribute here -LL | #[naked] - | ^^^^^^^^ `#[naked]` is incompatible with testing attributes +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes error: aborting due to 4 previous errors diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs index c27037819a44..67c05984be71 100644 --- a/tests/ui/asm/naked-functions-unused.rs +++ b/tests/ui/asm/naked-functions-unused.rs @@ -64,44 +64,34 @@ pub mod normal { pub mod naked { use std::arch::naked_asm; - #[naked] + #[unsafe(naked)] pub extern "C" fn function(a: usize, b: usize) -> usize { - unsafe { - naked_asm!(""); - } + naked_asm!("") } pub struct Naked; impl Naked { - #[naked] + #[unsafe(naked)] pub extern "C" fn associated(a: usize, b: usize) -> usize { - unsafe { - naked_asm!(""); - } + naked_asm!("") } - #[naked] + #[unsafe(naked)] pub extern "C" fn method(&self, a: usize, b: usize) -> usize { - unsafe { - naked_asm!(""); - } + naked_asm!("") } } impl super::Trait for Naked { - #[naked] + #[unsafe(naked)] extern "C" fn trait_associated(a: usize, b: usize) -> usize { - unsafe { - naked_asm!(""); - } + naked_asm!("") } - #[naked] + #[unsafe(naked)] extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { - unsafe { - naked_asm!(""); - } + naked_asm!("") } } } diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 8ba0eecb7b5c..b433c1b5389c 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -9,8 +9,8 @@ use std::arch::{asm, naked_asm}; #[unsafe(naked)] -pub unsafe extern "C" fn inline_asm_macro() { - asm!("", options(raw)); +pub extern "C" fn inline_asm_macro() { + unsafe { asm!("", options(raw)) }; //~^ERROR the `asm!` macro is not allowed in naked functions } @@ -21,7 +21,7 @@ pub struct P { } #[unsafe(naked)] -pub unsafe extern "C" fn patterns( +pub extern "C" fn patterns( mut a: u32, //~^ ERROR patterns not allowed in naked function parameters &b: &i32, @@ -35,7 +35,7 @@ pub unsafe extern "C" fn patterns( } #[unsafe(naked)] -pub unsafe extern "C" fn inc(a: u32) -> u32 { +pub extern "C" fn inc(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions @@ -43,19 +43,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { #[unsafe(naked)] #[allow(asm_sub_register)] -pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { +pub extern "C" fn inc_asm(a: u32) -> u32 { naked_asm!("/* {0} */", in(reg) a) //~^ ERROR the `in` operand cannot be used with `naked_asm!` } #[unsafe(naked)] -pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { +pub extern "C" fn inc_closure(a: u32) -> u32 { //~^ ERROR naked functions must contain a single `naked_asm!` invocation (|| a + 1)() } #[unsafe(naked)] -pub unsafe extern "C" fn unsupported_operands() { +pub extern "C" fn unsupported_operands() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation let mut a = 0usize; let mut b = 0usize; @@ -84,11 +84,10 @@ pub extern "C" fn missing_assembly() { #[unsafe(naked)] pub extern "C" fn too_many_asm_blocks() { //~^ ERROR naked functions must contain a single `naked_asm!` invocation - unsafe { - naked_asm!("", options(noreturn)); - //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` - naked_asm!(""); - } + + naked_asm!("", options(noreturn)); + //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` + naked_asm!(""); } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { @@ -124,49 +123,44 @@ unsafe extern "C" fn invalid_may_unwind() { #[unsafe(naked)] pub extern "C" fn valid_a() -> T { - unsafe { - naked_asm!(""); - } + naked_asm!(""); } #[unsafe(naked)] pub extern "C" fn valid_b() { - unsafe { + { { - { - naked_asm!(""); - }; + naked_asm!(""); }; - } + }; } #[unsafe(naked)] -pub unsafe extern "C" fn valid_c() { +pub extern "C" fn valid_c() { naked_asm!(""); } #[cfg(target_arch = "x86_64")] #[unsafe(naked)] -pub unsafe extern "C" fn valid_att_syntax() { +pub extern "C" fn valid_att_syntax() { naked_asm!("", options(att_syntax)); } #[unsafe(naked)] -#[unsafe(naked)] -pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { +pub extern "C" fn allow_compile_error(a: u32) -> u32 { compile_error!("this is a user specified error") //~^ ERROR this is a user specified error } #[unsafe(naked)] -pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { +pub extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error naked_asm!("") } #[unsafe(naked)] -pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { +pub extern "C" fn invalid_asm_syntax(a: u32) -> u32 { naked_asm!(invalid_syntax) //~^ ERROR asm template must be a string literal } @@ -174,7 +168,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg(target_arch = "x86_64")] #[cfg_attr(target_pointer_width = "64", no_mangle)] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_cfg_attributes() { +pub extern "C" fn compatible_cfg_attributes() { naked_asm!("", options(att_syntax)); } @@ -183,20 +177,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[deny(dead_code)] #[forbid(dead_code)] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_diagnostic_attributes() { +pub extern "C" fn compatible_diagnostic_attributes() { naked_asm!("", options(raw)); } #[deprecated = "test"] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_deprecated_attributes() { +pub extern "C" fn compatible_deprecated_attributes() { naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[must_use] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { +pub extern "C" fn compatible_must_use_attributes() -> u64 { naked_asm!( " mov rax, 42 @@ -208,13 +202,13 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[export_name = "exported_function_name"] #[link_section = ".custom_section"] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_ffi_attributes_1() { +pub extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); } #[cold] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_codegen_attributes() { +pub extern "C" fn compatible_codegen_attributes() { naked_asm!("", options(raw)); } @@ -223,12 +217,12 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { // a normal comment #[doc(alias = "ADocAlias")] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_doc_attributes() { +pub extern "C" fn compatible_doc_attributes() { naked_asm!("", options(raw)); } #[linkage = "external"] #[unsafe(naked)] -pub unsafe extern "C" fn compatible_linkage() { +pub extern "C" fn compatible_linkage() { naked_asm!("", options(raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 0a55bb9cd837..2b67c3aecd73 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -11,70 +11,70 @@ LL | in(reg) a, | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `noreturn` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:88:32 + --> $DIR/naked-functions.rs:88:28 | -LL | naked_asm!("", options(noreturn)); - | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly +LL | naked_asm!("", options(noreturn)); + | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly error: the `nomem` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:106:28 + --> $DIR/naked-functions.rs:105:28 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:106:35 + --> $DIR/naked-functions.rs:105:35 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:113:28 + --> $DIR/naked-functions.rs:112:28 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:113:38 + --> $DIR/naked-functions.rs:112:38 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:113:56 + --> $DIR/naked-functions.rs:112:56 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `may_unwind` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:121:28 + --> $DIR/naked-functions.rs:120:28 | LL | naked_asm!("", options(may_unwind)); | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:157:5 + --> $DIR/naked-functions.rs:151:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:163:5 + --> $DIR/naked-functions.rs:157:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:170:16 + --> $DIR/naked-functions.rs:164:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ error[E0787]: the `asm!` macro is not allowed in naked functions - --> $DIR/naked-functions.rs:13:5 + --> $DIR/naked-functions.rs:13:14 | -LL | asm!("", options(raw)); - | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead +LL | unsafe { asm!("", options(raw)) }; + | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead error: patterns not allowed in naked function parameters --> $DIR/naked-functions.rs:25:5 @@ -111,8 +111,8 @@ LL | a + 1 error[E0787]: naked functions must contain a single `naked_asm!` invocation --> $DIR/naked-functions.rs:38:1 | -LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C" fn inc(a: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | a + 1 | ----- not allowed in naked functions @@ -120,8 +120,8 @@ LL | a + 1 error[E0787]: naked functions must contain a single `naked_asm!` invocation --> $DIR/naked-functions.rs:52:1 | -LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C" fn inc_closure(a: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | (|| a + 1)() | ------------ not allowed in naked functions @@ -129,8 +129,8 @@ LL | (|| a + 1)() error[E0787]: naked functions must contain a single `naked_asm!` invocation --> $DIR/naked-functions.rs:58:1 | -LL | pub unsafe extern "C" fn unsupported_operands() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C" fn unsupported_operands() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | let mut a = 0usize; | ------------------- not allowed in naked functions @@ -155,11 +155,11 @@ error[E0787]: naked functions must contain a single `naked_asm!` invocation LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | naked_asm!(""); - | -------------- multiple `naked_asm!` invocations are not allowed in naked functions +LL | naked_asm!(""); + | -------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:98:11 + --> $DIR/naked-functions.rs:97:11 | LL | *&y | ^ @@ -167,7 +167,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:96:5 + --> $DIR/naked-functions.rs:95:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index 4053c58fb513..6c5fdbe74d82 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -1,17 +1,17 @@ -// Checks that #[naked] attribute can be placed on function definitions only. +// Checks that #[unsafe(naked)] attribute can be placed on function definitions only. // //@ needs-asm-support #![feature(naked_functions)] -#![naked] //~ ERROR should be applied to a function definition +#![unsafe(naked)] //~ ERROR should be applied to a function definition use std::arch::naked_asm; extern "C" { - #[naked] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR should be applied to a function definition fn f(); } -#[naked] //~ ERROR should be applied to a function definition +#[unsafe(naked)] //~ ERROR should be applied to a function definition #[repr(C)] struct S { a: u32, @@ -19,35 +19,35 @@ struct S { } trait Invoke { - #[naked] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR should be applied to a function definition extern "C" fn invoke(&self); } impl Invoke for S { - #[naked] + #[unsafe(naked)] extern "C" fn invoke(&self) { - unsafe { naked_asm!("") } + naked_asm!("") } } -#[naked] +#[unsafe(naked)] extern "C" fn ok() { - unsafe { naked_asm!("") } + naked_asm!("") } impl S { - #[naked] + #[unsafe(naked)] extern "C" fn g() { - unsafe { naked_asm!("") } + naked_asm!("") } - #[naked] + #[unsafe(naked)] extern "C" fn h(&self) { - unsafe { naked_asm!("") } + naked_asm!("") } } fn main() { - #[naked] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR should be applied to a function definition || {}; } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 640f9d9510d1..6e2746b56843 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -1,8 +1,8 @@ error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:14:1 | -LL | #[naked] - | ^^^^^^^^ +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ LL | #[repr(C)] LL | / struct S { LL | | a: u32, @@ -13,32 +13,32 @@ LL | | } error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:51:5 | -LL | #[naked] - | ^^^^^^^^ +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ LL | || {}; | ----- not a function definition error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:22:5 | -LL | #[naked] - | ^^^^^^^^ +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ LL | extern "C" fn invoke(&self); | ---------------------------- not a function definition error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:10:5 | -LL | #[naked] - | ^^^^^^^^ +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ LL | fn f(); | ------- not a function definition error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:5:1 | -LL | #![naked] - | ^^^^^^^^^ cannot be applied to crates +LL | #![unsafe(naked)] + | ^^^^^^^^^^^^^^^^^ cannot be applied to crates error: aborting due to 5 previous errors diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index 18b9c1014c3f..c9f335ea9506 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -6,43 +6,43 @@ use std::arch::naked_asm; #[repr(C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] -#[naked] +#[unsafe(naked)] extern "C" fn example1() { //~^ NOTE not a struct, enum, or union - unsafe { naked_asm!("") } + naked_asm!("") } #[repr(transparent)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] -#[naked] +#[unsafe(naked)] extern "C" fn example2() { //~^ NOTE not a struct, enum, or union - unsafe { naked_asm!("") } + naked_asm!("") } #[repr(align(16), C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] -#[naked] +#[unsafe(naked)] extern "C" fn example3() { //~^ NOTE not a struct, enum, or union - unsafe { naked_asm!("") } + naked_asm!("") } // note: two errors because of packed and C #[repr(C, packed)] //~^ ERROR attribute should be applied to a struct or union [E0517] //~| ERROR attribute should be applied to a struct, enum, or union [E0517] -#[naked] +#[unsafe(naked)] extern "C" fn example4() { //~^ NOTE not a struct, enum, or union //~| NOTE not a struct or union - unsafe { naked_asm!("") } + naked_asm!("") } #[repr(u8)] //~^ ERROR attribute should be applied to an enum [E0517] -#[naked] +#[unsafe(naked)] extern "C" fn example5() { //~^ NOTE not an enum - unsafe { naked_asm!("") } + naked_asm!("") } diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index 8248a8c16579..219e32473bea 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -6,7 +6,7 @@ LL | #[repr(C)] ... LL | / extern "C" fn example1() { LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not a struct, enum, or union @@ -18,7 +18,7 @@ LL | #[repr(transparent)] ... LL | / extern "C" fn example2() { LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not a struct, enum, or union @@ -30,7 +30,7 @@ LL | #[repr(align(16), C)] ... LL | / extern "C" fn example3() { LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not a struct, enum, or union @@ -43,7 +43,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not a struct, enum, or union @@ -56,7 +56,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not a struct or union @@ -68,7 +68,7 @@ LL | #[repr(u8)] ... LL | / extern "C" fn example5() { LL | | -LL | | unsafe { naked_asm!("") } +LL | | naked_asm!("") LL | | } | |_- not an enum diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 77831e679ed4..d5c194452d75 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -175,9 +175,9 @@ fn main() { // Trigger on naked fns too, even though they can't be inlined, reusing a // label or LTO can cause labels to break -#[naked] +#[unsafe(naked)] pub extern "C" fn foo() -> i32 { - unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } + naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) //~^ ERROR avoid using named labels } @@ -188,21 +188,21 @@ pub extern "C" fn bar() { //~^ ERROR avoid using named labels } -#[naked] +#[unsafe(naked)] pub extern "C" fn aaa() { fn _local() {} - unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels + naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels } pub fn normal() { fn _local1() {} - #[naked] + #[unsafe(naked)] pub extern "C" fn bbb() { fn _very_local() {} - unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels + naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels } fn _local2() {} @@ -219,8 +219,8 @@ fn closures() { }; || { - #[naked] - unsafe extern "C" fn _nested() { + #[unsafe(naked)] + extern "C" fn _nested() { naked_asm!("ret;"); } diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index 44ce358c62bd..0120d4948d51 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:180:26 + --> $DIR/named-asm-labels.rs:180:17 | -LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } - | ^^^^^ +LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information @@ -493,19 +493,19 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:195:26 + --> $DIR/named-asm-labels.rs:195:17 | -LL | unsafe { naked_asm!(".Laaa: nop; ret;") } - | ^^^^^ +LL | naked_asm!(".Laaa: nop; ret;") + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:205:30 + --> $DIR/named-asm-labels.rs:205:21 | -LL | unsafe { naked_asm!(".Lbbb: nop; ret;") } - | ^^^^^ +LL | naked_asm!(".Lbbb: nop; ret;") + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index 77a67e0696eb..d940decd561e 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -3,20 +3,18 @@ use std::arch::naked_asm; //~^ ERROR use of unstable library feature `naked_functions` -#[naked] +#[naked] //~ ERROR unsafe attribute used without unsafe //~^ ERROR the `#[naked]` attribute is an experimental feature extern "C" fn naked() { naked_asm!("") //~^ ERROR use of unstable library feature `naked_functions` - //~| ERROR: requires unsafe } -#[naked] +#[naked] //~ ERROR unsafe attribute used without unsafe //~^ ERROR the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { naked_asm!("") //~^ ERROR use of unstable library feature `naked_functions` - //~| ERROR: requires unsafe } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr index 9bfb9275bb20..ea765db7d946 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr @@ -9,7 +9,7 @@ LL | naked_asm!("") = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `naked_functions` - --> $DIR/feature-gate-naked_functions.rs:17:5 + --> $DIR/feature-gate-naked_functions.rs:16:5 | LL | naked_asm!("") | ^^^^^^^^^ @@ -18,6 +18,28 @@ LL | naked_asm!("") = help: add `#![feature(naked_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: unsafe attribute used without unsafe + --> $DIR/feature-gate-naked_functions.rs:6:3 + | +LL | #[naked] + | ^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(naked)] + | +++++++ + + +error: unsafe attribute used without unsafe + --> $DIR/feature-gate-naked_functions.rs:13:3 + | +LL | #[naked] + | ^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(naked)] + | +++++++ + + error[E0658]: the `#[naked]` attribute is an experimental feature --> $DIR/feature-gate-naked_functions.rs:6:1 | @@ -29,7 +51,7 @@ LL | #[naked] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:14:1 + --> $DIR/feature-gate-naked_functions.rs:13:1 | LL | #[naked] | ^^^^^^^^ @@ -48,23 +70,6 @@ LL | use std::arch::naked_asm; = help: add `#![feature(naked_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:9:5 - | -LL | naked_asm!("") - | ^^^^^^^^^^^^^^ use of inline assembly - | - = note: inline assembly is entirely unchecked and can cause undefined behavior - -error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:17:5 - | -LL | naked_asm!("") - | ^^^^^^^^^^^^^^ use of inline assembly - | - = note: inline assembly is entirely unchecked and can cause undefined behavior - error: aborting due to 7 previous errors -Some errors have detailed explanations: E0133, E0658. -For more information about an error, try `rustc --explain E0133`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs index c91d83399441..cc5b4f0e88b4 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs @@ -5,19 +5,19 @@ use std::arch::naked_asm; -#[naked] +#[unsafe(naked)] pub unsafe fn rust_implicit() { //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions naked_asm!("ret"); } -#[naked] +#[unsafe(naked)] pub unsafe extern "Rust" fn rust_explicit() { //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions naked_asm!("ret"); } -#[naked] +#[unsafe(naked)] pub unsafe extern "rust-cold" fn rust_cold() { //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions naked_asm!("ret"); diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs index 0d3af4c5fe0a..b2e102f1db4b 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs @@ -5,7 +5,7 @@ use std::arch::naked_asm; -#[naked] +#[unsafe(naked)] #[target_feature(enable = "avx2")] //~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions extern "C" fn naked() { diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs index 0e85515fd104..ce6d10bf33cb 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -5,7 +5,7 @@ use std::arch::naked_asm; #[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI -#[naked] +#[unsafe(naked)] extern "C" fn f() { unsafe { naked_asm!(""); @@ -17,7 +17,7 @@ struct S; impl S { #[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI - #[naked] + #[unsafe(naked)] extern "C" fn g() { unsafe { naked_asm!(""); diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index 0625ed1183ba..f89d94b67d80 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,20 +1,20 @@ -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/error-with-naked.rs:6:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` LL | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here -error[E0736]: attribute incompatible with `#[naked]` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/error-with-naked.rs:18:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` LL | -LL | #[naked] - | -------- function marked with `#[naked]` here +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here error[E0737]: `#[track_caller]` requires Rust ABI --> $DIR/error-with-naked.rs:6:1 From e0d9244472b50631f07af8a425c1dbed65161d25 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 15 Apr 2025 05:29:38 -0700 Subject: [PATCH 063/109] Sort Unix env constants alphabetically by target_os They were roughly grouped into Linux, Apple, BSD, and everything else, roughly in alphabetical order. Alphabetically order them to make it easier to maintain and discard the Unix-specific groups to generalize it to all platforms. --- library/std/src/sys/pal/unix/env.rs | 292 ++++++++++++++-------------- 1 file changed, 147 insertions(+), 145 deletions(-) diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs index c6609298f4b2..1a5e23f06b80 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/pal/unix/env.rs @@ -1,106 +1,20 @@ -#[cfg(target_os = "linux")] +// Keep entries sorted alphabetically. + +#[cfg(target_os = "aix")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "linux"; + pub const OS: &str = "aix"; pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; + pub const DLL_SUFFIX: &str = ".a"; + pub const DLL_EXTENSION: &str = "a"; pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "macos")] +#[cfg(target_os = "android")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "macos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "ios")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "ios"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "tvos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "tvos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "watchos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "watchos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "visionos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "visionos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "freebsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "freebsd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "dragonfly")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "dragonfly"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "netbsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "netbsd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "openbsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "openbsd"; + pub const OS: &str = "android"; pub const DLL_PREFIX: &str = "lib"; pub const DLL_SUFFIX: &str = ".so"; pub const DLL_EXTENSION: &str = "so"; @@ -119,10 +33,10 @@ pub mod os { pub const EXE_EXTENSION: &str = "exe"; } -#[cfg(target_os = "android")] +#[cfg(target_os = "dragonfly")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "android"; + pub const OS: &str = "dragonfly"; pub const DLL_PREFIX: &str = "lib"; pub const DLL_SUFFIX: &str = ".so"; pub const DLL_EXTENSION: &str = "so"; @@ -130,10 +44,21 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "solaris")] +#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "solaris"; + pub const OS: &str = "emscripten"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ".js"; + pub const EXE_EXTENSION: &str = "js"; +} + +#[cfg(target_os = "espidf")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "espidf"; pub const DLL_PREFIX: &str = "lib"; pub const DLL_SUFFIX: &str = ".so"; pub const DLL_EXTENSION: &str = "so"; @@ -141,10 +66,21 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "illumos")] +#[cfg(target_os = "freebsd")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "illumos"; + pub const OS: &str = "freebsd"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "fuchsia")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "fuchsia"; pub const DLL_PREFIX: &str = "lib"; pub const DLL_SUFFIX: &str = ".so"; pub const DLL_EXTENSION: &str = "so"; @@ -185,35 +121,24 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "vita")] +#[cfg(target_os = "illumos")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "vita"; + pub const OS: &str = "illumos"; pub const DLL_PREFIX: &str = "lib"; pub const DLL_SUFFIX: &str = ".so"; pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ".elf"; - pub const EXE_EXTENSION: &str = "elf"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; } -#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] +#[cfg(target_os = "ios")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "emscripten"; + pub const OS: &str = "ios"; pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ".js"; - pub const EXE_EXTENSION: &str = "js"; -} - -#[cfg(target_os = "fuchsia")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "fuchsia"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } @@ -229,6 +154,39 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "linux")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "linux"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "macos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "macos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "netbsd")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "netbsd"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "nto")] pub mod os { pub const FAMILY: &str = "unix"; @@ -240,6 +198,28 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "nuttx")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "nuttx"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "openbsd")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "openbsd"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "redox")] pub mod os { pub const FAMILY: &str = "unix"; @@ -262,6 +242,50 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "solaris")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "solaris"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "tvos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "tvos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "visionos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "visionos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +#[cfg(target_os = "vita")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "vita"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ".elf"; + pub const EXE_EXTENSION: &str = "elf"; +} + #[cfg(target_os = "vxworks")] pub mod os { pub const FAMILY: &str = "unix"; @@ -273,35 +297,13 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "espidf")] +#[cfg(target_os = "watchos")] pub mod os { pub const FAMILY: &str = "unix"; - pub const OS: &str = "espidf"; + pub const OS: &str = "watchos"; pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "aix")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "aix"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".a"; - pub const DLL_EXTENSION: &str = "a"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "nuttx")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "nuttx"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } From 37712cc01604633fec6aac9bc720210207fa4b54 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 15 Apr 2025 05:48:27 -0700 Subject: [PATCH 064/109] Combine env consts into std::sys::env_consts --- library/std/src/env.rs | 2 +- .../sys/{pal/unix/env.rs => env_consts.rs} | 70 ++++++++++++++++++- library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/hermit/env.rs | 9 --- library/std/src/sys/pal/hermit/mod.rs | 1 - library/std/src/sys/pal/sgx/env.rs | 9 --- library/std/src/sys/pal/sgx/mod.rs | 1 - library/std/src/sys/pal/solid/env.rs | 9 --- library/std/src/sys/pal/solid/mod.rs | 1 - library/std/src/sys/pal/teeos/mod.rs | 3 - library/std/src/sys/pal/trusty/mod.rs | 2 - library/std/src/sys/pal/uefi/env.rs | 9 --- library/std/src/sys/pal/uefi/mod.rs | 1 - library/std/src/sys/pal/unix/mod.rs | 1 - library/std/src/sys/pal/unsupported/env.rs | 9 --- library/std/src/sys/pal/unsupported/mod.rs | 1 - library/std/src/sys/pal/wasi/env.rs | 11 --- library/std/src/sys/pal/wasi/mod.rs | 1 - library/std/src/sys/pal/wasip2/mod.rs | 2 - library/std/src/sys/pal/wasm/env.rs | 9 --- library/std/src/sys/pal/wasm/mod.rs | 1 - library/std/src/sys/pal/windows/env.rs | 9 --- library/std/src/sys/pal/windows/mod.rs | 1 - library/std/src/sys/pal/xous/mod.rs | 2 - library/std/src/sys/pal/zkvm/mod.rs | 1 - 25 files changed, 71 insertions(+), 95 deletions(-) rename library/std/src/sys/{pal/unix/env.rs => env_consts.rs} (81%) delete mode 100644 library/std/src/sys/pal/hermit/env.rs delete mode 100644 library/std/src/sys/pal/sgx/env.rs delete mode 100644 library/std/src/sys/pal/solid/env.rs delete mode 100644 library/std/src/sys/pal/uefi/env.rs delete mode 100644 library/std/src/sys/pal/unsupported/env.rs delete mode 100644 library/std/src/sys/pal/wasi/env.rs delete mode 100644 library/std/src/sys/pal/wasm/env.rs delete mode 100644 library/std/src/sys/pal/windows/env.rs diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 05bd4345ea8d..c84a72c4fad0 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -950,7 +950,7 @@ impl fmt::Debug for ArgsOs { /// Constants associated with the current target #[stable(feature = "env", since = "1.0.0")] pub mod consts { - use crate::sys::env::os; + use crate::sys::env_consts::os; /// A string describing the architecture of the CPU that is currently in use. /// An example value may be: `"x86"`, `"arm"` or `"riscv64"`. diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/env_consts.rs similarity index 81% rename from library/std/src/sys/pal/unix/env.rs rename to library/std/src/sys/env_consts.rs index 1a5e23f06b80..f439aa5a905c 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/env_consts.rs @@ -1,3 +1,5 @@ +//! Constants associated with each target. + // Keep entries sorted alphabetically. #[cfg(target_os = "aix")] @@ -44,7 +46,7 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] +#[cfg(target_os = "emscripten")] pub mod os { pub const FAMILY: &str = "unix"; pub const OS: &str = "emscripten"; @@ -99,6 +101,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "hermit")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "hermit"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "horizon")] pub mod os { pub const FAMILY: &str = "unix"; @@ -242,6 +255,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".sgxs"; + pub const DLL_EXTENSION: &str = "sgxs"; + pub const EXE_SUFFIX: &str = ".sgxs"; + pub const EXE_EXTENSION: &str = "sgxs"; +} + #[cfg(target_os = "solaris")] pub mod os { pub const FAMILY: &str = "unix"; @@ -253,6 +277,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "solid_asp3")] +pub mod os { + pub const FAMILY: &str = "itron"; + pub const OS: &str = "solid"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "tvos")] pub mod os { pub const FAMILY: &str = "unix"; @@ -264,6 +299,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "uefi")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "uefi"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ".efi"; + pub const EXE_EXTENSION: &str = "efi"; +} + #[cfg(target_os = "visionos")] pub mod os { pub const FAMILY: &str = "unix"; @@ -297,6 +343,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "linux"))))] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".wasm"; + pub const DLL_EXTENSION: &str = "wasm"; + pub const EXE_SUFFIX: &str = ".wasm"; + pub const EXE_EXTENSION: &str = "wasm"; +} + #[cfg(target_os = "watchos")] pub mod os { pub const FAMILY: &str = "unix"; @@ -307,3 +364,14 @@ pub mod os { pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } + +#[cfg(target_os = "windows")] +pub mod os { + pub const FAMILY: &str = "windows"; + pub const OS: &str = "windows"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".dll"; + pub const DLL_EXTENSION: &str = "dll"; + pub const EXE_SUFFIX: &str = ".exe"; + pub const EXE_EXTENSION: &str = "exe"; +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index bc4bf11cb740..e7b631999e0d 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -12,6 +12,7 @@ pub mod anonymous_pipe; pub mod args; pub mod backtrace; pub mod cmath; +pub mod env_consts; pub mod exit_guard; pub mod fd; pub mod fs; diff --git a/library/std/src/sys/pal/hermit/env.rs b/library/std/src/sys/pal/hermit/env.rs deleted file mode 100644 index 7a0fcb31ef2e..000000000000 --- a/library/std/src/sys/pal/hermit/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = "hermit"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 821836824e2b..70636760a83b 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -18,7 +18,6 @@ use crate::os::raw::c_char; -pub mod env; pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/sgx/env.rs b/library/std/src/sys/pal/sgx/env.rs deleted file mode 100644 index 8043b7c5213a..000000000000 --- a/library/std/src/sys/pal/sgx/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".sgxs"; - pub const DLL_EXTENSION: &str = "sgxs"; - pub const EXE_SUFFIX: &str = ".sgxs"; - pub const EXE_EXTENSION: &str = "sgxs"; -} diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 8a87e7a7ae13..99735947e2cd 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -9,7 +9,6 @@ use crate::io::ErrorKind; use crate::sync::atomic::{AtomicBool, Ordering}; pub mod abi; -pub mod env; mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/solid/env.rs b/library/std/src/sys/pal/solid/env.rs deleted file mode 100644 index 6855c113b289..000000000000 --- a/library/std/src/sys/pal/solid/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = "itron"; - pub const OS: &str = "solid"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index c41dc848a1b4..0011cf256df7 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -16,7 +16,6 @@ pub mod itron { use super::unsupported; } -pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` pub(crate) mod error; diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index b8095cec3e97..c7b177772585 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -6,9 +6,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -#[path = "../unsupported/env.rs"] -pub mod env; -//pub mod fd; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 04e6b4c81868..275f60624633 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -3,8 +3,6 @@ #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] mod common; -#[path = "../unsupported/env.rs"] -pub mod env; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/uefi/env.rs b/library/std/src/sys/pal/uefi/env.rs deleted file mode 100644 index c106d5fed3e1..000000000000 --- a/library/std/src/sys/pal/uefi/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = "uefi"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ".efi"; - pub const EXE_EXTENSION: &str = "efi"; -} diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index cd901f48b76f..bd6a36021f4c 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -13,7 +13,6 @@ //! [`OsString`]: crate::ffi::OsString #![forbid(unsafe_op_in_unsafe_fn)] -pub mod env; pub mod helpers; pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 3a790d9c868c..a4702ae1b18d 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -6,7 +6,6 @@ use crate::io::ErrorKind; #[macro_use] pub mod weak; -pub mod env; #[cfg(target_os = "fuchsia")] pub mod fuchsia; pub mod futex; diff --git a/library/std/src/sys/pal/unsupported/env.rs b/library/std/src/sys/pal/unsupported/env.rs deleted file mode 100644 index d2efec506c56..000000000000 --- a/library/std/src/sys/pal/unsupported/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index dea42a95dcc6..5e3295b1331a 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,6 +1,5 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod env; pub mod os; pub mod pipe; pub mod thread; diff --git a/library/std/src/sys/pal/wasi/env.rs b/library/std/src/sys/pal/wasi/env.rs deleted file mode 100644 index 8d4449826736..000000000000 --- a/library/std/src/sys/pal/wasi/env.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".wasm"; - pub const DLL_EXTENSION: &str = "wasm"; - pub const EXE_SUFFIX: &str = ".wasm"; - pub const EXE_EXTENSION: &str = "wasm"; -} diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 4ea42b1082b1..61dd1c3f98b1 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -13,7 +13,6 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -pub mod env; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 6445bf2cc0d2..47fe3221c909 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -6,8 +6,6 @@ //! To begin with, this target mirrors the wasi target 1 to 1, but over //! time this will change significantly. -#[path = "../wasi/env.rs"] -pub mod env; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; diff --git a/library/std/src/sys/pal/wasm/env.rs b/library/std/src/sys/pal/wasm/env.rs deleted file mode 100644 index 730e356d7fe9..000000000000 --- a/library/std/src/sys/pal/wasm/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".wasm"; - pub const DLL_EXTENSION: &str = "wasm"; - pub const EXE_SUFFIX: &str = ".wasm"; - pub const EXE_EXTENSION: &str = "wasm"; -} diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index af370020d96a..37cb46a8f6b3 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -16,7 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -pub mod env; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] diff --git a/library/std/src/sys/pal/windows/env.rs b/library/std/src/sys/pal/windows/env.rs deleted file mode 100644 index f0a99d6200ca..000000000000 --- a/library/std/src/sys/pal/windows/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = "windows"; - pub const OS: &str = "windows"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".dll"; - pub const DLL_EXTENSION: &str = "dll"; - pub const EXE_SUFFIX: &str = ".exe"; - pub const EXE_EXTENSION: &str = "exe"; -} diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3c0a5c2de263..4f18c4009ab6 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -15,7 +15,6 @@ pub mod compat; pub mod api; pub mod c; -pub mod env; #[cfg(not(target_vendor = "win7"))] pub mod futex; pub mod handle; diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 4f652d3f130d..383d031ed435 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,7 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/env.rs"] -pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index ebd7b0367798..e1efa2406858 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -11,7 +11,6 @@ pub const WORD_SIZE: usize = size_of::(); pub mod abi; -pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; From 670ff84d1c70146a2556b41650d3e417143c6c60 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 15 Apr 2025 06:42:39 -0700 Subject: [PATCH 065/109] Handle unsupported fallback --- library/std/src/sys/env_consts.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs index f439aa5a905c..018d7954db26 100644 --- a/library/std/src/sys/env_consts.rs +++ b/library/std/src/sys/env_consts.rs @@ -1,6 +1,19 @@ //! Constants associated with each target. -// Keep entries sorted alphabetically. +// Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates. +// This ensures that they must be mutually exclusive and do not have precedence +// like cfg_if!. +macro cfg_unordered( + $(#[cfg($cfg:meta)] $os:item)* + #[else] $fallback:item +) { + $(#[cfg($cfg)] $os)* + #[cfg(not(any($($cfg),*)))] $fallback +} + +// Keep entries sorted alphabetically and mutually exclusive. + +cfg_unordered! { #[cfg(target_os = "aix")] pub mod os { @@ -375,3 +388,17 @@ pub mod os { pub const EXE_SUFFIX: &str = ".exe"; pub const EXE_EXTENSION: &str = "exe"; } + +// The fallback when none of the other gates match. +#[else] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + +} From 93fa96cfba126d542ebd33624e5f774d397dbf3f Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 18 Apr 2025 16:45:26 -0700 Subject: [PATCH 066/109] Use struct update syntax for some TargetOptions --- compiler/rustc_target/src/spec/base/linux_musl.rs | 15 +++++++-------- compiler/rustc_target/src/spec/base/linux_ohos.rs | 15 +++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/linux_musl.rs b/compiler/rustc_target/src/spec/base/linux_musl.rs index 1a854fe362d5..1bef602404e5 100644 --- a/compiler/rustc_target/src/spec/base/linux_musl.rs +++ b/compiler/rustc_target/src/spec/base/linux_musl.rs @@ -1,12 +1,11 @@ use crate::spec::{LinkSelfContainedDefault, TargetOptions, base, crt_objects}; pub(crate) fn opts() -> TargetOptions { - let mut base = base::linux::opts(); - - base.env = "musl".into(); - base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained(); - base.post_link_objects_self_contained = crt_objects::post_musl_self_contained(); - base.link_self_contained = LinkSelfContainedDefault::InferredForMusl; - - base + TargetOptions { + env: "musl".into(), + pre_link_objects_self_contained: crt_objects::pre_musl_self_contained(), + post_link_objects_self_contained: crt_objects::post_musl_self_contained(), + link_self_contained: LinkSelfContainedDefault::InferredForMusl, + ..base::linux::opts() + } } diff --git a/compiler/rustc_target/src/spec/base/linux_ohos.rs b/compiler/rustc_target/src/spec/base/linux_ohos.rs index 6f4d69a996c3..1b7f1e196664 100644 --- a/compiler/rustc_target/src/spec/base/linux_ohos.rs +++ b/compiler/rustc_target/src/spec/base/linux_ohos.rs @@ -1,12 +1,11 @@ use crate::spec::{TargetOptions, TlsModel, base}; pub(crate) fn opts() -> TargetOptions { - let mut base = base::linux::opts(); - - base.env = "ohos".into(); - base.crt_static_default = false; - base.tls_model = TlsModel::Emulated; - base.has_thread_local = false; - - base + TargetOptions { + env: "ohos".into(), + crt_static_default: false, + tls_model: TlsModel::Emulated, + has_thread_local: false, + ..base::linux::opts() + } } From 3eaa4b93684f10765ce9b8004fac461008ae678a Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 15 Apr 2025 21:06:27 -0600 Subject: [PATCH 067/109] Cleaned up 4 tests in `tests/ui/issues` --- src/tools/tidy/src/issues.txt | 5 -- src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/argument-suggestions/exotic-calls.rs | 10 +++ .../argument-suggestions/exotic-calls.stderr | 35 ++++++++--- .../ref-dyn-trait-in-structs-and-enums.rs | 54 ++++++++++++++++ tests/ui/issues/auxiliary/issue-14421.rs | 25 -------- tests/ui/issues/issue-14421.rs | 15 ----- tests/ui/issues/issue-16939.rs | 8 --- tests/ui/issues/issue-16939.stderr | 20 ------ tests/ui/issues/issue-23808.rs | 59 ------------------ tests/ui/issues/issue-9719.rs | 40 ------------ ...ead-code-reexported-types-across-crates.rs | 33 ++++++++++ .../no-dead-code-for-static-trait-impl.rs | 61 +++++++++++++++++++ ...ead-code-reexported-types-across-crates.rs | 17 ++++++ 14 files changed, 202 insertions(+), 182 deletions(-) create mode 100644 tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs delete mode 100644 tests/ui/issues/auxiliary/issue-14421.rs delete mode 100644 tests/ui/issues/issue-14421.rs delete mode 100644 tests/ui/issues/issue-16939.rs delete mode 100644 tests/ui/issues/issue-16939.stderr delete mode 100644 tests/ui/issues/issue-23808.rs delete mode 100644 tests/ui/issues/issue-9719.rs create mode 100644 tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs create mode 100644 tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs create mode 100644 tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index d2ae9b1f6ef8..1df95e915940 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1397,7 +1397,6 @@ ui/issues/auxiliary/issue-13620-1.rs ui/issues/auxiliary/issue-13620-2.rs ui/issues/auxiliary/issue-14344-1.rs ui/issues/auxiliary/issue-14344-2.rs -ui/issues/auxiliary/issue-14421.rs ui/issues/auxiliary/issue-14422.rs ui/issues/auxiliary/issue-15562.rs ui/issues/auxiliary/issue-16643.rs @@ -1564,7 +1563,6 @@ ui/issues/issue-14366.rs ui/issues/issue-14382.rs ui/issues/issue-14393.rs ui/issues/issue-14399.rs -ui/issues/issue-14421.rs ui/issues/issue-14422.rs ui/issues/issue-14541.rs ui/issues/issue-14721.rs @@ -1629,7 +1627,6 @@ ui/issues/issue-16774.rs ui/issues/issue-16783.rs ui/issues/issue-16819.rs ui/issues/issue-16922-rpass.rs -ui/issues/issue-16939.rs ui/issues/issue-16966.rs ui/issues/issue-16994.rs ui/issues/issue-17001.rs @@ -1867,7 +1864,6 @@ ui/issues/issue-23550.rs ui/issues/issue-23589.rs ui/issues/issue-23699.rs ui/issues/issue-2380-b.rs -ui/issues/issue-23808.rs ui/issues/issue-2383.rs ui/issues/issue-23891.rs ui/issues/issue-23898.rs @@ -2607,7 +2603,6 @@ ui/issues/issue-9249.rs ui/issues/issue-9259.rs ui/issues/issue-92741.rs ui/issues/issue-9446.rs -ui/issues/issue-9719.rs ui/issues/issue-9725.rs ui/issues/issue-9737.rs ui/issues/issue-9814.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 61728d0553fd..2e069af23d65 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1631; +const ISSUES_ENTRY_LIMIT: u32 = 1626; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/argument-suggestions/exotic-calls.rs b/tests/ui/argument-suggestions/exotic-calls.rs index 569a39a2b450..765b4bc536c3 100644 --- a/tests/ui/argument-suggestions/exotic-calls.rs +++ b/tests/ui/argument-suggestions/exotic-calls.rs @@ -1,8 +1,18 @@ +//! Checks variations of E0057, which is the incorrect number of agruments passed into a closure + +//@ check-fail + fn foo(t: T) { t(1i32); //~^ ERROR function takes 0 arguments but 1 argument was supplied } +/// Regression test for +fn foo2(f: T) { + |t| f(t); + //~^ ERROR function takes 0 arguments but 1 argument was supplied +} + fn bar(t: impl Fn()) { t(1i32); //~^ ERROR function takes 0 arguments but 1 argument was supplied diff --git a/tests/ui/argument-suggestions/exotic-calls.stderr b/tests/ui/argument-suggestions/exotic-calls.stderr index aca3b8a34334..e78871c19cb9 100644 --- a/tests/ui/argument-suggestions/exotic-calls.stderr +++ b/tests/ui/argument-suggestions/exotic-calls.stderr @@ -1,11 +1,11 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/exotic-calls.rs:2:5 + --> $DIR/exotic-calls.rs:6:5 | LL | t(1i32); | ^ ---- unexpected argument of type `i32` | note: callable defined here - --> $DIR/exotic-calls.rs:1:11 + --> $DIR/exotic-calls.rs:5:11 | LL | fn foo(t: T) { | ^^^^ @@ -16,13 +16,30 @@ LL + t(); | error[E0057]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/exotic-calls.rs:7:5 + --> $DIR/exotic-calls.rs:12:9 + | +LL | |t| f(t); + | ^ - unexpected argument + | +note: callable defined here + --> $DIR/exotic-calls.rs:11:12 + | +LL | fn foo2(f: T) { + | ^^^^ +help: remove the extra argument + | +LL - |t| f(t); +LL + |t| f(); + | + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:17:5 | LL | t(1i32); | ^ ---- unexpected argument of type `i32` | note: type parameter defined here - --> $DIR/exotic-calls.rs:6:11 + --> $DIR/exotic-calls.rs:16:11 | LL | fn bar(t: impl Fn()) { | ^^^^^^^^^ @@ -33,13 +50,13 @@ LL + t(); | error[E0057]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/exotic-calls.rs:16:5 + --> $DIR/exotic-calls.rs:26:5 | LL | baz()(1i32) | ^^^^^ ---- unexpected argument of type `i32` | note: opaque type defined here - --> $DIR/exotic-calls.rs:11:13 + --> $DIR/exotic-calls.rs:21:13 | LL | fn baz() -> impl Fn() { | ^^^^^^^^^ @@ -50,13 +67,13 @@ LL + baz()() | error[E0057]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/exotic-calls.rs:22:5 + --> $DIR/exotic-calls.rs:32:5 | LL | x(1i32); | ^ ---- unexpected argument of type `i32` | note: closure defined here - --> $DIR/exotic-calls.rs:21:13 + --> $DIR/exotic-calls.rs:31:13 | LL | let x = || {}; | ^^ @@ -66,6 +83,6 @@ LL - x(1i32); LL + x(); | -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0057`. diff --git a/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs b/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs new file mode 100644 index 000000000000..04548817773e --- /dev/null +++ b/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs @@ -0,0 +1,54 @@ +//! Regression test for an LLVM assertion that used to be hit when: +//! +//! - There's a generic enum contained within a tuple struct +//! - When the tuple struct is parameterized by some lifetime `'a` +//! - The enum is concretized with its type argument being a reference to a trait object (of +//! lifetime `'a`) +//! +//! Issue: + +//@ build-pass + +// Dummy trait implemented for `isize` to use in the test cases +pub trait MyTrait { + fn dummy(&self) {} +} +impl MyTrait for isize {} + +// `&dyn MyTrait` contained in enum variant +pub struct EnumRefDynTrait<'a>(Enum<&'a (dyn MyTrait + 'a)>); +pub enum Enum { + Variant(T), +} + +fn enum_dyn_trait() { + let x: isize = 42; + let y = EnumRefDynTrait(Enum::Variant(&x as &dyn MyTrait)); + let _ = y; +} + +// `&dyn MyTrait` contained behind `Option` in named field of struct +struct RefDynTraitNamed<'a> { + x: Option<&'a (dyn MyTrait + 'a)>, +} + +fn named_option_dyn_trait() { + let x: isize = 42; + let y = RefDynTraitNamed { x: Some(&x as &dyn MyTrait) }; + let _ = y; +} + +// `&dyn MyTrait` contained behind `Option` in unnamed field of struct +pub struct RefDynTraitUnnamed<'a>(Option<&'a (dyn MyTrait + 'a)>); + +fn unnamed_option_dyn_trait() { + let x: isize = 42; + let y = RefDynTraitUnnamed(Some(&x as &dyn MyTrait)); + let _ = y; +} + +pub fn main() { + enum_dyn_trait(); + named_option_dyn_trait(); + unnamed_option_dyn_trait(); +} diff --git a/tests/ui/issues/auxiliary/issue-14421.rs b/tests/ui/issues/auxiliary/issue-14421.rs deleted file mode 100644 index 5fe4b24cf170..000000000000 --- a/tests/ui/issues/auxiliary/issue-14421.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![crate_type="lib"] -#![deny(warnings)] -#![allow(dead_code)] - -pub use src::aliases::B; -pub use src::hidden_core::make; - -mod src { - pub mod aliases { - use super::hidden_core::A; - pub type B = A; - } - - pub mod hidden_core { - use super::aliases::B; - - pub struct A { t: T } - - pub fn make() -> B { A { t: 1.0 } } - - impl A { - pub fn foo(&mut self) { println!("called foo"); } - } - } -} diff --git a/tests/ui/issues/issue-14421.rs b/tests/ui/issues/issue-14421.rs deleted file mode 100644 index b7038584fcea..000000000000 --- a/tests/ui/issues/issue-14421.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -#![allow(non_snake_case)] - -//@ aux-build:issue-14421.rs - - -extern crate issue_14421 as bug_lib; - -use bug_lib::B; -use bug_lib::make; - -pub fn main() { - let mut an_A: B = make(); - an_A.foo(); -} diff --git a/tests/ui/issues/issue-16939.rs b/tests/ui/issues/issue-16939.rs deleted file mode 100644 index ad7248343918..000000000000 --- a/tests/ui/issues/issue-16939.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Make sure we don't ICE when making an overloaded call with the -// wrong arity. - -fn _foo (f: F) { - |t| f(t); //~ ERROR E0057 -} - -fn main() {} diff --git a/tests/ui/issues/issue-16939.stderr b/tests/ui/issues/issue-16939.stderr deleted file mode 100644 index 6e0889b89635..000000000000 --- a/tests/ui/issues/issue-16939.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0057]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/issue-16939.rs:5:9 - | -LL | |t| f(t); - | ^ - unexpected argument - | -note: callable defined here - --> $DIR/issue-16939.rs:4:12 - | -LL | fn _foo (f: F) { - | ^^^^ -help: remove the extra argument - | -LL - |t| f(t); -LL + |t| f(); - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0057`. diff --git a/tests/ui/issues/issue-23808.rs b/tests/ui/issues/issue-23808.rs deleted file mode 100644 index 6af0bd422e3a..000000000000 --- a/tests/ui/issues/issue-23808.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ run-pass - -#![deny(dead_code)] - -// use different types / traits to test all combinations - -trait Const { - const C: (); -} - -trait StaticFn { - fn sfn(); -} - -struct ConstStruct; -struct StaticFnStruct; - -enum ConstEnum {} -enum StaticFnEnum {} - -struct AliasedConstStruct; -struct AliasedStaticFnStruct; - -enum AliasedConstEnum {} -enum AliasedStaticFnEnum {} - -type AliasConstStruct = AliasedConstStruct; -type AliasStaticFnStruct = AliasedStaticFnStruct; -type AliasConstEnum = AliasedConstEnum; -type AliasStaticFnEnum = AliasedStaticFnEnum; - -macro_rules! impl_Const {($($T:ident),*) => {$( - impl Const for $T { - const C: () = (); - } -)*}} - -macro_rules! impl_StaticFn {($($T:ident),*) => {$( - impl StaticFn for $T { - fn sfn() {} - } -)*}} - -impl_Const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum); -impl_StaticFn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum); - -fn main() { - let () = ConstStruct::C; - let () = ConstEnum::C; - - StaticFnStruct::sfn(); - StaticFnEnum::sfn(); - - let () = AliasConstStruct::C; - let () = AliasConstEnum::C; - - AliasStaticFnStruct::sfn(); - AliasStaticFnEnum::sfn(); -} diff --git a/tests/ui/issues/issue-9719.rs b/tests/ui/issues/issue-9719.rs deleted file mode 100644 index 904768c93414..000000000000 --- a/tests/ui/issues/issue-9719.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ build-pass -#![allow(dead_code)] - -mod a { - pub enum Enum { - A(T), - } - - pub trait X { - fn dummy(&self) { } - } - impl X for isize {} - - pub struct Z<'a>(Enum<&'a (dyn X + 'a)>); - fn foo() { let x: isize = 42; let z = Z(Enum::A(&x as &dyn X)); let _ = z; } -} - -mod b { - trait X { - fn dummy(&self) { } - } - impl X for isize {} - struct Y<'a>{ - x:Option<&'a (dyn X + 'a)>, - } - - fn bar() { - let x: isize = 42; - let _y = Y { x: Some(&x as &dyn X) }; - } -} - -mod c { - pub trait X { fn f(&self); } - impl X for isize { fn f(&self) {} } - pub struct Z<'a>(Option<&'a (dyn X + 'a)>); - fn main() { let x: isize = 42; let z = Z(Some(&x as &dyn X)); let _ = z; } -} - -pub fn main() {} diff --git a/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs b/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs new file mode 100644 index 000000000000..5f328d1abf6a --- /dev/null +++ b/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs @@ -0,0 +1,33 @@ +//! Auxilary file for testing `dead_code` lint. This crate is compiled as a library and exposes +//! aliased types. When used externally, there should not be warnings of `dead_code` +//! +//! Issue: + +// Expose internal types to be used in external test +pub use src::aliases::ExposedType; +pub use src::hidden_core::new; + +mod src { + pub mod aliases { + use super::hidden_core::InternalStruct; + pub type ExposedType = InternalStruct; + } + + pub mod hidden_core { + use super::aliases::ExposedType; + + pub struct InternalStruct { + _x: T, + } + + pub fn new() -> ExposedType { + InternalStruct { _x: 1.0 } + } + + impl InternalStruct { + pub fn foo(&mut self) { + println!("called foo"); + } + } + } +} diff --git a/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs b/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs new file mode 100644 index 000000000000..8d54eda6bcaa --- /dev/null +++ b/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs @@ -0,0 +1,61 @@ +//! Regression test to ensure false positive `dead_code` diagnostic warnings are not triggered for +//! structs and enums that implement static trait functions or use associated constants. +//! +//! Aliased versions of all cases are also tested +//! +//! Issue: + +//@ check-pass +#![deny(dead_code)] + +trait Const { + const C: (); +} + +trait StaticFn { + fn sfn(); +} + +macro_rules! impl_const {($($T:ident),*) => {$( + impl Const for $T { + const C: () = (); + } +)*}} + +macro_rules! impl_static_fn {($($T:ident),*) => {$( + impl StaticFn for $T { + fn sfn() {} + } +)*}} + +struct ConstStruct; +enum ConstEnum {} +struct AliasedConstStruct; +type AliasConstStruct = AliasedConstStruct; +enum AliasedConstEnum {} +type AliasConstEnum = AliasedConstEnum; + +impl_const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum); + +struct StaticFnStruct; +enum StaticFnEnum {} +struct AliasedStaticFnStruct; +type AliasStaticFnStruct = AliasedStaticFnStruct; +enum AliasedStaticFnEnum {} +type AliasStaticFnEnum = AliasedStaticFnEnum; + +impl_static_fn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum); + +fn main() { + // Use the associated constant for all the types, they should be considered "used" + let () = ConstStruct::C; + let () = ConstEnum::C; + let () = AliasConstStruct::C; + let () = AliasConstEnum::C; + + // Use the associated static function for all the types, they should be considered "used" + StaticFnStruct::sfn(); + StaticFnEnum::sfn(); + AliasStaticFnStruct::sfn(); + AliasStaticFnEnum::sfn(); +} diff --git a/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs b/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs new file mode 100644 index 000000000000..11082f772ff6 --- /dev/null +++ b/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs @@ -0,0 +1,17 @@ +//! Regression test to ensure that `dead_code` warning does not get triggered when using re-exported +//! types that are exposed from a different crate +//! +//! Issue: + +//@ check-pass +//@ aux-build:no-dead-code-reexported-types-across-crates.rs + +extern crate no_dead_code_reexported_types_across_crates as bug_lib; + +use bug_lib::ExposedType; +use bug_lib::new; + +pub fn main() { + let mut x: ExposedType = new(); + x.foo(); +} From b3739f3c0e86a217599f78d99920867f30afdd18 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sat, 19 Apr 2025 03:36:02 -0400 Subject: [PATCH 068/109] Only consider MonoItem::Fn when preventing inlining for autodiff source functions --- compiler/rustc_monomorphize/src/partitioning.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index b1b6f10e0fe2..d7690a96e10d 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -254,8 +254,9 @@ where always_export_generics, ); - // We can't differentiate something that got inlined. + // We can't differentiate a function that got inlined. let autodiff_active = cfg!(llvm_enzyme) + && matches!(mono_item, MonoItem::Fn(_)) && cx .tcx .codegen_fn_attrs(mono_item.def_id()) From a86df238d3f21ccb6ec25080bcc24b1f9153ea63 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 19 Apr 2025 16:46:06 +0800 Subject: [PATCH 069/109] tests: rework `amdgpu-require-explicit-cpu.rs` - Reworked the test as a *centralized* version of checking that certain targets correctly require `-C target-cpu` being specified. - Document test intention. - Move `amdgpu-require-explicit-cpu.rs` under new dir `tests/ui/target-cpu/` - No other ui subdir really fits this "requires `-Ctarget-cpu`" check. --- tests/ui/amdgpu-require-explicit-cpu.rs | 18 --------- .../explicit-target-cpu.amdgcn_nocpu.stderr} | 0 .../explicit-target-cpu.avr_nocpu.stderr | 4 ++ tests/ui/target-cpu/explicit-target-cpu.rs | 37 +++++++++++++++++++ 4 files changed, 41 insertions(+), 18 deletions(-) delete mode 100644 tests/ui/amdgpu-require-explicit-cpu.rs rename tests/ui/{amdgpu-require-explicit-cpu.nocpu.stderr => target-cpu/explicit-target-cpu.amdgcn_nocpu.stderr} (100%) create mode 100644 tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr create mode 100644 tests/ui/target-cpu/explicit-target-cpu.rs diff --git a/tests/ui/amdgpu-require-explicit-cpu.rs b/tests/ui/amdgpu-require-explicit-cpu.rs deleted file mode 100644 index d40cb97977d9..000000000000 --- a/tests/ui/amdgpu-require-explicit-cpu.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ revisions: nocpu cpu -//@ no-prefer-dynamic -//@ compile-flags: --crate-type=cdylib --target=amdgcn-amd-amdhsa -//@ needs-llvm-components: amdgpu -//@ needs-rust-lld -//@[nocpu] build-fail -//@[cpu] compile-flags: -Ctarget-cpu=gfx900 -//@[cpu] build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang="sized"] -trait Sized {} - -pub fn foo() {} - -//[nocpu]~? ERROR target requires explicitly specifying a cpu with `-C target-cpu` diff --git a/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr b/tests/ui/target-cpu/explicit-target-cpu.amdgcn_nocpu.stderr similarity index 100% rename from tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr rename to tests/ui/target-cpu/explicit-target-cpu.amdgcn_nocpu.stderr diff --git a/tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr b/tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr new file mode 100644 index 000000000000..7480a8ed38f1 --- /dev/null +++ b/tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr @@ -0,0 +1,4 @@ +error: target requires explicitly specifying a cpu with `-C target-cpu` + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-cpu/explicit-target-cpu.rs b/tests/ui/target-cpu/explicit-target-cpu.rs new file mode 100644 index 000000000000..cd4c2384bc1d --- /dev/null +++ b/tests/ui/target-cpu/explicit-target-cpu.rs @@ -0,0 +1,37 @@ +//! Check that certain target *requires* the user to specify a target CPU via `-C target-cpu`. + +//@ revisions: amdgcn_nocpu amdgcn_cpu + +//@[amdgcn_nocpu] compile-flags: --target=amdgcn-amd-amdhsa +//@[amdgcn_nocpu] needs-llvm-components: amdgpu +//@[amdgcn_nocpu] build-fail + +//@[amdgcn_cpu] compile-flags: --target=amdgcn-amd-amdhsa +//@[amdgcn_cpu] needs-llvm-components: amdgpu +//@[amdgcn_cpu] compile-flags: -Ctarget-cpu=gfx900 +//@[amdgcn_cpu] build-pass + +//@ revisions: avr_nocpu avr_cpu + +//@[avr_nocpu] compile-flags: --target=avr-none +//@[avr_nocpu] needs-llvm-components: avr +//@[avr_nocpu] build-fail + +//@[avr_cpu] compile-flags: --target=avr-none +//@[avr_cpu] needs-llvm-components: avr +//@[avr_cpu] compile-flags: -Ctarget-cpu=atmega328p +//@[avr_cpu] build-pass + +#![crate_type = "rlib"] + +// FIXME(#140038): this can't use `minicore` yet because `minicore` doesn't currently propagate the +// `-C target-cpu` for targets that *require* a `target-cpu` being specified. +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized {} + +pub fn foo() {} + +//[amdgcn_nocpu,avr_nocpu]~? ERROR target requires explicitly specifying a cpu with `-C target-cpu` From 40b73322b93bf1627a7cb58aec5a7fe019af1f66 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 19 Apr 2025 17:05:05 +0800 Subject: [PATCH 070/109] tests: adjust some `augmented-assignment*` tests - `tests/ui/augmented-assignment-feature-gate-cross.rs`: - This was *originally* to feature-gate overloaded OpAssign cross-crate, but now let's keep it as a smoke test. - Renamed as `augmented-assignment-cross-crate.rs`. - Relocated under `tests/ui/binop/`. - `tests/ui/augmented-assignments.rs`: - Documented test intent. - Moved under `tests/ui/borrowck/`. - `tests/ui/augmented-assignment-rpass.rs`: - Renamed to drop the `-rpass` suffix, since this was leftover from when `run-pass` test suite was a thing. - Moved under `tests/ui/binop/`. --- .../augmented-assignment.rs} | 0 .../augmented-assignments-cross-crate.rs} | 2 ++ tests/ui/{ => binop}/auxiliary/augmented_assignments.rs | 0 tests/ui/{ => borrowck}/augmented-assignments.rs | 3 +++ tests/ui/{ => borrowck}/augmented-assignments.stderr | 4 ++-- 5 files changed, 7 insertions(+), 2 deletions(-) rename tests/ui/{augmented-assignments-rpass.rs => binop/augmented-assignment.rs} (100%) rename tests/ui/{augmented-assignments-feature-gate-cross.rs => binop/augmented-assignments-cross-crate.rs} (72%) rename tests/ui/{ => binop}/auxiliary/augmented_assignments.rs (100%) rename tests/ui/{ => borrowck}/augmented-assignments.rs (83%) rename tests/ui/{ => borrowck}/augmented-assignments.stderr (88%) diff --git a/tests/ui/augmented-assignments-rpass.rs b/tests/ui/binop/augmented-assignment.rs similarity index 100% rename from tests/ui/augmented-assignments-rpass.rs rename to tests/ui/binop/augmented-assignment.rs diff --git a/tests/ui/augmented-assignments-feature-gate-cross.rs b/tests/ui/binop/augmented-assignments-cross-crate.rs similarity index 72% rename from tests/ui/augmented-assignments-feature-gate-cross.rs rename to tests/ui/binop/augmented-assignments-cross-crate.rs index d402d2006177..6dbb03509884 100644 --- a/tests/ui/augmented-assignments-feature-gate-cross.rs +++ b/tests/ui/binop/augmented-assignments-cross-crate.rs @@ -1,3 +1,5 @@ +//! Smoke test for overloaded compound assignments cross-crate. + //@ run-pass //@ aux-build:augmented_assignments.rs diff --git a/tests/ui/auxiliary/augmented_assignments.rs b/tests/ui/binop/auxiliary/augmented_assignments.rs similarity index 100% rename from tests/ui/auxiliary/augmented_assignments.rs rename to tests/ui/binop/auxiliary/augmented_assignments.rs diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/borrowck/augmented-assignments.rs similarity index 83% rename from tests/ui/augmented-assignments.rs rename to tests/ui/borrowck/augmented-assignments.rs index 35ab2d454f7b..d717dcc7935e 100644 --- a/tests/ui/augmented-assignments.rs +++ b/tests/ui/borrowck/augmented-assignments.rs @@ -1,3 +1,6 @@ +//! Check that overloaded compound assignment operators respect usual borrowck rules and emit +//! reasonable diagnostics. + use std::ops::AddAssign; #[derive(Clone)] diff --git a/tests/ui/augmented-assignments.stderr b/tests/ui/borrowck/augmented-assignments.stderr similarity index 88% rename from tests/ui/augmented-assignments.stderr rename to tests/ui/borrowck/augmented-assignments.stderr index a4b75cbf6e8f..4b945cd998a1 100644 --- a/tests/ui/augmented-assignments.stderr +++ b/tests/ui/borrowck/augmented-assignments.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/augmented-assignments.rs:17:5 + --> $DIR/augmented-assignments.rs:20:5 | LL | let mut x = Int(1); | ----- binding `x` declared here @@ -10,7 +10,7 @@ LL | x; | ^ move out of `x` occurs here error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/augmented-assignments.rs:24:5 + --> $DIR/augmented-assignments.rs:27:5 | LL | y | ^ cannot borrow as mutable From b47fe51610fbe0d8d983f3ace0682044a1a450c3 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 19 Apr 2025 17:29:31 +0800 Subject: [PATCH 071/109] tests: adjust `tests/ui/auto-instantiate.rs` - Reformat the test. - Document test intention. - Move test under `tests/ui/inference/`. --- tests/ui/auto-instantiate.rs | 13 ------------ tests/ui/inference/auto-instantiate.rs | 28 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 13 deletions(-) delete mode 100644 tests/ui/auto-instantiate.rs create mode 100644 tests/ui/inference/auto-instantiate.rs diff --git a/tests/ui/auto-instantiate.rs b/tests/ui/auto-instantiate.rs deleted file mode 100644 index 73ad5d701e18..000000000000 --- a/tests/ui/auto-instantiate.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -#[derive(Debug)] -struct Pair { a: T, b: U } -struct Triple { x: isize, y: isize, z: isize } - -fn f(x: T, y: U) -> Pair { return Pair {a: x, b: y}; } - -pub fn main() { - println!("{}", f(Triple {x: 3, y: 4, z: 5}, 4).a.x); - println!("{}", f(5, 6).a); -} diff --git a/tests/ui/inference/auto-instantiate.rs b/tests/ui/inference/auto-instantiate.rs new file mode 100644 index 000000000000..bf43330a0b77 --- /dev/null +++ b/tests/ui/inference/auto-instantiate.rs @@ -0,0 +1,28 @@ +//! Check that type parameters in generic function arg position and in "nested" return type position +//! can be inferred on an invocation of the generic function. +//! +//! See . + +//@ run-pass + +#![allow(dead_code)] +#[derive(Debug)] +struct Pair { + a: T, + b: U, +} + +struct Triple { + x: isize, + y: isize, + z: isize, +} + +fn f(x: T, y: U) -> Pair { + return Pair { a: x, b: y }; +} + +pub fn main() { + println!("{}", f(Triple {x: 3, y: 4, z: 5}, 4).a.x); + println!("{}", f(5, 6).a); +} From 311ef44dca17c04629f9436011abbd1eeeb75e65 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 19 Apr 2025 13:08:43 +0200 Subject: [PATCH 072/109] readme: be copy-paste friendly --- src/doc/rustc-dev-guide/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index 6a25a91f56a5..9f468b933d79 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -43,13 +43,13 @@ rustdocs][rustdocs]. To build a local static HTML site, install [`mdbook`](https://github.com/rust-lang/mdBook) with: ``` -> cargo install mdbook mdbook-linkcheck2 mdbook-toc mdbook-mermaid +cargo install mdbook mdbook-linkcheck2 mdbook-toc mdbook-mermaid ``` and execute the following command in the root of the repository: ``` -> mdbook build --open +mdbook build --open ``` The build files are found in the `book/html` directory. @@ -61,8 +61,8 @@ checking is **not** run by default locally, though it is in CI. To enable it locally, set the environment variable `ENABLE_LINKCHECK=1` like in the following example. -```console -$ ENABLE_LINKCHECK=1 mdbook serve +``` +ENABLE_LINKCHECK=1 mdbook serve ``` ### Table of Contents @@ -86,14 +86,14 @@ Older versions of `josh-proxy` may not round trip commits losslessly so it is im 1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide` 2) Run the pull command ``` - $ cargo run --manifest-path josh-sync/Cargo.toml rustc-pull + cargo run --manifest-path josh-sync/Cargo.toml rustc-pull ``` 3) Push the branch to your fork and create a PR into `rustc-dev-guide` ### Push changes from this repository into `rust-lang/rust` 1) Run the push command to create a branch named `` in a `rustc` fork under the `` account ``` - $ cargo run --manifest-path josh-sync/Cargo.toml rustc-push + cargo run --manifest-path josh-sync/Cargo.toml rustc-push ``` 2) Create a PR from `` into `rust-lang/rust` @@ -106,5 +106,5 @@ You may observe "Nothing to pull" even if you *know* rustc-pull has something to To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g. ``` -$ GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull +GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull ``` From a0c64dce0d70d1be54a6fd7b7aa9ed37665ad998 Mon Sep 17 00:00:00 2001 From: The rustc-dev-guide Cronjob Bot Date: Sat, 19 Apr 2025 13:53:05 +0000 Subject: [PATCH 073/109] Preparing for merge from rustc --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index a6f295108797..67de4a981655 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -25a615bf829b9f6d6f22da537e3851043f92e5f2 +a7c39b68616668a45f0afd62849a1da7c8ad2516 From 07b7f00a9e961fdf66ece2ecf70ae1dba505f10e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 19 Apr 2025 16:04:22 +0200 Subject: [PATCH 074/109] fix broken link --- src/doc/rustc-dev-guide/src/hir.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 65779f3129d9..0c1c9941572d 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -144,7 +144,7 @@ that `n` must be some HIR expression, you can do Finally, you can find the parents of nodes, via calls like [`tcx.parent_hir_node(n)`][parent_hir_node]. -[get_parent_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node +[parent_hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node ## HIR Bodies From 1ab497b3f497c7c9de8b488f98f990981a5b7f1b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 19 Apr 2025 15:12:11 +0200 Subject: [PATCH 075/109] document `#[cfg(bootstrap)]` in dependencies --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + .../bootstrap-in-dependencies.md | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 90fcde072805..68112d06167a 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -81,6 +81,7 @@ - [How Bootstrap does it](./building/bootstrapping/how-bootstrap-does-it.md) - [Writing tools in Bootstrap](./building/bootstrapping/writing-tools-in-bootstrap.md) - [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md) +- [cfg(bootstrap) in dependencies](./building/bootstrapping/bootstrap-in-dependencies.md) # High-level Compiler Architecture diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md new file mode 100644 index 000000000000..68c5c2386bd5 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md @@ -0,0 +1,53 @@ +# `cfg(bootstrap)` in compiler dependencies + +The rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. This page describes how `#[cfg(bootstrap)]` can be used to break this cycle. + +## Enabling `#[cfg(bootstrap)]` + +Usually the use of `#[cfg(bootstrap)]` in an external crate causes a warning: + +``` +warning: unexpected `cfg` condition name: `bootstrap` + --> src/main.rs:1:7 + | +1 | #[cfg(bootstrap)] + | ^^^^^^^^^ + | + = help: expected names are: `docsrs`, `feature`, and `test` and 31 more + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(bootstrap)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +``` + +This warning can be silenced by adding these lines to the project's `Cargo.toml`: + +```toml +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } +``` + +Now `#[cfg(bootstrap)]` can be used in the crate just like it can be in the compiler: when the bootstrap compiler is used, code annotated with `#[cfg(bootstrap)]` is compiled, otherwise code annotated with `#[cfg(not(bootstrap))]` is compiled. + +## The update dance + +As a concrete example we'll use a change where the `#[naked]` attribute was made into an unsafe attribute, which caused a cyclic dependency with the `compiler-builtins` crate. + +### Step 1: accept the new behavior in the compiler ([#139797](https://github.com/rust-lang/rust/pull/139797)) + +In this example it is possible to accept both the old and new behavior at the same time by disabling an error. + +### Step 2: update the crate ([#821](https://github.com/rust-lang/compiler-builtins/pull/821)) + +Now in the crate, use `#[cfg(bootstrap)]` to use the old behavior, or `#[cfg(not(bootstrap))]` to use the new behavior. + +### Step 3: update the crate version used by the compiler ([#139934](https://github.com/rust-lang/rust/pull/139934)) + +For `compiler-builtins` this meant a version bump, in other cases it may be a git submodule update. + +### Step 4: remove the old behavior from the compiler ([#139753](https://github.com/rust-lang/rust/pull/139753)) + +The updated crate can now be used. In this example that meant that the old behavior could be removed. From 6be60e83b5660f45fc26d75e43b6745e3a2d0ee9 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 19 Apr 2025 17:51:41 +0200 Subject: [PATCH 076/109] needed a stronger pause --- src/doc/rustc-dev-guide/src/tests/ui.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 7c4e2a0fdae7..f7857ae69034 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -337,7 +337,8 @@ possible, including `//~?` annotations for diagnostics without span. If the compile time output is target dependent or too verbose, use directive `//@ dont-require-annotations: ` to make the line annotation checking -non-exhaustive, some of the compiler messages can stay uncovered by annotations in this mode. +non-exhaustive. +Some of the compiler messages can stay uncovered by annotations in this mode. For checking runtime output `//@ check-run-results` may be preferable. From d09b3c75de1d2a4f15c6537d402df60a98fe07c3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 19 Apr 2025 17:57:56 +0200 Subject: [PATCH 077/109] fix grammar --- src/doc/rustc-dev-guide/src/tests/ui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index f7857ae69034..06b13a324ee7 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -333,7 +333,7 @@ fn main() { Use of `error-pattern` is not recommended in general. For strict testing of compile time output, try to use the line annotations `//~` as much as -possible, including `//~?` annotations for diagnostics without span. +possible, including `//~?` annotations for diagnostics without spans. If the compile time output is target dependent or too verbose, use directive `//@ dont-require-annotations: ` to make the line annotation checking From 48612702d937bc6e26ccc70496c0aade6fae493c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 19 Apr 2025 17:56:23 +0200 Subject: [PATCH 078/109] improve readability by adding pauses --- src/doc/rustc-dev-guide/src/tests/ui.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 06b13a324ee7..6232c8bcc0a6 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -303,7 +303,7 @@ It should be preferred to using `error-pattern`, which is imprecise and non-exha ### `error-pattern` The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't -have a specific span, or in exceptional cases for compile time messages. +have a specific span, or in exceptional cases, for compile time messages. Let's think about this test: @@ -316,7 +316,7 @@ fn main() { } ``` -We want to ensure this shows "index out of bounds" but we cannot use the `ERROR` +We want to ensure this shows "index out of bounds", but we cannot use the `ERROR` annotation since the runtime error doesn't have any span. Then it's time to use the `error-pattern` directive: @@ -340,12 +340,12 @@ If the compile time output is target dependent or too verbose, use directive non-exhaustive. Some of the compiler messages can stay uncovered by annotations in this mode. -For checking runtime output `//@ check-run-results` may be preferable. +For checking runtime output, `//@ check-run-results` may be preferable. Only use `error-pattern` if none of the above works. Line annotations `//~` are still checked in tests using `error-pattern`. -In exceptional cases use `//@ compile-flags: --error-format=human` to opt out of these checks. +In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks. ### Diagnostic kinds (error levels) From 47911eb677a29006d243a0b6bf17f26486191ead Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Apr 2025 23:36:17 +0000 Subject: [PATCH 079/109] Don't ICE on pending obligations from deep normalization in a loop --- .../src/traits/normalize.rs | 10 +- tests/crashes/133868.rs | 13 -- tests/ui/traits/deep-norm-pending.rs | 24 ++++ tests/ui/traits/deep-norm-pending.stderr | 130 ++++++++++++++++++ 4 files changed, 163 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/133868.rs create mode 100644 tests/ui/traits/deep-norm-pending.rs create mode 100644 tests/ui/traits/deep-norm-pending.stderr diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 4ac45172a0e1..7551ac5aa973 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -77,7 +77,15 @@ impl<'tcx> At<'_, 'tcx> { .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); let errors = fulfill_cx.select_all_or_error(self.infcx); let value = self.infcx.resolve_vars_if_possible(value); - if errors.is_empty() { Ok(value) } else { Err(errors) } + if errors.is_empty() { + Ok(value) + } else { + // Drop pending obligations, since deep normalization may happen + // in a loop and we don't want to trigger the assertion on the next + // iteration due to pending ambiguous obligations we've left over. + let _ = fulfill_cx.collect_remaining_errors(self.infcx); + Err(errors) + } } } } diff --git a/tests/crashes/133868.rs b/tests/crashes/133868.rs deleted file mode 100644 index dc25cb9df288..000000000000 --- a/tests/crashes/133868.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #133868 - -trait Foo { - type Assoc; -} - -trait Bar { - fn method() -> impl Sized; -} -impl Bar for T where ::Assoc: Sized -{ - fn method() {} -} diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/deep-norm-pending.rs new file mode 100644 index 000000000000..f56c3cfa3eab --- /dev/null +++ b/tests/ui/traits/deep-norm-pending.rs @@ -0,0 +1,24 @@ +trait Foo { + type Assoc; +} + +trait Bar { + fn method() -> impl Sized; + //~^ ERROR the trait bound `T: Foo` is not satisfied +} +impl Bar for T +//~^ ERROR the trait bound `T: Foo` is not satisfied +//~| ERROR the trait bound `T: Foo` is not satisfied +where + ::Assoc: Sized, +{ + fn method() {} + //~^ ERROR the trait bound `T: Foo` is not satisfied + //~| ERROR the trait bound `T: Foo` is not satisfied + //~| ERROR the trait bound `T: Foo` is not satisfied + //~| ERROR the trait bound `T: Foo` is not satisfied + //~| ERROR the trait bound `T: Foo` is not satisfied + //~| ERROR the trait bound `T: Foo` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/deep-norm-pending.stderr new file mode 100644 index 000000000000..b95b9d7f4aec --- /dev/null +++ b/tests/ui/traits/deep-norm-pending.stderr @@ -0,0 +1,130 @@ +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:5 + | +LL | fn method() {} + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:9:1 + | +LL | / impl Bar for T +LL | | +LL | | +LL | | where +LL | | ::Assoc: Sized, + | |_____________________________^ the trait `Foo` is not implemented for `T` + | +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:9:1 + | +LL | / impl Bar for T +LL | | +LL | | +LL | | where +... | +LL | | } + | |_^ the trait `Foo` is not implemented for `T` + | +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:5 + | +LL | fn method() {} + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:5 + | +LL | fn method() {} + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | +note: required for `T` to implement `Bar` + --> $DIR/deep-norm-pending.rs:9:9 + | +LL | impl Bar for T + | ^^^ ^ +... +LL | ::Assoc: Sized, + | ----- unsatisfied trait bound introduced here +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:5 + | +LL | fn method() {} + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:6:20 + | +LL | fn method() -> impl Sized; + | ^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | +note: required for `T` to implement `Bar` + --> $DIR/deep-norm-pending.rs:9:9 + | +LL | impl Bar for T + | ^^^ ^ +... +LL | ::Assoc: Sized, + | ----- unsatisfied trait bound introduced here +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:5 + | +LL | fn method() {} + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/deep-norm-pending.rs:15:8 + | +LL | fn method() {} + | ^^^^^^ the trait `Foo` is not implemented for `T` + | +help: consider further restricting type parameter `T` with trait `Foo` + | +LL | ::Assoc: Sized, T: Foo + | ++++++ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0277`. From ae4b6d6c65c32d41d8017b4e3765a8a1871e8519 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Apr 2025 21:06:52 +0200 Subject: [PATCH 080/109] Update docs for `AssocItems::filter_by_name_unhygienic` --- compiler/rustc_middle/src/ty/assoc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 0c44fd2758d5..78b2e265b488 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -246,6 +246,8 @@ impl AssocItems { } /// Returns an iterator over all associated items with the given name, ignoring hygiene. + /// + /// Panics if `name.is_empty()` returns `true`. pub fn filter_by_name_unhygienic( &self, name: Symbol, From e0437ec364017b11b5e63d1c09e3204029d8b497 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Apr 2025 21:07:24 +0200 Subject: [PATCH 081/109] Fix error when an intra doc link is trying to resolve an empty associated item --- src/librustdoc/passes/collect_intra_doc_links.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 297597b3deac..36f5889dcf4e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -59,7 +59,12 @@ fn filter_assoc_items_by_name_and_namespace( ident: Ident, ns: Namespace, ) -> impl Iterator { - tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { + let iter: Box> = if !ident.name.is_empty() { + Box::new(tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name)) + } else { + Box::new([].iter()) + }; + iter.filter(move |item| { item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) } From 88a5e1ef683673c7e1b16b399d745d01ad540a19 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Apr 2025 21:10:40 +0200 Subject: [PATCH 082/109] Add regression test for #140026 --- .../rustdoc-ui/intra-doc/empty-associated-items.rs | 8 ++++++++ .../intra-doc/empty-associated-items.stderr | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/rustdoc-ui/intra-doc/empty-associated-items.rs create mode 100644 tests/rustdoc-ui/intra-doc/empty-associated-items.stderr diff --git a/tests/rustdoc-ui/intra-doc/empty-associated-items.rs b/tests/rustdoc-ui/intra-doc/empty-associated-items.rs new file mode 100644 index 000000000000..ea94cb349ad2 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/empty-associated-items.rs @@ -0,0 +1,8 @@ +// This test ensures that an empty associated item will not crash rustdoc. +// This is a regression test for . + +#[deny(rustdoc::broken_intra_doc_links)] + +/// [`String::`] +//~^ ERROR +pub struct Foo; diff --git a/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr b/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr new file mode 100644 index 000000000000..b0527916ab50 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `String::` + --> $DIR/empty-associated-items.rs:6:7 + | +LL | /// [`String::`] + | ^^^^^^^^ the struct `String` has no field or associated item named `` + | +note: the lint level is defined here + --> $DIR/empty-associated-items.rs:4:8 + | +LL | #[deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From f3b7e2381aead49fea038952c37291635d279229 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 19 Apr 2025 12:11:22 -0700 Subject: [PATCH 083/109] Switch exploit mitigations to mdbook footnotes This updates the exploit mitigations chapter in the rustc book to use the footnote feature of mdbook instead of manually implementing footnotes with HTML. --- src/doc/rustc/src/exploit-mitigations.md | 65 ++++++++---------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index d4e2fc52e973..f8bafe032140 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -42,8 +42,7 @@ understood within a given context. This section documents the exploit mitigations applicable to the Rust compiler when building programs for the Linux operating system on the AMD64 architecture -and equivalent.1 All examples in this section were built using +and equivalent.[^all-targets] All examples in this section were built using nightly builds of the Rust compiler on Debian testing. The Rust Programming Language currently has no specification. The Rust compiler @@ -67,11 +66,8 @@ equivalent. | Forward-edge control flow protection | Yes | Nightly | | Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | -1\. See - -for a list of targets and their default options. - +[^all-targets]: See + for a list of targets and their default options. ### Position-independent executable @@ -141,18 +137,15 @@ Integer overflow checks are enabled when debug assertions are enabled (see Fig. 3), and disabled when debug assertions are disabled (see Fig. 4). To enable integer overflow checks independently, use the option to control integer overflow checks, scoped attributes, or explicit checking methods such as -`checked_add`2. +`checked_add`[^checked-methods]. It is recommended that explicit wrapping methods such as `wrapping_add` be used when wrapping semantics are intended, and that explicit checking and wrapping methods always be used when using Unsafe Rust. -2\. See [the `u32` docs](../std/primitive.u32.html) for more -information on the checked, overflowing, saturating, and wrapping methods -(using u32 as an example). - +[^checked-methods]: See [the `u32` docs](../std/primitive.u32.html) for more + information on the checked, overflowing, saturating, and wrapping methods + (using u32 as an example). ### Non-executable memory regions @@ -180,17 +173,14 @@ binary. The presence of an element of type `PT_GNU_STACK` in the program header table with the `PF_X` (i.e., executable) flag unset indicates non-executable memory -regions3 are enabled for a given binary (see Fig. 5). +regions[^other-regions] are enabled for a given binary (see Fig. 5). Conversely, the presence of an element of type `PT_GNU_STACK` in the program header table with the `PF_X` flag set or the absence of an element of type `PT_GNU_STACK` in the program header table indicates non-executable memory regions are not enabled for a given binary. -3\. See the Appendix section for more information on why it -affects other memory regions besides the stack. - +[^other-regions]: See the [Appendix section](#appendix) for more information + on why it affects other memory regions besides the stack. ### Stack clashing protection @@ -270,8 +260,7 @@ $ readelf -d target/release/hello-rust | grep BIND_NOW Fig. 10. Checking if immediate binding is enabled for a given binary. The presence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` -flag4 in the dynamic section indicates immediate binding +flag[^bind-now] in the dynamic section indicates immediate binding is enabled for a given binary (see Fig. 10). Conversely, the absence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the dynamic section indicates immediate binding is not enabled for a given binary. @@ -281,9 +270,7 @@ table and of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the dynamic section indicates full RELRO is enabled for a given binary (see Figs. 9–10). -4\. And the `DF_1_NOW` flag for some link editors. - +[^bind-now]: And the `DF_1_NOW` flag for some link editors. ### Heap corruption protection @@ -303,8 +290,7 @@ Rust’s default allocator has historically been [jemalloc](http://jemalloc.net/), and it has long been the cause of issues and the subject of much discussion[32]–[38]. Consequently, it has been removed as the default allocator in favor of the operating system’s standard C library -default allocator5 since version 1.32.0 (2019-01-17)[39]. +default allocator[^linx-allocator] since version 1.32.0 (2019-01-17)[39]. ```rust,no_run fn main() { @@ -343,11 +329,9 @@ Fig. 13. Build and execution of hello-rust-heap with debug assertions disabled Heap corruption checks are performed when using the default allocator (i.e., the GNU Allocator) (see Figs. 12–13). -5\. Linux's standard C library default allocator is the GNU -Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram Gloger, -which in turn is derived from dlmalloc (Doug Lea malloc) by Doug Lea. - +[^linx-allocator]: Linux's standard C library default allocator is the GNU + Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram Gloger, + which in turn is derived from dlmalloc (Doug Lea malloc) by Doug Lea. ### Stack smashing protection @@ -385,8 +369,7 @@ commercially available [grsecurity/PaX Reuse Attack Protector (RAP)](https://grsecurity.net/rap_faq). The Rust compiler supports forward-edge control flow protection on nightly -builds[41]-[42] 6. +builds[41]-[42] [^win-cfg]. ```text $ readelf -s -W target/release/hello-rust | grep "\.cfi" @@ -401,10 +384,8 @@ of symbols suffixed with ".cfi" or the `__cfi_init` symbol (and references to `__cfi_check`) indicates that LLVM CFI is not enabled for a given binary (see Fig. 15). -6\. It also supports Control Flow Guard (CFG) on Windows (see -). - +[^win-cfg]: It also supports Control Flow Guard (CFG) on Windows (see + ). ### Backward-edge control flow protection @@ -431,8 +412,7 @@ Newer processors provide hardware assistance for backward-edge control flow protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part of Intel CET. -The Rust compiler supports shadow stack for the AArch64 architecture7on +The Rust compiler supports shadow stack for the AArch64 architecture[^amd64-shadow] on nightly builds[43]-[44], and also supports safe stack on nightly builds[45]-[46]. @@ -447,9 +427,8 @@ enabled for a given binary. Conversely, the absence of the `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a given binary (see Fig. 16). -7\. The shadow stack implementation for the AMD64 architecture -and equivalent in LLVM was removed due to performance and security issues. +[^amd64-shadow]: The shadow stack implementation for the AMD64 architecture + and equivalent in LLVM was removed due to performance and security issues. ## Appendix From 648653824bf8704685d45ef465a115d3dcae4ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?On=C3=A8?= <43485962+c-git@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:57:06 -0400 Subject: [PATCH 084/109] docs: fix typo change from inconstants to invariants --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 7b2a3fac38a3..1ae0849db5b5 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2814,7 +2814,7 @@ impl [T] { let half = size / 2; let mid = base + half; - // SAFETY: the call is made safe by the following inconstants: + // SAFETY: the call is made safe by the following invariants: // - `mid >= 0`: by definition // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` let cmp = f(unsafe { self.get_unchecked(mid) }); From 957b5488a5fb3875006c06577d9049177ed971bc Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 17 Apr 2025 17:58:34 +0000 Subject: [PATCH 085/109] transmutability: remove NFA intermediate representation Prior to this commit, the transmutability analysis used an intermediate NFA representation of type layout. We then determinized this representation into a DFA, upon which we ran the core transmutability analysis. Unfortunately, determinizing NFAs is expensive. In this commit, we avoid NFAs entirely by observing that Rust `union`s are the only source of nondeterminism and that it is comparatively cheap to compute the DFA union of DFAs. We also implement Graphviz DOT debug formatting of DFAs. Fixes rust-lang/project-safe-transmute#23 Fixes rust-lang/project-safe-transmute#24 --- compiler/rustc_transmute/src/layout/dfa.rs | 283 ++++++++++++------ compiler/rustc_transmute/src/layout/mod.rs | 10 +- compiler/rustc_transmute/src/layout/nfa.rs | 169 ----------- compiler/rustc_transmute/src/lib.rs | 2 +- .../src/maybe_transmutable/mod.rs | 33 +- .../src/maybe_transmutable/tests.rs | 31 +- 6 files changed, 236 insertions(+), 292 deletions(-) delete mode 100644 compiler/rustc_transmute/src/layout/nfa.rs diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index af568171f911..bb909c54d2bc 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -1,19 +1,18 @@ use std::fmt; use std::sync::atomic::{AtomicU32, Ordering}; -use tracing::instrument; - -use super::{Byte, Nfa, Ref, nfa}; +use super::{Byte, Ref, Tree, Uninhabited}; use crate::Map; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq)] +#[cfg_attr(test, derive(Clone))] pub(crate) struct Dfa where R: Ref, { pub(crate) transitions: Map>, pub(crate) start: State, - pub(crate) accepting: State, + pub(crate) accept: State, } #[derive(PartialEq, Clone, Debug)] @@ -34,35 +33,15 @@ where } } -impl Transitions -where - R: Ref, -{ - #[cfg(test)] - fn insert(&mut self, transition: Transition, state: State) { - match transition { - Transition::Byte(b) => { - self.byte_transitions.insert(b, state); - } - Transition::Ref(r) => { - self.ref_transitions.insert(r, state); - } - } - } -} - -/// The states in a `Nfa` represent byte offsets. +/// The states in a [`Dfa`] represent byte offsets. #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] -pub(crate) struct State(u32); +pub(crate) struct State(pub(crate) u32); -#[cfg(test)] -#[derive(Hash, Eq, PartialEq, Clone, Copy)] -pub(crate) enum Transition -where - R: Ref, -{ - Byte(Byte), - Ref(R), +impl State { + pub(crate) fn new() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } } impl fmt::Debug for State { @@ -71,19 +50,6 @@ impl fmt::Debug for State { } } -#[cfg(test)] -impl fmt::Debug for Transition -where - R: Ref, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self { - Self::Byte(b) => b.fmt(f), - Self::Ref(r) => r.fmt(f), - } - } -} - impl Dfa where R: Ref, @@ -92,60 +58,167 @@ where pub(crate) fn bool() -> Self { let mut transitions: Map> = Map::default(); let start = State::new(); - let accepting = State::new(); + let accept = State::new(); - transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting); + transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x00), accept); - transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting); + transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x01), accept); - Self { transitions, start, accepting } + Self { transitions, start, accept } } - #[instrument(level = "debug")] - pub(crate) fn from_nfa(nfa: Nfa) -> Self { - let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; + pub(crate) fn unit() -> Self { + let transitions: Map> = Map::default(); + let start = State::new(); + let accept = start; - let mut dfa_transitions: Map> = Map::default(); - let mut nfa_to_dfa: Map = Map::default(); - let dfa_start = State::new(); - nfa_to_dfa.insert(nfa_start, dfa_start); + Self { transitions, start, accept } + } - let mut queue = vec![(nfa_start, dfa_start)]; + pub(crate) fn from_byte(byte: Byte) -> Self { + let mut transitions: Map> = Map::default(); + let start = State::new(); + let accept = State::new(); - while let Some((nfa_state, dfa_state)) = queue.pop() { - if nfa_state == nfa_accepting { - continue; + transitions.entry(start).or_default().byte_transitions.insert(byte, accept); + + Self { transitions, start, accept } + } + + pub(crate) fn from_ref(r: R) -> Self { + let mut transitions: Map> = Map::default(); + let start = State::new(); + let accept = State::new(); + + transitions.entry(start).or_default().ref_transitions.insert(r, accept); + + Self { transitions, start, accept } + } + + pub(crate) fn from_tree(tree: Tree) -> Result { + Ok(match tree { + Tree::Byte(b) => Self::from_byte(b), + Tree::Ref(r) => Self::from_ref(r), + Tree::Alt(alts) => { + // Convert and filter the inhabited alternatives. + let mut alts = alts.into_iter().map(Self::from_tree).filter_map(Result::ok); + // If there are no alternatives, return `Uninhabited`. + let dfa = alts.next().ok_or(Uninhabited)?; + // Combine the remaining alternatives with `dfa`. + alts.fold(dfa, |dfa, alt| dfa.union(alt, State::new)) + } + Tree::Seq(elts) => { + let mut dfa = Self::unit(); + for elt in elts.into_iter().map(Self::from_tree) { + dfa = dfa.concat(elt?); + } + dfa + } + }) + } + + /// Concatenate two `Dfa`s. + pub(crate) fn concat(self, other: Self) -> Self { + if self.start == self.accept { + return other; + } else if other.start == other.accept { + return self; + } + + let start = self.start; + let accept = other.accept; + + let mut transitions: Map> = self.transitions; + + for (source, transition) in other.transitions { + let fix_state = |state| if state == other.start { self.accept } else { state }; + let entry = transitions.entry(fix_state(source)).or_default(); + for (edge, destination) in transition.byte_transitions { + entry.byte_transitions.insert(edge, fix_state(destination)); + } + for (edge, destination) in transition.ref_transitions { + entry.ref_transitions.insert(edge, fix_state(destination)); + } + } + + Self { transitions, start, accept } + } + + /// Compute the union of two `Dfa`s. + pub(crate) fn union(self, other: Self, mut new_state: impl FnMut() -> State) -> Self { + // We implement `union` by lazily initializing a set of states + // corresponding to the product of states in `self` and `other`, and + // then add transitions between these states that correspond to where + // they exist between `self` and `other`. + + let a = self; + let b = other; + + let accept = new_state(); + + let mut mapping: Map<(Option, Option), State> = Map::default(); + + let mut mapped = |(a_state, b_state)| { + if Some(a.accept) == a_state || Some(b.accept) == b_state { + // If either `a_state` or `b_state` are accepting, map to a + // common `accept` state. + accept + } else { + *mapping.entry((a_state, b_state)).or_insert_with(&mut new_state) + } + }; + + let start = mapped((Some(a.start), Some(b.start))); + let mut transitions: Map> = Map::default(); + let mut queue = vec![(Some(a.start), Some(b.start))]; + let empty_transitions = Transitions::default(); + + while let Some((a_src, b_src)) = queue.pop() { + let a_transitions = + a_src.and_then(|a_src| a.transitions.get(&a_src)).unwrap_or(&empty_transitions); + let b_transitions = + b_src.and_then(|b_src| b.transitions.get(&b_src)).unwrap_or(&empty_transitions); + + let byte_transitions = + a_transitions.byte_transitions.keys().chain(b_transitions.byte_transitions.keys()); + + for byte_transition in byte_transitions { + let a_dst = a_transitions.byte_transitions.get(byte_transition).copied(); + let b_dst = b_transitions.byte_transitions.get(byte_transition).copied(); + + assert!(a_dst.is_some() || b_dst.is_some()); + + let src = mapped((a_src, b_src)); + let dst = mapped((a_dst, b_dst)); + + transitions.entry(src).or_default().byte_transitions.insert(*byte_transition, dst); + + if !transitions.contains_key(&dst) { + queue.push((a_dst, b_dst)) + } } - for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() { - let dfa_transitions = - dfa_transitions.entry(dfa_state).or_insert_with(Default::default); + let ref_transitions = + a_transitions.ref_transitions.keys().chain(b_transitions.ref_transitions.keys()); - let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied()); + for ref_transition in ref_transitions { + let a_dst = a_transitions.ref_transitions.get(ref_transition).copied(); + let b_dst = b_transitions.ref_transitions.get(ref_transition).copied(); - let next_dfa_state = match nfa_transition { - &nfa::Transition::Byte(b) => *dfa_transitions - .byte_transitions - .entry(b) - .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), - &nfa::Transition::Ref(r) => *dfa_transitions - .ref_transitions - .entry(r) - .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), - }; + assert!(a_dst.is_some() || b_dst.is_some()); - for &next_nfa_state in next_nfa_states { - nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| { - queue.push((next_nfa_state, next_dfa_state)); - next_dfa_state - }); + let src = mapped((a_src, b_src)); + let dst = mapped((a_dst, b_dst)); + + transitions.entry(src).or_default().ref_transitions.insert(*ref_transition, dst); + + if !transitions.contains_key(&dst) { + queue.push((a_dst, b_dst)) } } } - let dfa_accepting = nfa_to_dfa[&nfa_accepting]; - - Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting } + Self { transitions, start, accept } } pub(crate) fn bytes_from(&self, start: State) -> Option<&Map> { @@ -159,24 +232,48 @@ where pub(crate) fn refs_from(&self, start: State) -> Option<&Map> { Some(&self.transitions.get(&start)?.ref_transitions) } -} -impl State { - pub(crate) fn new() -> Self { - static COUNTER: AtomicU32 = AtomicU32::new(0); - Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + #[cfg(test)] + pub(crate) fn from_edges>( + start: u32, + accept: u32, + edges: &[(u32, B, u32)], + ) -> Self { + let start = State(start); + let accept = State(accept); + let mut transitions: Map> = Map::default(); + + for &(src, edge, dst) in edges { + let src = State(src); + let dst = State(dst); + let old = transitions.entry(src).or_default().byte_transitions.insert(edge.into(), dst); + assert!(old.is_none()); + } + + Self { start, accept, transitions } } } -#[cfg(test)] -impl From> for Transition +/// Serialize the DFA using the Graphviz DOT format. +impl fmt::Debug for Dfa where R: Ref, { - fn from(nfa_transition: nfa::Transition) -> Self { - match nfa_transition { - nfa::Transition::Byte(byte) => Transition::Byte(byte), - nfa::Transition::Ref(r) => Transition::Ref(r), + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "digraph {{")?; + writeln!(f, " {:?} [shape = doublecircle]", self.start)?; + writeln!(f, " {:?} [shape = doublecircle]", self.accept)?; + + for (src, transitions) in self.transitions.iter() { + for (t, dst) in transitions.byte_transitions.iter() { + writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?; + } + + for (t, dst) in transitions.ref_transitions.iter() { + writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?; + } } + + writeln!(f, "}}") } } diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index c4c01a8fac31..c940f7c42a82 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -4,9 +4,6 @@ use std::hash::Hash; pub(crate) mod tree; pub(crate) use tree::Tree; -pub(crate) mod nfa; -pub(crate) use nfa::Nfa; - pub(crate) mod dfa; pub(crate) use dfa::Dfa; @@ -29,6 +26,13 @@ impl fmt::Debug for Byte { } } +#[cfg(test)] +impl From for Byte { + fn from(src: u8) -> Self { + Self::Init(src) + } +} + pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone { fn has_safety_invariants(&self) -> bool; } diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs deleted file mode 100644 index 9c21fd94f03e..000000000000 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::fmt; -use std::sync::atomic::{AtomicU32, Ordering}; - -use super::{Byte, Ref, Tree, Uninhabited}; -use crate::{Map, Set}; - -/// A non-deterministic finite automaton (NFA) that represents the layout of a type. -/// The transmutability of two given types is computed by comparing their `Nfa`s. -#[derive(PartialEq, Debug)] -pub(crate) struct Nfa -where - R: Ref, -{ - pub(crate) transitions: Map, Set>>, - pub(crate) start: State, - pub(crate) accepting: State, -} - -/// The states in a `Nfa` represent byte offsets. -#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] -pub(crate) struct State(u32); - -/// The transitions between states in a `Nfa` reflect bit validity. -#[derive(Hash, Eq, PartialEq, Clone, Copy)] -pub(crate) enum Transition -where - R: Ref, -{ - Byte(Byte), - Ref(R), -} - -impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "S_{}", self.0) - } -} - -impl fmt::Debug for Transition -where - R: Ref, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self { - Self::Byte(b) => b.fmt(f), - Self::Ref(r) => r.fmt(f), - } - } -} - -impl Nfa -where - R: Ref, -{ - pub(crate) fn unit() -> Self { - let transitions: Map, Set>> = Map::default(); - let start = State::new(); - let accepting = start; - - Nfa { transitions, start, accepting } - } - - pub(crate) fn from_byte(byte: Byte) -> Self { - let mut transitions: Map, Set>> = Map::default(); - let start = State::new(); - let accepting = State::new(); - - let source = transitions.entry(start).or_default(); - let edge = source.entry(Transition::Byte(byte)).or_default(); - edge.insert(accepting); - - Nfa { transitions, start, accepting } - } - - pub(crate) fn from_ref(r: R) -> Self { - let mut transitions: Map, Set>> = Map::default(); - let start = State::new(); - let accepting = State::new(); - - let source = transitions.entry(start).or_default(); - let edge = source.entry(Transition::Ref(r)).or_default(); - edge.insert(accepting); - - Nfa { transitions, start, accepting } - } - - pub(crate) fn from_tree(tree: Tree) -> Result { - Ok(match tree { - Tree::Byte(b) => Self::from_byte(b), - Tree::Ref(r) => Self::from_ref(r), - Tree::Alt(alts) => { - let mut alts = alts.into_iter().map(Self::from_tree); - let mut nfa = alts.next().ok_or(Uninhabited)??; - for alt in alts { - nfa = nfa.union(alt?); - } - nfa - } - Tree::Seq(elts) => { - let mut nfa = Self::unit(); - for elt in elts.into_iter().map(Self::from_tree) { - nfa = nfa.concat(elt?); - } - nfa - } - }) - } - - /// Concatenate two `Nfa`s. - pub(crate) fn concat(self, other: Self) -> Self { - if self.start == self.accepting { - return other; - } else if other.start == other.accepting { - return self; - } - - let start = self.start; - let accepting = other.accepting; - - let mut transitions: Map, Set>> = self.transitions; - - for (source, transition) in other.transitions { - let fix_state = |state| if state == other.start { self.accepting } else { state }; - let entry = transitions.entry(fix_state(source)).or_default(); - for (edge, destinations) in transition { - let entry = entry.entry(edge).or_default(); - for destination in destinations { - entry.insert(fix_state(destination)); - } - } - } - - Self { transitions, start, accepting } - } - - /// Compute the union of two `Nfa`s. - pub(crate) fn union(self, other: Self) -> Self { - let start = self.start; - let accepting = self.accepting; - - let mut transitions: Map, Set>> = self.transitions.clone(); - - for (&(mut source), transition) in other.transitions.iter() { - // if source is starting state of `other`, replace with starting state of `self` - if source == other.start { - source = self.start; - } - let entry = transitions.entry(source).or_default(); - for (edge, destinations) in transition { - let entry = entry.entry(*edge).or_default(); - for &(mut destination) in destinations { - // if dest is accepting state of `other`, replace with accepting state of `self` - if destination == other.accepting { - destination = self.accepting; - } - entry.insert(destination); - } - } - } - Self { transitions, start, accepting } - } -} - -impl State { - pub(crate) fn new() -> Self { - static COUNTER: AtomicU32 = AtomicU32::new(0); - Self(COUNTER.fetch_add(1, Ordering::SeqCst)) - } -} diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 00928137d297..76fa6ceabe7e 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -2,7 +2,7 @@ #![feature(never_type)] // tidy-alphabetical-end -pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; +pub(crate) use rustc_data_structures::fx::FxIndexMap as Map; pub mod layout; mod maybe_transmutable; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 63fabc9c83d9..db0e1ab8e986 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -4,7 +4,7 @@ pub(crate) mod query_context; #[cfg(test)] mod tests; -use crate::layout::{self, Byte, Def, Dfa, Nfa, Ref, Tree, Uninhabited, dfa}; +use crate::layout::{self, Byte, Def, Dfa, Ref, Tree, Uninhabited, dfa}; use crate::maybe_transmutable::query_context::QueryContext; use crate::{Answer, Condition, Map, Reason}; @@ -73,7 +73,7 @@ where /// Answers whether a `Tree` is transmutable into another `Tree`. /// /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, - /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. + /// then converts `src` and `dst` to `Dfa`s, and computes an answer using those DFAs. #[inline(always)] #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { @@ -105,22 +105,22 @@ where trace!(?dst, "pruned dst"); - // Convert `src` from a tree-based representation to an NFA-based + // Convert `src` from a tree-based representation to an DFA-based // representation. If the conversion fails because `src` is uninhabited, // conclude that the transmutation is acceptable, because instances of // the `src` type do not exist. - let src = match Nfa::from_tree(src) { + let src = match Dfa::from_tree(src) { Ok(src) => src, Err(Uninhabited) => return Answer::Yes, }; - // Convert `dst` from a tree-based representation to an NFA-based + // Convert `dst` from a tree-based representation to an DFA-based // representation. If the conversion fails because `src` is uninhabited, // conclude that the transmutation is unacceptable. Valid instances of // the `dst` type do not exist, either because it's genuinely // uninhabited, or because there are no branches of the tree that are // free of safety invariants. - let dst = match Nfa::from_tree(dst) { + let dst = match Dfa::from_tree(dst) { Ok(dst) => dst, Err(Uninhabited) => return Answer::No(Reason::DstMayHaveSafetyInvariants), }; @@ -129,23 +129,6 @@ where } } -impl MaybeTransmutableQuery::Ref>, C> -where - C: QueryContext, -{ - /// Answers whether a `Nfa` is transmutable into another `Nfa`. - /// - /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. - #[inline(always)] - #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] - pub(crate) fn answer(self) -> Answer<::Ref> { - let Self { src, dst, assume, context } = self; - let src = Dfa::from_nfa(src); - let dst = Dfa::from_nfa(dst); - MaybeTransmutableQuery { src, dst, assume, context }.answer() - } -} - impl MaybeTransmutableQuery::Ref>, C> where C: QueryContext, @@ -173,7 +156,7 @@ where src_transitions_len = self.src.transitions.len(), dst_transitions_len = self.dst.transitions.len() ); - let answer = if dst_state == self.dst.accepting { + let answer = if dst_state == self.dst.accept { // truncation: `size_of(Src) >= size_of(Dst)` // // Why is truncation OK to do? Because even though the Src is bigger, all we care about @@ -190,7 +173,7 @@ where // that none of the actually-used data can introduce an invalid state for Dst's type, we // are able to safely transmute, even with truncation. Answer::Yes - } else if src_state == self.src.accepting { + } else if src_state == self.src.accept { // extension: `size_of(Src) >= size_of(Dst)` if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) { self.answer_memo(cache, src_state, dst_state_prime) diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 69a6b1b77f4b..cc6a4dce17b6 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -126,7 +126,7 @@ mod bool { let into_set = |alts: Vec<_>| { #[cfg(feature = "rustc")] - let mut set = crate::Set::default(); + let mut set = rustc_data_structures::fx::FxIndexSet::default(); #[cfg(not(feature = "rustc"))] let mut set = std::collections::HashSet::new(); set.extend(alts); @@ -174,3 +174,32 @@ mod bool { } } } + +mod union { + use super::*; + + #[test] + fn union() { + let [a, b, c, d] = [0, 1, 2, 3]; + let s = Dfa::from_edges(a, d, &[(a, 0, b), (b, 0, d), (a, 1, c), (c, 1, d)]); + + let t = Dfa::from_edges(a, c, &[(a, 1, b), (b, 0, c)]); + + let mut ctr = 0; + let new_state = || { + let state = crate::layout::dfa::State(ctr); + ctr += 1; + state + }; + + let u = s.clone().union(t.clone(), new_state); + + let expected_u = + Dfa::from_edges(b, a, &[(b, 0, c), (b, 1, d), (d, 1, a), (d, 0, a), (c, 0, a)]); + + assert_eq!(u, expected_u); + + assert_eq!(is_transmutable(&s, &u, Assume::default()), Answer::Yes); + assert_eq!(is_transmutable(&t, &u, Assume::default()), Answer::Yes); + } +} From de9d8e9f71d3016566ccccf535f16c488d8ae098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 20 Apr 2025 08:57:28 +0200 Subject: [PATCH 086/109] Remove stray newline from post-merge report --- src/ci/citool/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index f4e671b609fa..87ce09cfb233 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -191,7 +191,7 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow output_details("Test dashboard", || { println!( - r#"\nRun + r#"Run ```bash cargo run --manifest-path src/ci/citool/Cargo.toml -- \ From 5f4d676e70d23b27cf03d931a8a9e944703ade8a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 16 Apr 2025 23:35:33 +0200 Subject: [PATCH 087/109] Remove #[rustc_macro_edition_2021]. It was only temporarily used by pin!(), which no longer needs it. --- .../src/attributes.rs | 1 - .../rustc_attr_parsing/src/attributes/mod.rs | 1 - .../src/attributes/rustc.rs | 19 ------------------- compiler/rustc_attr_parsing/src/context.rs | 2 -- compiler/rustc_feature/src/builtin_attrs.rs | 8 -------- compiler/rustc_resolve/src/macros.rs | 9 +-------- compiler/rustc_span/src/symbol.rs | 1 - 7 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 969bce7ae20a..d2d1285b0756 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -191,7 +191,6 @@ pub enum AttributeKind { }, MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), - RustcMacroEdition2021, Stability { stability: Stability, /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index bac111159db5..6ecd6b4d7dbb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -28,7 +28,6 @@ pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod repr; -pub(crate) mod rustc; pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc.rs b/compiler/rustc_attr_parsing/src/attributes/rustc.rs deleted file mode 100644 index bdd3bef2834b..000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/rustc.rs +++ /dev/null @@ -1,19 +0,0 @@ -use rustc_attr_data_structures::AttributeKind; -use rustc_span::sym; - -use super::{AcceptContext, SingleAttributeParser}; -use crate::parser::ArgParser; - -pub(crate) struct RustcMacroEdition2021Parser; - -// FIXME(jdonszelmann): make these proper diagnostics -impl SingleAttributeParser for RustcMacroEdition2021Parser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021]; - - fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {} - - fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { - assert!(args.no_args()); - Some(AttributeKind::RustcMacroEdition2021) - } -} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 972614a3366c..63597b37cb5e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,6 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInterna use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::repr::ReprParser; -use crate::attributes::rustc::RustcMacroEdition2021Parser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -77,7 +76,6 @@ attribute_groups!( // tidy-alphabetical-start Single, Single, - Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 713e460e507f..ccbb8e83fb65 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -676,14 +676,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "`rustc_never_type_options` is used to experiment with never type fallback and work on \ never type stabilization, and will never be stable" ), - rustc_attr!( - rustc_macro_edition_2021, - Normal, - template!(Word), - ErrorFollowing, - EncodeCrossCrate::No, - "makes spans in this macro edition 2021" - ), // ========================================================================== // Internal attributes: Runtime related: diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 749b7f24c50f..c58f84805720 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr}; +use rustc_attr_parsing::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ @@ -1128,13 +1128,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { edition, ); - // The #[rustc_macro_edition_2021] attribute is used by the pin!() macro - // as a temporary workaround for a regression in expressiveness in Rust 2024. - // See https://github.com/rust-lang/rust/issues/138718. - if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) { - ext.edition = Edition::Edition2021; - } - if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. if let Some(builtin_ext_kind) = self.builtin_macros.get(&builtin_name) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1c325ce7fd42..32a5aff0cb32 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1824,7 +1824,6 @@ symbols! { rustc_lint_opt_ty, rustc_lint_query_instability, rustc_lint_untracked_query_information, - rustc_macro_edition_2021, rustc_macro_transparency, rustc_main, rustc_mir, From df8a3d5f1d363c19e2fc82060aabb80a9cd94015 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 18 Dec 2024 22:05:27 +0100 Subject: [PATCH 088/109] stabilize `naked_functions` --- .../example/mini_core_hello_world.rs | 11 +- .../src/error_codes/E0787.md | 2 - compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/builtin_attrs.rs | 7 +- compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_passes/src/check_attr.rs | 7 -- library/core/src/arch.rs | 2 +- .../src/compiler-flags/sanitizer.md | 2 - .../aarch64-naked-fn-no-bti-prolog.rs | 2 +- tests/assembly/naked-functions/aix.rs | 2 +- tests/assembly/naked-functions/wasm32.rs | 2 +- .../x86_64-naked-fn-no-cet-prolog.rs | 2 +- tests/auxiliary/minicore.rs | 1 - tests/codegen/cffi/c-variadic-naked.rs | 1 - tests/codegen/naked-asan.rs | 2 +- tests/codegen/naked-fn/aligned.rs | 2 +- tests/codegen/naked-fn/generics.rs | 1 - tests/codegen/naked-fn/instruction-set.rs | 2 +- .../naked-fn/min-function-alignment.rs | 2 +- tests/codegen/naked-fn/naked-functions.rs | 2 +- .../naked-symbol-visibility/a_rust_dylib.rs | 2 +- tests/ui/asm/naked-asm-outside-naked-fn.rs | 1 - .../ui/asm/naked-asm-outside-naked-fn.stderr | 6 +- tests/ui/asm/naked-functions-ffi.rs | 1 - tests/ui/asm/naked-functions-ffi.stderr | 4 +- tests/ui/asm/naked-functions-inline.rs | 1 - tests/ui/asm/naked-functions-inline.stderr | 8 +- .../ui/asm/naked-functions-instruction-set.rs | 2 +- tests/ui/asm/naked-functions-rustic-abi.rs | 2 +- .../ui/asm/naked-functions-target-feature.rs | 2 +- tests/ui/asm/naked-functions-testattrs.rs | 1 - tests/ui/asm/naked-functions-testattrs.stderr | 8 +- .../asm/naked-functions-unused.aarch64.stderr | 20 +-- tests/ui/asm/naked-functions-unused.rs | 1 - .../asm/naked-functions-unused.x86_64.stderr | 20 +-- tests/ui/asm/naked-functions.rs | 1 - tests/ui/asm/naked-functions.stderr | 50 ++++---- tests/ui/asm/naked-invalid-attr.rs | 4 +- tests/ui/asm/naked-invalid-attr.stderr | 17 ++- tests/ui/asm/naked-with-invalid-repr-attr.rs | 1 - .../asm/naked-with-invalid-repr-attr.stderr | 12 +- tests/ui/asm/named-asm-labels.rs | 2 - tests/ui/asm/named-asm-labels.stderr | 116 +++++++++--------- tests/ui/asm/simple_global_asm.rs | 1 - .../feature-gate-naked_functions.rs | 20 --- .../feature-gate-naked_functions.stderr | 75 ----------- ...feature-gate-naked_functions_rustic_abi.rs | 2 +- ...ure-gate-naked_functions_target_feature.rs | 2 - ...gate-naked_functions_target_feature.stderr | 2 +- tests/ui/lint/inline-exported.rs | 2 - tests/ui/lint/inline-exported.stderr | 8 +- .../rfc-2091-track-caller/error-with-naked.rs | 1 - .../error-with-naked.stderr | 8 +- 53 files changed, 165 insertions(+), 294 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-naked_functions.rs delete mode 100644 tests/ui/feature-gates/feature-gate-naked_functions.stderr diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 0b3a7281d5a0..93ca2e0e4218 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,13 +1,4 @@ -#![feature( - no_core, - lang_items, - never_type, - linkage, - extern_types, - naked_functions, - thread_local, - repr_simd -)] +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md index 47b56ac17f4f..b7f92c8feb58 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0787.md +++ b/compiler/rustc_error_codes/src/error_codes/E0787.md @@ -3,8 +3,6 @@ An unsupported naked function definition. Erroneous code example: ```compile_fail,E0787 -#![feature(naked_functions)] - #[unsafe(naked)] pub extern "C" fn f() -> u32 { 42 diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index fcc11dd3c1fd..e3e4eefe5e10 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -300,6 +300,8 @@ declare_features! ( /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.49.0", Some(68354)), + /// Allows using `#[naked]` on functions. + (accepted, naked_functions, "CURRENT_RUSTC_VERSION", Some(90957)), /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` (accepted, native_link_modifiers, "1.61.0", Some(81490)), /// Allows specifying the bundle link modifier diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 713e460e507f..0233f7a72e88 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -443,6 +443,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), + ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Limits: ungated!( @@ -515,12 +516,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Unstable attributes: // ========================================================================== - // Linking: - gated!( - unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, - naked_functions, experimental!(naked) - ), - // Testing: gated!( test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e09ae3c12394..cbc121e3632a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -563,8 +563,6 @@ declare_features! ( (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), - /// Allows using `#[naked]` on functions. - (unstable, naked_functions, "1.9.0", Some(90957)), /// Allows using `#[naked]` on `extern "Rust"` functions. (unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)), /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cbe5058b5519..cfc71a412bea 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -690,13 +690,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[naked]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked") - } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { attr_span: attr.span(), diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index 81d828a971c8..f19fde2b4c73 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -32,7 +32,7 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { /// /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html -#[unstable(feature = "naked_functions", issue = "90957")] +#[stable(feature = "naked_functions", since = "CURRENT_RUSTC_VERSION")] #[rustc_builtin_macro] pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index f2e1bb80cb26..2f9d4d22e5a8 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -245,8 +245,6 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. ## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination ```rust,ignore (making doc tests pass cross-platform is hard) -#![feature(naked_functions)] - use std::arch::naked_asm; use std::mem; diff --git a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs index 46acf7c6501a..860ecc3cfcd0 100644 --- a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs +++ b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs @@ -4,7 +4,7 @@ //@ only-aarch64 #![crate_type = "lib"] -#![feature(naked_functions)] + use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", diff --git a/tests/assembly/naked-functions/aix.rs b/tests/assembly/naked-functions/aix.rs index 9aa9edc39e78..57ff0e183bed 100644 --- a/tests/assembly/naked-functions/aix.rs +++ b/tests/assembly/naked-functions/aix.rs @@ -9,7 +9,7 @@ //@[aix] needs-llvm-components: powerpc #![crate_type = "lib"] -#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)] +#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] #![no_core] // tests that naked functions work for the `powerpc64-ibm-aix` target. diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs index c114cb385be1..71e4d80764a3 100644 --- a/tests/assembly/naked-functions/wasm32.rs +++ b/tests/assembly/naked-functions/wasm32.rs @@ -9,7 +9,7 @@ //@ [wasm32-wasip1] needs-llvm-components: webassembly #![crate_type = "lib"] -#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)] +#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] #![no_core] extern crate minicore; diff --git a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs index df6a2e91c51e..81ee9b13b4ec 100644 --- a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs +++ b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs @@ -4,7 +4,7 @@ //@ only-x86_64 #![crate_type = "lib"] -#![feature(naked_functions)] + use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 03aa84765082..941c4abed467 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -22,7 +22,6 @@ negative_impls, rustc_attrs, decl_macro, - naked_functions, f16, f128, asm_experimental_arch, diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs index 05d48e52dc00..5843628b6330 100644 --- a/tests/codegen/cffi/c-variadic-naked.rs +++ b/tests/codegen/cffi/c-variadic-naked.rs @@ -5,7 +5,6 @@ #![crate_type = "lib"] #![feature(c_variadic)] -#![feature(naked_functions)] #![no_std] #[unsafe(naked)] diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index 52b3e709cd35..223c41b15bb3 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -6,7 +6,7 @@ #![crate_type = "lib"] #![no_std] -#![feature(abi_x86_interrupt, naked_functions)] +#![feature(abi_x86_interrupt)] pub fn caller() { page_fault_handler(1, 2); diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index 6183461fedae..47ef779f1b21 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -3,7 +3,7 @@ //@ ignore-arm no "ret" mnemonic #![crate_type = "lib"] -#![feature(naked_functions, fn_align)] +#![feature(fn_align)] use std::arch::naked_asm; // CHECK: .balign 16 diff --git a/tests/codegen/naked-fn/generics.rs b/tests/codegen/naked-fn/generics.rs index 442758677716..865be00d91ee 100644 --- a/tests/codegen/naked-fn/generics.rs +++ b/tests/codegen/naked-fn/generics.rs @@ -2,7 +2,6 @@ //@ only-x86_64 #![crate_type = "lib"] -#![feature(naked_functions, asm_const)] use std::arch::naked_asm; diff --git a/tests/codegen/naked-fn/instruction-set.rs b/tests/codegen/naked-fn/instruction-set.rs index 2ccd47d64585..67560c5aba75 100644 --- a/tests/codegen/naked-fn/instruction-set.rs +++ b/tests/codegen/naked-fn/instruction-set.rs @@ -6,7 +6,7 @@ //@ [thumb-mode] needs-llvm-components: arm #![crate_type = "lib"] -#![feature(no_core, lang_items, rustc_attrs, naked_functions)] +#![feature(no_core, lang_items, rustc_attrs)] #![no_core] extern crate minicore; diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs index 4a9142288248..1d778be8c90d 100644 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ b/tests/codegen/naked-fn/min-function-alignment.rs @@ -2,7 +2,7 @@ //@ needs-asm-support //@ ignore-arm no "ret" mnemonic -#![feature(naked_functions, fn_align)] +#![feature(fn_align)] #![crate_type = "lib"] // functions without explicit alignment use the global minimum diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 1bcdd6de373e..344af6eb42fa 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -13,7 +13,7 @@ //@[thumb] needs-llvm-components: arm #![crate_type = "lib"] -#![feature(no_core, lang_items, rustc_attrs, naked_functions)] +#![feature(no_core, lang_items, rustc_attrs)] #![no_core] extern crate minicore; diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs index ae7551952536..ce787f83ade6 100644 --- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs +++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs @@ -1,4 +1,4 @@ -#![feature(naked_functions, linkage)] +#![feature(linkage)] #![crate_type = "dylib"] use std::arch::naked_asm; diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.rs b/tests/ui/asm/naked-asm-outside-naked-fn.rs index a7680cc63ae0..0a15b21f4d01 100644 --- a/tests/ui/asm/naked-asm-outside-naked-fn.rs +++ b/tests/ui/asm/naked-asm-outside-naked-fn.rs @@ -3,7 +3,6 @@ //@ ignore-nvptx64 //@ ignore-spirv -#![feature(naked_functions)] #![crate_type = "lib"] use std::arch::naked_asm; diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.stderr b/tests/ui/asm/naked-asm-outside-naked-fn.stderr index 85a50a49fecf..2cebaa9ea285 100644 --- a/tests/ui/asm/naked-asm-outside-naked-fn.stderr +++ b/tests/ui/asm/naked-asm-outside-naked-fn.stderr @@ -1,17 +1,17 @@ error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - --> $DIR/naked-asm-outside-naked-fn.rs:21:5 + --> $DIR/naked-asm-outside-naked-fn.rs:20:5 | LL | naked_asm!("") | ^^^^^^^^^^^^^^ error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - --> $DIR/naked-asm-outside-naked-fn.rs:26:9 + --> $DIR/naked-asm-outside-naked-fn.rs:25:9 | LL | (|| naked_asm!(""))() | ^^^^^^^^^^^^^^ error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - --> $DIR/naked-asm-outside-naked-fn.rs:32:9 + --> $DIR/naked-asm-outside-naked-fn.rs:31:9 | LL | naked_asm!(""); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index 8fd0da01d72a..565c440022db 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -1,6 +1,5 @@ //@ check-pass //@ needs-asm-support -#![feature(naked_functions)] #![crate_type = "lib"] use std::arch::naked_asm; diff --git a/tests/ui/asm/naked-functions-ffi.stderr b/tests/ui/asm/naked-functions-ffi.stderr index 908881b19499..9df6185498ed 100644 --- a/tests/ui/asm/naked-functions-ffi.stderr +++ b/tests/ui/asm/naked-functions-ffi.stderr @@ -1,5 +1,5 @@ warning: `extern` fn uses type `char`, which is not FFI-safe - --> $DIR/naked-functions-ffi.rs:9:28 + --> $DIR/naked-functions-ffi.rs:8:28 | LL | pub extern "C" fn naked(p: char) -> u128 { | ^^^^ not FFI-safe @@ -9,7 +9,7 @@ LL | pub extern "C" fn naked(p: char) -> u128 { = note: `#[warn(improper_ctypes_definitions)]` on by default warning: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/naked-functions-ffi.rs:9:37 + --> $DIR/naked-functions-ffi.rs:8:37 | LL | pub extern "C" fn naked(p: char) -> u128 { | ^^^^ not FFI-safe diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 261401be6451..93741f26275b 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -1,5 +1,4 @@ //@ needs-asm-support -#![feature(naked_functions)] #![crate_type = "lib"] use std::arch::naked_asm; diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 6df5b08ae853..07d5f3bc49a9 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -1,5 +1,5 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:13:1 + --> $DIR/naked-functions-inline.rs:12:1 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here @@ -7,7 +7,7 @@ LL | #[inline] | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:20:1 + --> $DIR/naked-functions-inline.rs:19:1 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here @@ -15,7 +15,7 @@ LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:27:1 + --> $DIR/naked-functions-inline.rs:26:1 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here @@ -23,7 +23,7 @@ LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:34:19 + --> $DIR/naked-functions-inline.rs:33:19 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index 6fd34b035edd..69927a56aabb 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -5,7 +5,7 @@ //@ build-pass #![crate_type = "lib"] -#![feature(no_core, naked_functions)] +#![feature(no_core)] #![no_core] extern crate minicore; diff --git a/tests/ui/asm/naked-functions-rustic-abi.rs b/tests/ui/asm/naked-functions-rustic-abi.rs index 99b8d2e19fe4..d9c114748288 100644 --- a/tests/ui/asm/naked-functions-rustic-abi.rs +++ b/tests/ui/asm/naked-functions-rustic-abi.rs @@ -6,7 +6,7 @@ //@ build-pass //@ needs-asm-support -#![feature(naked_functions, naked_functions_rustic_abi, rust_cold_cc)] +#![feature(naked_functions_rustic_abi, rust_cold_cc)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs index d8dc2104c76e..57ad79b1c315 100644 --- a/tests/ui/asm/naked-functions-target-feature.rs +++ b/tests/ui/asm/naked-functions-target-feature.rs @@ -1,7 +1,7 @@ //@ build-pass //@ needs-asm-support -#![feature(naked_functions, naked_functions_target_feature)] +#![feature(naked_functions_target_feature)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index c8539e806408..6dc14a6840ec 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -1,7 +1,6 @@ //@ needs-asm-support //@ compile-flags: --test -#![feature(naked_functions)] #![feature(test)] #![crate_type = "lib"] diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr index ad2041ec118b..8aab2f04ee29 100644 --- a/tests/ui/asm/naked-functions-testattrs.stderr +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -1,5 +1,5 @@ error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:11:1 + --> $DIR/naked-functions-testattrs.rs:10:1 | LL | #[test] | ------- function marked with testing attribute here @@ -7,7 +7,7 @@ LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:19:1 + --> $DIR/naked-functions-testattrs.rs:18:1 | LL | #[test] | ------- function marked with testing attribute here @@ -15,7 +15,7 @@ LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:27:1 + --> $DIR/naked-functions-testattrs.rs:26:1 | LL | #[test] | ------- function marked with testing attribute here @@ -23,7 +23,7 @@ LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes - --> $DIR/naked-functions-testattrs.rs:34:1 + --> $DIR/naked-functions-testattrs.rs:33:1 | LL | #[bench] | -------- function marked with testing attribute here diff --git a/tests/ui/asm/naked-functions-unused.aarch64.stderr b/tests/ui/asm/naked-functions-unused.aarch64.stderr index ea63ced1aab0..bfb2923b0b8d 100644 --- a/tests/ui/asm/naked-functions-unused.aarch64.stderr +++ b/tests/ui/asm/naked-functions-unused.aarch64.stderr @@ -1,5 +1,5 @@ error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:17:32 + --> $DIR/naked-functions-unused.rs:16:32 | LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` @@ -12,55 +12,55 @@ LL | #![deny(unused)] = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:17:42 + --> $DIR/naked-functions-unused.rs:16:42 | LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:28:38 + --> $DIR/naked-functions-unused.rs:27:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:28:48 + --> $DIR/naked-functions-unused.rs:27:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:36:41 + --> $DIR/naked-functions-unused.rs:35:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:36:51 + --> $DIR/naked-functions-unused.rs:35:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:40 + --> $DIR/naked-functions-unused.rs:45:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:50 + --> $DIR/naked-functions-unused.rs:45:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:54:43 + --> $DIR/naked-functions-unused.rs:53:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:54:53 + --> $DIR/naked-functions-unused.rs:53:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs index 67c05984be71..945ab1a40ad0 100644 --- a/tests/ui/asm/naked-functions-unused.rs +++ b/tests/ui/asm/naked-functions-unused.rs @@ -3,7 +3,6 @@ //@[x86_64] only-x86_64 //@[aarch64] only-aarch64 #![deny(unused)] -#![feature(naked_functions)] #![crate_type = "lib"] pub trait Trait { diff --git a/tests/ui/asm/naked-functions-unused.x86_64.stderr b/tests/ui/asm/naked-functions-unused.x86_64.stderr index ea63ced1aab0..bfb2923b0b8d 100644 --- a/tests/ui/asm/naked-functions-unused.x86_64.stderr +++ b/tests/ui/asm/naked-functions-unused.x86_64.stderr @@ -1,5 +1,5 @@ error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:17:32 + --> $DIR/naked-functions-unused.rs:16:32 | LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` @@ -12,55 +12,55 @@ LL | #![deny(unused)] = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:17:42 + --> $DIR/naked-functions-unused.rs:16:42 | LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:28:38 + --> $DIR/naked-functions-unused.rs:27:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:28:48 + --> $DIR/naked-functions-unused.rs:27:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:36:41 + --> $DIR/naked-functions-unused.rs:35:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:36:51 + --> $DIR/naked-functions-unused.rs:35:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:40 + --> $DIR/naked-functions-unused.rs:45:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:50 + --> $DIR/naked-functions-unused.rs:45:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:54:43 + --> $DIR/naked-functions-unused.rs:53:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:54:53 + --> $DIR/naked-functions-unused.rs:53:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index b433c1b5389c..1eeb716e98a1 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -2,7 +2,6 @@ //@ ignore-nvptx64 //@ ignore-spirv -#![feature(naked_functions)] #![feature(asm_unwind, linkage)] #![crate_type = "lib"] diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 2b67c3aecd73..b94a09bb92ed 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -1,107 +1,107 @@ error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:47:29 + --> $DIR/naked-functions.rs:46:29 | LL | naked_asm!("/* {0} */", in(reg) a) | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:68:10 + --> $DIR/naked-functions.rs:67:10 | LL | in(reg) a, | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `noreturn` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:88:28 + --> $DIR/naked-functions.rs:87:28 | LL | naked_asm!("", options(noreturn)); | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly error: the `nomem` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:105:28 + --> $DIR/naked-functions.rs:104:28 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:105:35 + --> $DIR/naked-functions.rs:104:35 | LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:112:28 + --> $DIR/naked-functions.rs:111:28 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:112:38 + --> $DIR/naked-functions.rs:111:38 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:112:56 + --> $DIR/naked-functions.rs:111:56 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `may_unwind` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:120:28 + --> $DIR/naked-functions.rs:119:28 | LL | naked_asm!("", options(may_unwind)); | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:151:5 + --> $DIR/naked-functions.rs:150:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:157:5 + --> $DIR/naked-functions.rs:156:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:164:16 + --> $DIR/naked-functions.rs:163:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ error[E0787]: the `asm!` macro is not allowed in naked functions - --> $DIR/naked-functions.rs:13:14 + --> $DIR/naked-functions.rs:12:14 | LL | unsafe { asm!("", options(raw)) }; | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:25:5 + --> $DIR/naked-functions.rs:24:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:27:5 + --> $DIR/naked-functions.rs:26:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:29:6 + --> $DIR/naked-functions.rs:28:6 | LL | (None | Some(_)): Option>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:31:5 + --> $DIR/naked-functions.rs:30:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:40:5 + --> $DIR/naked-functions.rs:39:5 | LL | a + 1 | ^ @@ -109,7 +109,7 @@ LL | a + 1 = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:38:1 + --> $DIR/naked-functions.rs:37:1 | LL | pub extern "C" fn inc(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | a + 1 | ----- not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:52:1 + --> $DIR/naked-functions.rs:51:1 | LL | pub extern "C" fn inc_closure(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | (|| a + 1)() | ------------ not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:58:1 + --> $DIR/naked-functions.rs:57:1 | LL | pub extern "C" fn unsupported_operands() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,13 +144,13 @@ LL | let mut e = 0usize; | ------------------- not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:80:1 + --> $DIR/naked-functions.rs:79:1 | LL | pub extern "C" fn missing_assembly() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:85:1 + --> $DIR/naked-functions.rs:84:1 | LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -159,7 +159,7 @@ LL | naked_asm!(""); | -------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:97:11 + --> $DIR/naked-functions.rs:96:11 | LL | *&y | ^ @@ -167,7 +167,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single `naked_asm!` invocation - --> $DIR/naked-functions.rs:95:5 + --> $DIR/naked-functions.rs:94:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index 6c5fdbe74d82..c3a3131ee463 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -1,7 +1,6 @@ -// Checks that #[unsafe(naked)] attribute can be placed on function definitions only. +// Checks that the #[unsafe(naked)] attribute can be placed on function definitions only. // //@ needs-asm-support -#![feature(naked_functions)] #![unsafe(naked)] //~ ERROR should be applied to a function definition use std::arch::naked_asm; @@ -14,6 +13,7 @@ extern "C" { #[unsafe(naked)] //~ ERROR should be applied to a function definition #[repr(C)] struct S { + #[unsafe(naked)] //~ ERROR should be applied to a function definition a: u32, b: u32, } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 6e2746b56843..81d30e6475d9 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -1,15 +1,24 @@ error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:14:1 + --> $DIR/naked-invalid-attr.rs:13:1 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ LL | #[repr(C)] LL | / struct S { +LL | | #[unsafe(naked)] LL | | a: u32, LL | | b: u32, LL | | } | |_- not a function definition +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:16:5 + | +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ +LL | a: u32, + | ------ not a function definition + error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:51:5 | @@ -27,7 +36,7 @@ LL | extern "C" fn invoke(&self); | ---------------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:10:5 + --> $DIR/naked-invalid-attr.rs:9:5 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ @@ -35,10 +44,10 @@ LL | fn f(); | ------- not a function definition error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:5:1 + --> $DIR/naked-invalid-attr.rs:4:1 | LL | #![unsafe(naked)] | ^^^^^^^^^^^^^^^^^ cannot be applied to crates -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index c9f335ea9506..96eed70dc550 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -1,5 +1,4 @@ //@ needs-asm-support -#![feature(naked_functions)] #![feature(fn_align)] #![crate_type = "lib"] use std::arch::naked_asm; diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index 219e32473bea..f173a39e5bf6 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -1,5 +1,5 @@ error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:7:8 + --> $DIR/naked-with-invalid-repr-attr.rs:6:8 | LL | #[repr(C)] | ^ @@ -11,7 +11,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:15:8 + --> $DIR/naked-with-invalid-repr-attr.rs:14:8 | LL | #[repr(transparent)] | ^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:23:19 + --> $DIR/naked-with-invalid-repr-attr.rs:22:19 | LL | #[repr(align(16), C)] | ^ @@ -35,7 +35,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:32:8 + --> $DIR/naked-with-invalid-repr-attr.rs:31:8 | LL | #[repr(C, packed)] | ^ @@ -48,7 +48,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct or union - --> $DIR/naked-with-invalid-repr-attr.rs:32:11 + --> $DIR/naked-with-invalid-repr-attr.rs:31:11 | LL | #[repr(C, packed)] | ^^^^^^ @@ -61,7 +61,7 @@ LL | | } | |_- not a struct or union error[E0517]: attribute should be applied to an enum - --> $DIR/naked-with-invalid-repr-attr.rs:42:8 + --> $DIR/naked-with-invalid-repr-attr.rs:41:8 | LL | #[repr(u8)] | ^^ diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index d5c194452d75..996fb82a944f 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -10,8 +10,6 @@ // which causes less readable LLVM errors and in the worst cases causes ICEs // or segfaults based on system dependent behavior and codegen flags. -#![feature(naked_functions)] - use std::arch::{asm, global_asm, naked_asm}; #[no_mangle] diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index 0120d4948d51..cd7e7a08c1d2 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -1,5 +1,5 @@ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:23:15 + --> $DIR/named-asm-labels.rs:21:15 | LL | asm!("bar: nop"); | ^^^ @@ -9,7 +9,7 @@ LL | asm!("bar: nop"); = note: `#[deny(named_asm_labels)]` on by default error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:26:15 + --> $DIR/named-asm-labels.rs:24:15 | LL | asm!("abcd:"); | ^^^^ @@ -18,7 +18,7 @@ LL | asm!("abcd:"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:29:15 + --> $DIR/named-asm-labels.rs:27:15 | LL | asm!("foo: bar1: nop"); | ^^^ @@ -27,7 +27,7 @@ LL | asm!("foo: bar1: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:29:20 + --> $DIR/named-asm-labels.rs:27:20 | LL | asm!("foo: bar1: nop"); | ^^^^ @@ -36,7 +36,7 @@ LL | asm!("foo: bar1: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:34:15 + --> $DIR/named-asm-labels.rs:32:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -45,7 +45,7 @@ LL | asm!("foo1: nop", "nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:35:15 + --> $DIR/named-asm-labels.rs:33:15 | LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ @@ -54,7 +54,7 @@ LL | asm!("foo2: foo3: nop", "nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:35:21 + --> $DIR/named-asm-labels.rs:33:21 | LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ @@ -63,7 +63,7 @@ LL | asm!("foo2: foo3: nop", "nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:38:22 + --> $DIR/named-asm-labels.rs:36:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -72,7 +72,7 @@ LL | asm!("nop", "foo4: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:39:15 + --> $DIR/named-asm-labels.rs:37:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -81,7 +81,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:39:28 + --> $DIR/named-asm-labels.rs:37:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -90,7 +90,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:15 + --> $DIR/named-asm-labels.rs:42:15 | LL | asm!("foo7: nop; foo8: nop"); | ^^^^ @@ -99,7 +99,7 @@ LL | asm!("foo7: nop; foo8: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:26 + --> $DIR/named-asm-labels.rs:42:26 | LL | asm!("foo7: nop; foo8: nop"); | ^^^^ @@ -108,7 +108,7 @@ LL | asm!("foo7: nop; foo8: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:47:15 + --> $DIR/named-asm-labels.rs:45:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -117,7 +117,7 @@ LL | asm!("foo9: nop; nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:48:20 + --> $DIR/named-asm-labels.rs:46:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -126,7 +126,7 @@ LL | asm!("nop; foo10: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:51:15 + --> $DIR/named-asm-labels.rs:49:15 | LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ @@ -135,7 +135,7 @@ LL | asm!("bar2: nop\n bar3: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:51:27 + --> $DIR/named-asm-labels.rs:49:27 | LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ @@ -144,7 +144,7 @@ LL | asm!("bar2: nop\n bar3: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:54:15 + --> $DIR/named-asm-labels.rs:52:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -153,7 +153,7 @@ LL | asm!("bar4: nop\n nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:55:21 + --> $DIR/named-asm-labels.rs:53:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -162,7 +162,7 @@ LL | asm!("nop\n bar5: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:56:21 + --> $DIR/named-asm-labels.rs:54:21 | LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ @@ -171,7 +171,7 @@ LL | asm!("nop\n bar6: bar7: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:56:27 + --> $DIR/named-asm-labels.rs:54:27 | LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ @@ -180,7 +180,7 @@ LL | asm!("nop\n bar6: bar7: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:63:13 + --> $DIR/named-asm-labels.rs:61:13 | LL | blah2: nop | ^^^^^ @@ -189,7 +189,7 @@ LL | blah2: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:64:13 + --> $DIR/named-asm-labels.rs:62:13 | LL | blah3: nop | ^^^^^ @@ -198,7 +198,7 @@ LL | blah3: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:73:19 + --> $DIR/named-asm-labels.rs:71:19 | LL | nop ; blah4: nop | ^^^^^ @@ -207,7 +207,7 @@ LL | nop ; blah4: nop = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:87:15 + --> $DIR/named-asm-labels.rs:85:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -216,7 +216,7 @@ LL | asm!("blah1: 2bar: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:90:15 + --> $DIR/named-asm-labels.rs:88:15 | LL | asm!("def: def: nop"); | ^^^ @@ -225,7 +225,7 @@ LL | asm!("def: def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:90:15 + --> $DIR/named-asm-labels.rs:88:15 | LL | asm!("def: def: nop"); | ^^^ @@ -235,7 +235,7 @@ LL | asm!("def: def: nop"); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:93:15 + --> $DIR/named-asm-labels.rs:91:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -244,7 +244,7 @@ LL | asm!("def: nop\ndef: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:93:15 + --> $DIR/named-asm-labels.rs:91:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -254,7 +254,7 @@ LL | asm!("def: nop\ndef: nop"); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:96:15 + --> $DIR/named-asm-labels.rs:94:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -263,7 +263,7 @@ LL | asm!("def: nop; def: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:96:15 + --> $DIR/named-asm-labels.rs:94:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -273,7 +273,7 @@ LL | asm!("def: nop; def: nop"); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:106:15 + --> $DIR/named-asm-labels.rs:104:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL | asm!("fooo\u{003A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:107:15 + --> $DIR/named-asm-labels.rs:105:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -291,7 +291,7 @@ LL | asm!("foooo\x3A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:110:15 + --> $DIR/named-asm-labels.rs:108:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -300,7 +300,7 @@ LL | asm!("fooooo:\u{000A} nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:111:15 + --> $DIR/named-asm-labels.rs:109:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -309,7 +309,7 @@ LL | asm!("foooooo:\x0A nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:115:14 + --> $DIR/named-asm-labels.rs:113:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -319,7 +319,7 @@ LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); = note: the label may be declared in the expansion of a macro error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:123:13 + --> $DIR/named-asm-labels.rs:121:13 | LL | ab: nop // ab: does foo | ^^ @@ -328,7 +328,7 @@ LL | ab: nop // ab: does foo = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:144:19 + --> $DIR/named-asm-labels.rs:142:19 | LL | asm!("test_{}: nop", in(reg) 10); | ^^^^^^^ @@ -338,7 +338,7 @@ LL | asm!("test_{}: nop", in(reg) 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:146:15 + --> $DIR/named-asm-labels.rs:144:15 | LL | asm!("test_{}: nop", const 10); | ^^^^^^^ @@ -348,7 +348,7 @@ LL | asm!("test_{}: nop", const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:147:15 + --> $DIR/named-asm-labels.rs:145:15 | LL | asm!("test_{}: nop", sym main); | ^^^^^^^ @@ -358,7 +358,7 @@ LL | asm!("test_{}: nop", sym main); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:148:15 + --> $DIR/named-asm-labels.rs:146:15 | LL | asm!("{}_test: nop", const 10); | ^^^^^^^ @@ -368,7 +368,7 @@ LL | asm!("{}_test: nop", const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:149:15 + --> $DIR/named-asm-labels.rs:147:15 | LL | asm!("test_{}_test: nop", const 10); | ^^^^^^^^^^^^ @@ -378,7 +378,7 @@ LL | asm!("test_{}_test: nop", const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:150:15 + --> $DIR/named-asm-labels.rs:148:15 | LL | asm!("{}: nop", const 10); | ^^ @@ -388,7 +388,7 @@ LL | asm!("{}: nop", const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:152:15 + --> $DIR/named-asm-labels.rs:150:15 | LL | asm!("{uwu}: nop", uwu = const 10); | ^^^^^ @@ -398,7 +398,7 @@ LL | asm!("{uwu}: nop", uwu = const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:153:15 + --> $DIR/named-asm-labels.rs:151:15 | LL | asm!("{0}: nop", const 10); | ^^^ @@ -408,7 +408,7 @@ LL | asm!("{0}: nop", const 10); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:154:15 + --> $DIR/named-asm-labels.rs:152:15 | LL | asm!("{1}: nop", "/* {0} */", const 10, const 20); | ^^^ @@ -418,7 +418,7 @@ LL | asm!("{1}: nop", "/* {0} */", const 10, const 20); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:157:14 + --> $DIR/named-asm-labels.rs:155:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -428,7 +428,7 @@ LL | asm!(include_str!("named-asm-labels.s")); = note: the label may be declared in the expansion of a macro error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:157:14 + --> $DIR/named-asm-labels.rs:155:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | asm!(include_str!("named-asm-labels.s")); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:157:14 + --> $DIR/named-asm-labels.rs:155:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -450,7 +450,7 @@ LL | asm!(include_str!("named-asm-labels.s")); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:157:14 + --> $DIR/named-asm-labels.rs:155:14 | LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -461,7 +461,7 @@ LL | asm!(include_str!("named-asm-labels.s")); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:171:19 + --> $DIR/named-asm-labels.rs:169:19 | LL | asm!("warned: nop"); | ^^^^^^ @@ -469,13 +469,13 @@ LL | asm!("warned: nop"); = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information note: the lint level is defined here - --> $DIR/named-asm-labels.rs:169:16 + --> $DIR/named-asm-labels.rs:167:16 | LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:180:17 + --> $DIR/named-asm-labels.rs:178:17 | LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) | ^^^^^ @@ -484,7 +484,7 @@ LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:187:20 + --> $DIR/named-asm-labels.rs:185:20 | LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } | ^^^^^ @@ -493,7 +493,7 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:195:17 + --> $DIR/named-asm-labels.rs:193:17 | LL | naked_asm!(".Laaa: nop; ret;") | ^^^^^ @@ -502,7 +502,7 @@ LL | naked_asm!(".Laaa: nop; ret;") = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:205:21 + --> $DIR/named-asm-labels.rs:203:21 | LL | naked_asm!(".Lbbb: nop; ret;") | ^^^^^ @@ -511,7 +511,7 @@ LL | naked_asm!(".Lbbb: nop; ret;") = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:214:15 + --> $DIR/named-asm-labels.rs:212:15 | LL | asm!("closure1: nop"); | ^^^^^^^^ @@ -520,7 +520,7 @@ LL | asm!("closure1: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:218:15 + --> $DIR/named-asm-labels.rs:216:15 | LL | asm!("closure2: nop"); | ^^^^^^^^ @@ -529,7 +529,7 @@ LL | asm!("closure2: nop"); = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:228:19 + --> $DIR/named-asm-labels.rs:226:19 | LL | asm!("closure3: nop"); | ^^^^^^^^ diff --git a/tests/ui/asm/simple_global_asm.rs b/tests/ui/asm/simple_global_asm.rs index 9b193b3e44ce..68b0b83858e1 100644 --- a/tests/ui/asm/simple_global_asm.rs +++ b/tests/ui/asm/simple_global_asm.rs @@ -1,7 +1,6 @@ //@ run-pass //@ needs-asm-support -#![feature(naked_functions)] #![allow(dead_code)] #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs deleted file mode 100644 index d940decd561e..000000000000 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ needs-asm-support - -use std::arch::naked_asm; -//~^ ERROR use of unstable library feature `naked_functions` - -#[naked] //~ ERROR unsafe attribute used without unsafe -//~^ ERROR the `#[naked]` attribute is an experimental feature -extern "C" fn naked() { - naked_asm!("") - //~^ ERROR use of unstable library feature `naked_functions` -} - -#[naked] //~ ERROR unsafe attribute used without unsafe -//~^ ERROR the `#[naked]` attribute is an experimental feature -extern "C" fn naked_2() -> isize { - naked_asm!("") - //~^ ERROR use of unstable library feature `naked_functions` -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr deleted file mode 100644 index ea765db7d946..000000000000 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ /dev/null @@ -1,75 +0,0 @@ -error[E0658]: use of unstable library feature `naked_functions` - --> $DIR/feature-gate-naked_functions.rs:9:5 - | -LL | naked_asm!("") - | ^^^^^^^^^ - | - = note: see issue #90957 for more information - = help: add `#![feature(naked_functions)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `naked_functions` - --> $DIR/feature-gate-naked_functions.rs:16:5 - | -LL | naked_asm!("") - | ^^^^^^^^^ - | - = note: see issue #90957 for more information - = help: add `#![feature(naked_functions)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: unsafe attribute used without unsafe - --> $DIR/feature-gate-naked_functions.rs:6:3 - | -LL | #[naked] - | ^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(naked)] - | +++++++ + - -error: unsafe attribute used without unsafe - --> $DIR/feature-gate-naked_functions.rs:13:3 - | -LL | #[naked] - | ^^^^^ usage of unsafe attribute - | -help: wrap the attribute in `unsafe(...)` - | -LL | #[unsafe(naked)] - | +++++++ + - -error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:6:1 - | -LL | #[naked] - | ^^^^^^^^ - | - = note: see issue #90957 for more information - = help: add `#![feature(naked_functions)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:13:1 - | -LL | #[naked] - | ^^^^^^^^ - | - = note: see issue #90957 for more information - = help: add `#![feature(naked_functions)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `naked_functions` - --> $DIR/feature-gate-naked_functions.rs:3:5 - | -LL | use std::arch::naked_asm; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #90957 for more information - = help: add `#![feature(naked_functions)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs index cc5b4f0e88b4..d16c6ccd4c33 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs @@ -1,7 +1,7 @@ //@ needs-asm-support //@ only-x86_64 -#![feature(naked_functions, rust_cold_cc)] +#![feature(rust_cold_cc)] use std::arch::naked_asm; diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs index b2e102f1db4b..1fee3e7dcd1a 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs @@ -1,8 +1,6 @@ //@ needs-asm-support //@ only-x86_64 -#![feature(naked_functions)] - use std::arch::naked_asm; #[unsafe(naked)] diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr index b0592d08046f..8e601a14753b 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr @@ -1,5 +1,5 @@ error[E0658]: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions - --> $DIR/feature-gate-naked_functions_target_feature.rs:9:1 + --> $DIR/feature-gate-naked_functions_target_feature.rs:7:1 | LL | #[target_feature(enable = "avx2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/inline-exported.rs b/tests/ui/lint/inline-exported.rs index 69e322ef513a..6a23cd58236f 100644 --- a/tests/ui/lint/inline-exported.rs +++ b/tests/ui/lint/inline-exported.rs @@ -2,9 +2,7 @@ //! because `#[inline]` is ignored for such functions. #![crate_type = "lib"] - #![feature(linkage)] -#![feature(naked_functions)] #![deny(unused_attributes)] #[inline] diff --git a/tests/ui/lint/inline-exported.stderr b/tests/ui/lint/inline-exported.stderr index dcf63cc4090e..05a2bda24067 100644 --- a/tests/ui/lint/inline-exported.stderr +++ b/tests/ui/lint/inline-exported.stderr @@ -1,18 +1,18 @@ error: `#[inline]` is ignored on externally exported functions - --> $DIR/inline-exported.rs:10:1 + --> $DIR/inline-exported.rs:8:1 | LL | #[inline] | ^^^^^^^^^ | = help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` note: the lint level is defined here - --> $DIR/inline-exported.rs:8:9 + --> $DIR/inline-exported.rs:6:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: `#[inline]` is ignored on externally exported functions - --> $DIR/inline-exported.rs:15:1 + --> $DIR/inline-exported.rs:13:1 | LL | #[inline] | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #[inline] = help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` error: `#[inline]` is ignored on externally exported functions - --> $DIR/inline-exported.rs:20:1 + --> $DIR/inline-exported.rs:18:1 | LL | #[inline] | ^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs index ce6d10bf33cb..a4baf1fe4b97 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -1,5 +1,4 @@ //@ needs-asm-support -#![feature(naked_functions)] use std::arch::naked_asm; diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index f89d94b67d80..d3cafbc63508 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,5 +1,5 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/error-with-naked.rs:6:1 + --> $DIR/error-with-naked.rs:5:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` @@ -8,7 +8,7 @@ LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/error-with-naked.rs:18:5 + --> $DIR/error-with-naked.rs:17:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` @@ -17,13 +17,13 @@ LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-naked.rs:6:1 + --> $DIR/error-with-naked.rs:5:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-naked.rs:18:5 + --> $DIR/error-with-naked.rs:17:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ From 2b6e845d7fbda8f2ce9780eeee7e0d9296620a98 Mon Sep 17 00:00:00 2001 From: Devkuni <155117116+detrina@users.noreply.github.com> Date: Sun, 20 Apr 2025 12:34:03 +0300 Subject: [PATCH 089/109] Update links armv7-rtems-eabihf.md --- src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md index 2791c21ee453..4961304ea1f9 100644 --- a/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md @@ -12,7 +12,7 @@ ARM targets for the [RTEMS realtime operating system](https://www.rtems.org) us The target does not support host tools. Only cross-compilation is possible. The cross-compiler toolchain can be obtained by following the installation instructions -of the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html). Additionally to the cross-compiler also a compiled BSP +of the [RTEMS Documentation](https://docs.rtems.org/docs/main/user/index.html). Additionally to the cross-compiler also a compiled BSP for a board fitting the architecture needs to be available on the host. Currently tested has been the BSP `xilinx_zynq_a9_qemu` of RTEMS 6. @@ -49,4 +49,4 @@ While basic execution of the unit test harness seems to work. However, running t ## Cross-compilation toolchains and C code Compatible C-code can be built with the RTEMS cross-compiler toolchain `arm-rtems6-gcc`. -For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html). +For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/docs/main/user/index.html). From 566dfd1a0d8c4afbe54ea060059b8f716456ea66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Mar 2025 18:18:33 +0100 Subject: [PATCH 090/109] simd intrinsics with mask: accept unsigned integer masks --- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 25 ++++----- compiler/rustc_codegen_llvm/src/intrinsic.rs | 56 ++++--------------- compiler/rustc_codegen_ssa/messages.ftl | 7 +-- compiler/rustc_codegen_ssa/src/errors.rs | 23 +------- library/core/src/intrinsics/simd.rs | 10 ++-- src/tools/miri/src/helpers.rs | 5 ++ .../simd-intrinsic-generic-gather.rs | 13 +++++ .../simd-intrinsic-generic-masked-load.rs | 13 +++++ .../simd-intrinsic-generic-masked-store.rs | 9 +++ .../simd-intrinsic-generic-scatter.rs | 9 +++ .../simd-intrinsic-generic-select.rs | 13 +++++ ...pass.rs => generic-gather-scatter-pass.rs} | 0 ...ic-gather.rs => generic-gather-scatter.rs} | 11 +--- ...r.stderr => generic-gather-scatter.stderr} | 26 +++------ tests/ui/simd/intrinsic/generic-select.rs | 5 +- tests/ui/simd/intrinsic/generic-select.stderr | 24 +++----- tests/ui/simd/masked-load-store-build-fail.rs | 8 +-- .../simd/masked-load-store-build-fail.stderr | 10 ++-- 18 files changed, 119 insertions(+), 148 deletions(-) rename tests/ui/simd/intrinsic/{generic-gather-pass.rs => generic-gather-scatter-pass.rs} (100%) rename tests/ui/simd/intrinsic/{generic-gather.rs => generic-gather-scatter.rs} (70%) rename tests/ui/simd/intrinsic/{generic-gather.stderr => generic-gather-scatter.stderr} (53%) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 8b454ab2a424..787f4cd7d41d 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -443,9 +443,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( m_len == v_len, InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); + // TODO: also support unsigned integers. match *m_elem_ty.kind() { ty::Int(_) => {} - _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }), + _ => return_error!(InvalidMonomorphization::MaskWrongElementType { + span, + name, + ty: m_elem_ty + }), } return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate())); } @@ -987,19 +992,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( assert_eq!(pointer_count - 1, ptr_count(element_ty0)); assert_eq!(underlying_ty, non_ptr(element_ty0)); - // The element type of the third argument must be a signed integer type of any width: + // The element type of the third argument must be an integer type of any width: + // TODO: also support unsigned integers. let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); match *element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 } ); } } @@ -1105,17 +1106,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: + // TODO: also support unsigned integers. match *element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 } ); } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 67135fcc3080..5c4809309b2d 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1184,18 +1184,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }}; } - /// Returns the bitwidth of the `$ty` argument if it is an `Int` type. - macro_rules! require_int_ty { - ($ty: expr, $diag: expr) => { - match $ty { - ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()), - _ => { - return_error!($diag); - } - } - }; - } - /// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type. macro_rules! require_int_or_uint_ty { ($ty: expr, $diag: expr) => { @@ -1476,9 +1464,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( m_len == v_len, InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); - let in_elem_bitwidth = require_int_ty!( + let in_elem_bitwidth = require_int_or_uint_ty!( m_elem_ty.kind(), - InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } ); let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); @@ -1499,7 +1487,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // Integer vector : let in_elem_bitwidth = require_int_or_uint_ty!( in_elem.kind(), - InvalidMonomorphization::VectorArgument { span, name, in_ty, in_elem } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem } ); let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len); @@ -1723,14 +1711,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } ); - let mask_elem_bitwidth = require_int_ty!( + let mask_elem_bitwidth = require_int_or_uint_ty!( element_ty2.kind(), - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 } ); // Alignment of T, must be a constant integer value: @@ -1825,14 +1808,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } ); - let m_elem_bitwidth = require_int_ty!( + let m_elem_bitwidth = require_int_or_uint_ty!( mask_elem.kind(), - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: values_elem, - third_arg: mask_ty, - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem } ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); @@ -1915,14 +1893,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } ); - let m_elem_bitwidth = require_int_ty!( + let m_elem_bitwidth = require_int_or_uint_ty!( mask_elem.kind(), - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: values_elem, - third_arg: mask_ty, - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem } ); let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len); @@ -2010,15 +1983,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } ); - // The element type of the third argument must be a signed integer type of any width: - let mask_elem_bitwidth = require_int_ty!( + // The element type of the third argument must be an integer type of any width: + let mask_elem_bitwidth = require_int_or_uint_ty!( element_ty2.kind(), - InvalidMonomorphization::ThirdArgElementType { - span, - name, - expected_element: element_ty2, - third_arg: arg_tys[2] - } + InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 } ); // Alignment of T, must be a constant integer value: diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 95912b016007..99a90193ecd2 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -133,8 +133,7 @@ codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: found mask element type is `{$ty}`, expected a signed integer type - .note = the mask may be widened, which only has the correct behavior for signed integers +codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorphization of `{$name}` intrinsic: expected mask element type to be an integer, found `{$ty}` codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` @@ -166,8 +165,6 @@ codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}` -codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type - codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len} codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` @@ -180,8 +177,6 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}` -codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type - codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize` .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 0b7cad0c2fd8..82a0f128443f 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1059,24 +1059,14 @@ pub enum InvalidMonomorphization<'tcx> { v_len: u64, }, - #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)] - #[note] - MaskType { + #[diag(codegen_ssa_invalid_monomorphization_mask_wrong_element_type, code = E0511)] + MaskWrongElementType { #[primary_span] span: Span, name: Symbol, ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)] - VectorArgument { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - }, - #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)] CannotReturn { #[primary_span] @@ -1099,15 +1089,6 @@ pub enum InvalidMonomorphization<'tcx> { mutability: ExpectedPointerMutability, }, - #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)] - ThirdArgElementType { - #[primary_span] - span: Span, - name: Symbol, - expected_element: Ty<'tcx>, - third_arg: Ty<'tcx>, - }, - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)] UnsupportedSymbolOfSize { #[primary_span] diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index ae6e1a779ed5..d58338dd8fd0 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -271,7 +271,7 @@ pub unsafe fn simd_shuffle(x: T, y: T, idx: U) -> V; /// /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. /// -/// `V` must be a vector of signed integers with the same length as `T` (but any element size). +/// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer. /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from @@ -292,7 +292,7 @@ pub unsafe fn simd_gather(val: T, ptr: U, mask: V) -> T; /// /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. /// -/// `V` must be a vector of signed integers with the same length as `T` (but any element size). +/// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the /// corresponding value in `val` to the pointer. @@ -316,7 +316,7 @@ pub unsafe fn simd_scatter(val: T, ptr: U, mask: V); /// /// `U` must be a pointer to the element type of `T` /// -/// `V` must be a vector of signed integers with the same length as `T` (but any element size). +/// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, read the corresponding /// pointer offset from `ptr`. @@ -339,7 +339,7 @@ pub unsafe fn simd_masked_load(mask: V, ptr: U, val: T) -> T; /// /// `U` must be a pointer to the element type of `T` /// -/// `V` must be a vector of signed integers with the same length as `T` (but any element size). +/// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, write the corresponding /// value in `val` to the pointer offset from `ptr`. @@ -523,7 +523,7 @@ pub unsafe fn simd_bitmask(x: T) -> U; /// /// `T` must be a vector. /// -/// `M` must be a signed integer vector with the same length as `T` (but any element size). +/// `M` must be an integer vector with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, select the element from /// `if_true`. If the corresponding value in `mask` is `0`, select the element from diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 12e7d0f1a62c..42f586bf6ec3 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1295,6 +1295,11 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { } pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> { + assert!( + matches!(elem.layout.ty.kind(), ty::Int(_) | ty::Uint(_)), + "SIMD mask element type must be an integer, but this is `{}`", + elem.layout.ty + ); let val = elem.to_scalar().to_int(elem.layout.size)?; interp_ok(match val { 0 => false, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs index 9bb46a3546bf..c06b36d68b90 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs @@ -29,6 +29,19 @@ pub unsafe fn gather_f32x2( simd_gather(values, pointers, mask) } +// CHECK-LABEL: @gather_f32x2_unsigned +#[no_mangle] +pub unsafe fn gather_f32x2_unsigned( + pointers: Vec2<*const f32>, + mask: Vec2, + values: Vec2, +) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_gather(values, pointers, mask) +} + // CHECK-LABEL: @gather_pf32x2 #[no_mangle] pub unsafe fn gather_pf32x2( diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs index fcc4cb5d6300..21578e67cffc 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs @@ -23,6 +23,19 @@ pub unsafe fn load_f32x2(mask: Vec2, pointer: *const f32, values: Vec2 simd_masked_load(mask, pointer, values) } +// CHECK-LABEL: @load_f32x2_unsigned +#[no_mangle] +pub unsafe fn load_f32x2_unsigned( + mask: Vec2, + pointer: *const f32, + values: Vec2, +) -> Vec2 { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}}) + simd_masked_load(mask, pointer, values) +} + // CHECK-LABEL: @load_pf32x4 #[no_mangle] pub unsafe fn load_pf32x4( diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs index 04f4a0c63829..22a8f7e54bd3 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs @@ -23,6 +23,15 @@ pub unsafe fn store_f32x2(mask: Vec2, pointer: *mut f32, values: Vec2) simd_masked_store(mask, pointer, values) } +// CHECK-LABEL: @store_f32x2_unsigned +#[no_mangle] +pub unsafe fn store_f32x2_unsigned(mask: Vec2, pointer: *mut f32, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]]) + simd_masked_store(mask, pointer, values) +} + // CHECK-LABEL: @store_pf32x4 #[no_mangle] pub unsafe fn store_pf32x4(mask: Vec4, pointer: *mut *const f32, values: Vec4<*const f32>) { diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs index 9506f8f6d3a8..0cc9e6ae59ad 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs @@ -25,6 +25,15 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2, values: V simd_scatter(values, pointers, mask) } +// CHECK-LABEL: @scatter_f32x2_unsigned +#[no_mangle] +pub unsafe fn scatter_f32x2_unsigned(pointers: Vec2<*mut f32>, mask: Vec2, values: Vec2) { + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> + // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]] + simd_scatter(values, pointers, mask) +} + // CHECK-LABEL: @scatter_pf32x2 #[no_mangle] pub unsafe fn scatter_pf32x2( diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs index 71279d9f0eac..f6531c1b23ae 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -22,6 +22,10 @@ pub struct b8x4(pub [i8; 4]); #[derive(Copy, Clone, PartialEq, Debug)] pub struct i32x4([i32; 4]); +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct u32x4([u32; 4]); + // CHECK-LABEL: @select_m8 #[no_mangle] pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 { @@ -40,6 +44,15 @@ pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 { simd_select(m, a, b) } +// CHECK-LABEL: @select_m32_unsigned +#[no_mangle] +pub unsafe fn select_m32_unsigned(m: u32x4, a: f32x4, b: f32x4) -> f32x4 { + // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{|splat \(i32 31\)}} + // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1> + // CHECK: select <4 x i1> [[B]] + simd_select(m, a, b) +} + // CHECK-LABEL: @select_bitmask #[no_mangle] pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 { diff --git a/tests/ui/simd/intrinsic/generic-gather-pass.rs b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs similarity index 100% rename from tests/ui/simd/intrinsic/generic-gather-pass.rs rename to tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs diff --git a/tests/ui/simd/intrinsic/generic-gather.rs b/tests/ui/simd/intrinsic/generic-gather-scatter.rs similarity index 70% rename from tests/ui/simd/intrinsic/generic-gather.rs rename to tests/ui/simd/intrinsic/generic-gather-scatter.rs index 118d80294830..c1de7fd1c72e 100644 --- a/tests/ui/simd/intrinsic/generic-gather.rs +++ b/tests/ui/simd/intrinsic/generic-gather-scatter.rs @@ -20,7 +20,6 @@ fn main() { let s_strided = x4([0_f32, 2., -3., 6.]); let mask = x4([-1_i32, -1, 0, -1]); - let umask = x4([0u16; 4]); let fmask = x4([0_f32; 4]); let pointer = x.as_mut_ptr(); @@ -31,11 +30,8 @@ fn main() { simd_gather(default, mask, mask); //~^ ERROR expected element type `i32` of second argument `x4` to be a pointer to the element type `f32` - simd_gather(default, pointers, umask); - //~^ ERROR expected element type `u16` of third argument `x4` to be a signed integer type - simd_gather(default, pointers, fmask); - //~^ ERROR expected element type `f32` of third argument `x4` to be a signed integer type + //~^ ERROR expected mask element type to be an integer, found `f32` } unsafe { @@ -43,10 +39,7 @@ fn main() { simd_scatter(values, mask, mask); //~^ ERROR expected element type `i32` of second argument `x4` to be a pointer to the element type `f32` of the first argument `x4`, found `i32` != `*mut f32` - simd_scatter(values, pointers, umask); - //~^ ERROR expected element type `u16` of third argument `x4` to be a signed integer type - simd_scatter(values, pointers, fmask); - //~^ ERROR expected element type `f32` of third argument `x4` to be a signed integer type + //~^ ERROR expected mask element type to be an integer, found `f32` } } diff --git a/tests/ui/simd/intrinsic/generic-gather.stderr b/tests/ui/simd/intrinsic/generic-gather-scatter.stderr similarity index 53% rename from tests/ui/simd/intrinsic/generic-gather.stderr rename to tests/ui/simd/intrinsic/generic-gather-scatter.stderr index 81e10fc98752..e1806671564b 100644 --- a/tests/ui/simd/intrinsic/generic-gather.stderr +++ b/tests/ui/simd/intrinsic/generic-gather-scatter.stderr @@ -1,39 +1,27 @@ error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `i32` of second argument `x4` to be a pointer to the element type `f32` of the first argument `x4`, found `i32` != `*_ f32` - --> $DIR/generic-gather.rs:31:9 + --> $DIR/generic-gather-scatter.rs:30:9 | LL | simd_gather(default, mask, mask); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `u16` of third argument `x4` to be a signed integer type - --> $DIR/generic-gather.rs:34:9 - | -LL | simd_gather(default, pointers, umask); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `f32` of third argument `x4` to be a signed integer type - --> $DIR/generic-gather.rs:37:9 +error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected mask element type to be an integer, found `f32` + --> $DIR/generic-gather-scatter.rs:33:9 | LL | simd_gather(default, pointers, fmask); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `i32` of second argument `x4` to be a pointer to the element type `f32` of the first argument `x4`, found `i32` != `*mut f32` - --> $DIR/generic-gather.rs:43:9 + --> $DIR/generic-gather-scatter.rs:39:9 | LL | simd_scatter(values, mask, mask); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `u16` of third argument `x4` to be a signed integer type - --> $DIR/generic-gather.rs:46:9 - | -LL | simd_scatter(values, pointers, umask); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `f32` of third argument `x4` to be a signed integer type - --> $DIR/generic-gather.rs:49:9 +error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected mask element type to be an integer, found `f32` + --> $DIR/generic-gather-scatter.rs:42:9 | LL | simd_scatter(values, pointers, fmask); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/tests/ui/simd/intrinsic/generic-select.rs b/tests/ui/simd/intrinsic/generic-select.rs index db14032f1f20..924938fd01a6 100644 --- a/tests/ui/simd/intrinsic/generic-select.rs +++ b/tests/ui/simd/intrinsic/generic-select.rs @@ -36,11 +36,8 @@ fn main() { simd_select(m8, x, x); //~^ ERROR mismatched lengths: mask length `8` != other vector length `4` - simd_select(x, x, x); - //~^ ERROR mask element type is `u32`, expected a signed integer type - simd_select(z, z, z); - //~^ ERROR mask element type is `f32`, expected a signed integer type + //~^ ERROR expected mask element type to be an integer, found `f32` simd_select(m4, 0u32, 1u32); //~^ ERROR found non-SIMD `u32` diff --git a/tests/ui/simd/intrinsic/generic-select.stderr b/tests/ui/simd/intrinsic/generic-select.stderr index b9af86515fde..36b56adcfa65 100644 --- a/tests/ui/simd/intrinsic/generic-select.stderr +++ b/tests/ui/simd/intrinsic/generic-select.stderr @@ -4,52 +4,42 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched le LL | simd_select(m8, x, x); | ^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_select` intrinsic: found mask element type is `u32`, expected a signed integer type +error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected mask element type to be an integer, found `f32` --> $DIR/generic-select.rs:39:9 | -LL | simd_select(x, x, x); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: the mask may be widened, which only has the correct behavior for signed integers - -error[E0511]: invalid monomorphization of `simd_select` intrinsic: found mask element type is `f32`, expected a signed integer type - --> $DIR/generic-select.rs:42:9 - | LL | simd_select(z, z, z); | ^^^^^^^^^^^^^^^^^^^^ - | - = note: the mask may be widened, which only has the correct behavior for signed integers error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` - --> $DIR/generic-select.rs:45:9 + --> $DIR/generic-select.rs:42:9 | LL | simd_select(m4, 0u32, 1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]` - --> $DIR/generic-select.rs:48:9 + --> $DIR/generic-select.rs:45:9 | LL | simd_select_bitmask(0u16, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` - --> $DIR/generic-select.rs:51:9 + --> $DIR/generic-select.rs:48:9 | LL | simd_select_bitmask(0u8, 1u32, 2u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]` - --> $DIR/generic-select.rs:54:9 + --> $DIR/generic-select.rs:51:9 | LL | simd_select_bitmask(0.0f32, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]` - --> $DIR/generic-select.rs:57:9 + --> $DIR/generic-select.rs:54:9 | LL | simd_select_bitmask("x", x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/tests/ui/simd/masked-load-store-build-fail.rs b/tests/ui/simd/masked-load-store-build-fail.rs index ad2de5561033..4b6cc17683c2 100644 --- a/tests/ui/simd/masked-load-store-build-fail.rs +++ b/tests/ui/simd/masked-load-store-build-fail.rs @@ -21,8 +21,8 @@ fn main() { simd_masked_load(Simd::([-1, 0, -1, -1]), arr.as_ptr(), Simd::([9; 4])); //~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd`, found `u32` != `*_ u32` - simd_masked_load(Simd::([1, 0, 1, 1]), arr.as_ptr(), default); - //~^ ERROR expected element type `u8` of third argument `Simd` to be a signed integer type + simd_masked_load(Simd::([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default); + //~^ ERROR expected mask element type to be an integer, found `f32` simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u32; 4])); //~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd`, found `u32` != `*mut u32` @@ -33,7 +33,7 @@ fn main() { simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2])); //~^ ERROR expected third argument with length 4 (same as input type `Simd`), found `Simd` with length 2 - simd_masked_store(Simd([1u32; 4]), arr.as_mut_ptr(), Simd([5u8; 4])); - //~^ ERROR expected element type `u8` of third argument `Simd` to be a signed integer type + simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4])); + //~^ ERROR expected mask element type to be an integer, found `f32` } } diff --git a/tests/ui/simd/masked-load-store-build-fail.stderr b/tests/ui/simd/masked-load-store-build-fail.stderr index d57e0aa539f5..7f09841b5971 100644 --- a/tests/ui/simd/masked-load-store-build-fail.stderr +++ b/tests/ui/simd/masked-load-store-build-fail.stderr @@ -16,11 +16,11 @@ error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected LL | simd_masked_load(Simd::([-1, 0, -1, -1]), arr.as_ptr(), Simd::([9; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of third argument `Simd` to be a signed integer type +error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected mask element type to be an integer, found `f32` --> $DIR/masked-load-store-build-fail.rs:24:9 | -LL | simd_masked_load(Simd::([1, 0, 1, 1]), arr.as_ptr(), default); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | simd_masked_load(Simd::([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd`, found `u32` != `*mut u32` --> $DIR/masked-load-store-build-fail.rs:27:9 @@ -40,10 +40,10 @@ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expecte LL | simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of third argument `Simd` to be a signed integer type +error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected mask element type to be an integer, found `f32` --> $DIR/masked-load-store-build-fail.rs:36:9 | -LL | simd_masked_store(Simd([1u32; 4]), arr.as_mut_ptr(), Simd([5u8; 4])); +LL | simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors From c7e976eb1e4ba7590efd19a29a6a1eba23eb352a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 20 Apr 2025 11:28:16 +0000 Subject: [PATCH 091/109] rustdoc-json: Improve test for auto-trait impls --- tests/rustdoc-json/impls/auto.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs index ce47d1be690f..5440301f9650 100644 --- a/tests/rustdoc-json/impls/auto.rs +++ b/tests/rustdoc-json/impls/auto.rs @@ -17,6 +17,8 @@ impl Foo { // Testing spans, so all tests below code //@ is "$.index[?(@.docs=='has span')].span.begin" "[13, 1]" //@ is "$.index[?(@.docs=='has span')].span.end" "[15, 2]" -// FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91 -// is "$.index[?(@.inner.impl.is_synthetic==true)].span" null +//@ is "$.index[?(@.docs=='has span')].inner.impl.is_synthetic" false +//@ is "$.index[?(@.inner.impl.is_synthetic==true)].span" null +//@ is "$.index[?(@.inner.impl.is_synthetic==true)].inner.impl.for.resolved_path.path" '"Foo"' +//@ is "$.index[?(@.inner.impl.is_synthetic==true)].inner.impl.trait.path" '"Bar"' pub struct Foo; From fd4a093a4e9319fa1dc6603ea4ba5a5703ef5009 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 20 Apr 2025 11:34:49 +0000 Subject: [PATCH 092/109] jsondocck: Require command is at start of line --- src/tools/jsondocck/src/main.rs | 1 + tests/rustdoc-json/fns/return_type_alias.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 79e419884c68..65ad38da98b0 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -154,6 +154,7 @@ impl CommandKind { static LINE_PATTERN: LazyLock = LazyLock::new(|| { RegexBuilder::new( r#" + ^\s* //@\s+ (?P!?) (?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) diff --git a/tests/rustdoc-json/fns/return_type_alias.rs b/tests/rustdoc-json/fns/return_type_alias.rs index 0aa1db47b7f9..c39abc758945 100644 --- a/tests/rustdoc-json/fns/return_type_alias.rs +++ b/tests/rustdoc-json/fns/return_type_alias.rs @@ -1,6 +1,6 @@ // Regression test for -///@ set foo = "$.index[?(@.name=='Foo')].id" +//@ set foo = "$.index[?(@.name=='Foo')].id" pub type Foo = i32; //@ is "$.index[?(@.name=='demo')].inner.function.sig.output.resolved_path.id" $foo From 4c20d17365e7963a178e053dfb3525f4091cc39b Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 20 Apr 2025 19:39:09 +0800 Subject: [PATCH 093/109] Add ui test emit-output-types-without-args.rs Signed-off-by: xizheyin --- .../invalid-compile-flags/emit-output-types-without-args.rs | 1 + .../emit-output-types-without-args.stderr | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 tests/ui/invalid-compile-flags/emit-output-types-without-args.rs create mode 100644 tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs new file mode 100644 index 000000000000..793931e99d9c --- /dev/null +++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs @@ -0,0 +1 @@ +//@ compile-flags: --emit diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr new file mode 100644 index 000000000000..dad81dcb13c0 --- /dev/null +++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr @@ -0,0 +1,6 @@ +error: Argument to option 'emit' missing + Usage: + --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + Comma separated list of types of output for the + compiler to emit + From 6ea0fe5fc4558ed485cab1cd21c63a0e6cd35851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sun, 20 Apr 2025 21:16:07 +0800 Subject: [PATCH 094/109] Update `libc` to 0.2.172 for std --- library/Cargo.lock | 4 ++-- library/std/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index e4f1c4ec96a3..ba5e54db95d1 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 917a470842ca..c02efd997cfc 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -35,7 +35,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false } addr2line = { version = "0.24.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.171", default-features = false, features = [ +libc = { version = "0.2.172", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } From 864a9ba928aeae3a6f6c58f1ed4daf4e0cd97a2c Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:03:16 +0100 Subject: [PATCH 095/109] Make target maintainers more easily pingable Put them all on the same line with just their GitHub handles to make it very easy to copy and paste (with ctrl-shift-v!!!) the names. We have no use for email, so I removed all the emails, we don't care about people's full names either. Co-authored-by: Thalia Archibald --- src/doc/rustc/src/platform-support/TEMPLATE.md | 3 ++- .../aarch64-nintendo-switch-freestanding.md | 6 +++--- .../src/platform-support/aarch64-unknown-teeos.md | 4 ++-- src/doc/rustc/src/platform-support/aix.md | 4 ++-- .../rustc/src/platform-support/amdgcn-amd-amdhsa.md | 2 +- src/doc/rustc/src/platform-support/android.md | 6 +++--- src/doc/rustc/src/platform-support/apple-darwin.md | 4 ++-- src/doc/rustc/src/platform-support/apple-ios-macabi.md | 6 +++--- src/doc/rustc/src/platform-support/apple-ios.md | 6 +++--- src/doc/rustc/src/platform-support/apple-tvos.md | 4 ++-- src/doc/rustc/src/platform-support/apple-visionos.md | 4 ++-- src/doc/rustc/src/platform-support/apple-watchos.md | 8 ++++---- .../rustc/src/platform-support/arm64e-apple-darwin.md | 2 +- src/doc/rustc/src/platform-support/arm64e-apple-ios.md | 2 +- .../rustc/src/platform-support/arm64e-apple-tvos.md | 2 +- .../src/platform-support/arm64ec-pc-windows-msvc.md | 2 +- .../platform-support/armeb-unknown-linux-gnueabi.md | 3 ++- src/doc/rustc/src/platform-support/armv4t-none-eabi.md | 4 ++-- .../rustc/src/platform-support/armv5te-none-eabi.md | 2 +- .../rustc/src/platform-support/armv6k-nintendo-3ds.md | 6 +++--- .../rustc/src/platform-support/armv7-rtems-eabihf.md | 2 +- .../platform-support/armv7-sony-vita-newlibeabihf.md | 6 +++--- .../platform-support/armv7-unknown-linux-uclibceabi.md | 2 +- .../armv7-unknown-linux-uclibceabihf.md | 4 ++-- src/doc/rustc/src/platform-support/armv7r-none-eabi.md | 2 +- .../rustc/src/platform-support/armv8r-none-eabihf.md | 2 +- src/doc/rustc/src/platform-support/avr-none.md | 2 +- .../platform-support/csky-unknown-linux-gnuabiv2.md | 2 +- src/doc/rustc/src/platform-support/esp-idf.md | 6 +++--- src/doc/rustc/src/platform-support/freebsd.md | 4 ++-- src/doc/rustc/src/platform-support/fuchsia.md | 6 ++++-- src/doc/rustc/src/platform-support/hermit.md | 4 ++-- .../src/platform-support/hexagon-unknown-linux-musl.md | 2 +- .../src/platform-support/hexagon-unknown-none-elf.md | 2 +- src/doc/rustc/src/platform-support/hurd.md | 2 +- .../rustc/src/platform-support/i686-apple-darwin.md | 4 ++-- src/doc/rustc/src/platform-support/illumos.md | 4 ++-- src/doc/rustc/src/platform-support/kmc-solid.md | 4 ++-- src/doc/rustc/src/platform-support/loongarch-linux.md | 8 ++++---- src/doc/rustc/src/platform-support/loongarch-none.md | 4 ++-- .../src/platform-support/m68k-unknown-linux-gnu.md | 6 +++--- .../src/platform-support/m68k-unknown-none-elf.md | 4 ++-- .../rustc/src/platform-support/mips-mti-none-elf.md | 2 +- src/doc/rustc/src/platform-support/mips-release-6.md | 8 ++++---- .../src/platform-support/mips64-openwrt-linux-musl.md | 3 ++- src/doc/rustc/src/platform-support/mipsel-sony-psx.md | 2 +- .../src/platform-support/mipsel-unknown-linux-gnu.md | 2 +- src/doc/rustc/src/platform-support/netbsd.md | 9 ++++++--- src/doc/rustc/src/platform-support/nto-qnx.md | 8 ++++---- src/doc/rustc/src/platform-support/nuttx.md | 2 +- .../rustc/src/platform-support/nvptx64-nvidia-cuda.md | 4 ++-- src/doc/rustc/src/platform-support/openbsd.md | 7 +++++-- src/doc/rustc/src/platform-support/openharmony.md | 4 ++-- .../platform-support/powerpc-unknown-linux-muslspe.md | 2 +- .../platform-support/powerpc64-unknown-linux-musl.md | 6 +++--- .../platform-support/powerpc64le-unknown-linux-gnu.md | 4 ++-- .../platform-support/powerpc64le-unknown-linux-musl.md | 6 +++--- src/doc/rustc/src/platform-support/redox.md | 2 +- .../src/platform-support/riscv32e-unknown-none-elf.md | 2 +- .../src/platform-support/riscv32im-risc0-zkvm-elf.md | 6 +++--- .../platform-support/riscv32imac-unknown-xous-elf.md | 2 +- .../platform-support/riscv64gc-unknown-linux-gnu.md | 8 ++++---- .../platform-support/riscv64gc-unknown-linux-musl.md | 4 ++-- .../src/platform-support/s390x-unknown-linux-gnu.md | 4 ++-- .../src/platform-support/s390x-unknown-linux-musl.md | 2 +- src/doc/rustc/src/platform-support/solaris.md | 2 +- .../src/platform-support/sparc-unknown-none-elf.md | 2 +- src/doc/rustc/src/platform-support/trusty.md | 6 ++---- .../rustc/src/platform-support/unikraft-linux-musl.md | 2 +- src/doc/rustc/src/platform-support/unknown-uefi.md | 4 ++-- src/doc/rustc/src/platform-support/uwp-windows-msvc.md | 2 +- src/doc/rustc/src/platform-support/vxworks.md | 2 +- .../src/platform-support/wasm32-unknown-emscripten.md | 4 ++-- .../src/platform-support/wasm32-unknown-unknown.md | 2 +- .../rustc/src/platform-support/wasm32-wali-linux.md | 2 +- .../src/platform-support/wasm32-wasip1-threads.md | 8 ++++---- src/doc/rustc/src/platform-support/wasm32-wasip1.md | 2 +- src/doc/rustc/src/platform-support/wasm32-wasip2.md | 4 ++-- src/doc/rustc/src/platform-support/wasm32v1-none.md | 4 ++-- .../src/platform-support/wasm64-unknown-unknown.md | 2 +- src/doc/rustc/src/platform-support/win7-windows-gnu.md | 2 +- .../rustc/src/platform-support/win7-windows-msvc.md | 2 +- src/doc/rustc/src/platform-support/windows-gnullvm.md | 4 ++-- .../platform-support/x86_64-fortanix-unknown-sgx.md | 10 ++++++---- src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md | 2 +- .../src/platform-support/x86_64-unknown-linux-none.md | 2 +- .../rustc/src/platform-support/x86_64-unknown-none.md | 4 ++-- .../rustc/src/platform-support/x86_64h-apple-darwin.md | 2 +- src/doc/rustc/src/platform-support/xtensa.md | 4 ++-- 89 files changed, 176 insertions(+), 165 deletions(-) diff --git a/src/doc/rustc/src/platform-support/TEMPLATE.md b/src/doc/rustc/src/platform-support/TEMPLATE.md index 96c79973a163..f523237ab06f 100644 --- a/src/doc/rustc/src/platform-support/TEMPLATE.md +++ b/src/doc/rustc/src/platform-support/TEMPLATE.md @@ -6,7 +6,8 @@ One-sentence description of the target (e.g. CPU, OS) ## Target maintainers -- Some Person, https://github.com/... +[@Ghost](https://github.com/Ghost) +[@octocat](https://github.com/octocat) ## Requirements diff --git a/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md index 308e1fe2f92a..6951d7f23f8d 100644 --- a/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md +++ b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md @@ -4,10 +4,10 @@ Nintendo Switch with pure-Rust toolchain. -## Designated Developers +## Target Maintainers -* [@leo60228](https://github.com/leo60228) -* [@jam1garner](https://github.com/jam1garner) +[@leo60228](https://github.com/leo60228) +[@jam1garner](https://github.com/jam1garner) ## Requirements diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md index e2f2379ec440..be11d0cdd103 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md @@ -20,8 +20,8 @@ TEEOS is open source in progress. [MORE about](https://gitee.com/opentrustee-gro ## Target maintainers -- Petrochenkov Vadim -- Sword-Destiny +[@petrochenkov](https://github.com/petrochenkov) +[@Sword-Destiny](https://github.com/Sword-Destiny) ## Setup We use OpenHarmony SDK for TEEOS. diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md index 5a198062b952..3002a5c4b2cd 100644 --- a/src/doc/rustc/src/platform-support/aix.md +++ b/src/doc/rustc/src/platform-support/aix.md @@ -6,8 +6,8 @@ Rust for AIX operating system, currently only 64-bit PowerPC is supported. ## Target maintainers -- David Tenty `daltenty@ibm.com`, https://github.com/daltenty -- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr +[@daltenty](https://github.com/daltenty) +[@gilamn5tr](https://github.com/gilamn5tr) ## Requirements diff --git a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md index 0b2f798e66de..16152dd2dad5 100644 --- a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md +++ b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md @@ -6,7 +6,7 @@ AMD GPU target for compute/HSA (Heterogeneous System Architecture). ## Target maintainers -- [@Flakebi](https://github.com/Flakebi) +[@Flakebi](https://github.com/Flakebi) ## Requirements diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md index 54e7ddca32aa..a54288f8f050 100644 --- a/src/doc/rustc/src/platform-support/android.md +++ b/src/doc/rustc/src/platform-support/android.md @@ -8,9 +8,9 @@ ## Target maintainers -- Chris Wailes ([@chriswailes](https://github.com/chriswailes)) -- Matthew Maurer ([@maurer](https://github.com/maurer)) -- Martin Geisler ([@mgeisler](https://github.com/mgeisler)) +[@chriswailes](https://github.com/chriswailes) +[@maurer](https://github.com/maurer) +[@mgeisler](https://github.com/mgeisler) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md index 22c54d04b1eb..e41aee9bdb24 100644 --- a/src/doc/rustc/src/platform-support/apple-darwin.md +++ b/src/doc/rustc/src/platform-support/apple-darwin.md @@ -9,8 +9,8 @@ Apple macOS targets. ## Target maintainers -- [@thomcc](https://github.com/thomcc) -- [@madsmtm](https://github.com/madsmtm) +[@thomcc](https://github.com/thomcc) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md index 79966d908d89..d4b71dbd4f49 100644 --- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md +++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md @@ -9,9 +9,9 @@ Apple Mac Catalyst targets. ## Target maintainers -- [@badboy](https://github.com/badboy) -- [@BlackHoleFox](https://github.com/BlackHoleFox) -- [@madsmtm](https://github.com/madsmtm) +[@badboy](https://github.com/badboy) +[@BlackHoleFox](https://github.com/BlackHoleFox) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md index 7f5dc361c49d..64325554ab60 100644 --- a/src/doc/rustc/src/platform-support/apple-ios.md +++ b/src/doc/rustc/src/platform-support/apple-ios.md @@ -15,9 +15,9 @@ Apple iOS / iPadOS targets. ## Target maintainers -- [@badboy](https://github.com/badboy) -- [@deg4uss3r](https://github.com/deg4uss3r) -- [@madsmtm](https://github.com/madsmtm) +[@badboy](https://github.com/badboy) +[@deg4uss3r](https://github.com/deg4uss3r) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index fc46db20074f..193d64666121 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -10,8 +10,8 @@ Apple tvOS targets. ## Target maintainers -- [@thomcc](https://github.com/thomcc) -- [@madsmtm](https://github.com/madsmtm) +[@thomcc](https://github.com/thomcc) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md index 7cf9549227d9..ed96912da7a4 100644 --- a/src/doc/rustc/src/platform-support/apple-visionos.md +++ b/src/doc/rustc/src/platform-support/apple-visionos.md @@ -9,8 +9,8 @@ Apple visionOS / xrOS targets. ## Target maintainers -- [@agg23](https://github.com/agg23) -- [@madsmtm](https://github.com/madsmtm) +[@agg23](https://github.com/agg23) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/apple-watchos.md b/src/doc/rustc/src/platform-support/apple-watchos.md index 7b12d9ebfd4b..6ac09d0d1e53 100644 --- a/src/doc/rustc/src/platform-support/apple-watchos.md +++ b/src/doc/rustc/src/platform-support/apple-watchos.md @@ -12,10 +12,10 @@ Apple watchOS targets. ## Target maintainers -- [@deg4uss3r](https://github.com/deg4uss3r) -- [@vladimir-ea](https://github.com/vladimir-ea) -- [@leohowell](https://github.com/leohowell) -- [@madsmtm](https://github.com/madsmtm) +[@deg4uss3r](https://github.com/deg4uss3r) +[@vladimir-ea](https://github.com/vladimir-ea) +[@leohowell](https://github.com/leohowell) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md index 3200b7ae1b6e..2043b3421053 100644 --- a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md +++ b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md @@ -6,7 +6,7 @@ ARM64e macOS (11.0+, Big Sur+) ## Target maintainers -- Artyom Tetyukhin ([@arttet](https://github.com/arttet)) +[@arttet](https://github.com/arttet) ## Requirements diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md index aa99276a68fd..a2b09e077282 100644 --- a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md +++ b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md @@ -6,7 +6,7 @@ ARM64e iOS (14.0+) ## Target maintainers -- Artyom Tetyukhin ([@arttet](https://github.com/arttet)) +[@arttet](https://github.com/arttet) ## Requirements diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md index 332ea750f208..36588c5a9643 100644 --- a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md +++ b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md @@ -6,7 +6,7 @@ ARM64e tvOS (10.0+) ## Target maintainers -- Artyom Tetyukhin ([@arttet](https://github.com/arttet)) +[@arttet](https://github.com/arttet) ## Requirements diff --git a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md index 67903ae64014..d02043b2ae9e 100644 --- a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md +++ b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md @@ -7,7 +7,7 @@ applications on AArch64 Windows 11. See +[@Patryk27](https://github.com/Patryk27) ## Requirements diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index f749b37aa7a8..e69d606ccd2f 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -22,7 +22,7 @@ other links: ## Target maintainers -* [@Dirreke](https://github.com/Dirreke) +[@Dirreke](https://github.com/Dirreke) ## Requirements diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md index 91d7d66627d0..baf42ab29a66 100644 --- a/src/doc/rustc/src/platform-support/esp-idf.md +++ b/src/doc/rustc/src/platform-support/esp-idf.md @@ -6,9 +6,9 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram ## Target maintainers -- Ivan Markov [@ivmarkov](https://github.com/ivmarkov) -- Scott Mabin [@MabezDev](https://github.com/MabezDev) -- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez) +[@ivmarkov](https://github.com/ivmarkov) +[@MabezDev](https://github.com/MabezDev) +[@SergioGasquez](https://github.com/SergioGasquez) ## Requirements diff --git a/src/doc/rustc/src/platform-support/freebsd.md b/src/doc/rustc/src/platform-support/freebsd.md index 9d34d3649208..9d7218b258ec 100644 --- a/src/doc/rustc/src/platform-support/freebsd.md +++ b/src/doc/rustc/src/platform-support/freebsd.md @@ -6,8 +6,8 @@ ## Target maintainers -- Alan Somers `asomers@FreeBSD.org`, https://github.com/asomers -- Mikael Urankar `mikael@FreeBSD.org`, https://github.com/MikaelUrankar +[@asomers](https://github.com/asomers) +[@MikaelUrankar](https://github.com/MikaelUrankar) ## Requirements diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index bed5b81adc5b..e2befc5d9955 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -7,9 +7,11 @@ updatable, and performant. ## Target maintainers -See [`fuchsia.toml`] in the `team` repository for current target maintainers. +[@erickt](https://github.com/erickt) +[@Nashenas88](https://github.com/Nashenas88) -[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml +The up-to-date list can be also found via the +[fuchsia marker team](https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml). ## Table of contents diff --git a/src/doc/rustc/src/platform-support/hermit.md b/src/doc/rustc/src/platform-support/hermit.md index df7bc495fce8..069c253bd38a 100644 --- a/src/doc/rustc/src/platform-support/hermit.md +++ b/src/doc/rustc/src/platform-support/hermit.md @@ -14,8 +14,8 @@ Target triplets available so far: ## Target maintainers -- Stefan Lankes ([@stlankes](https://github.com/stlankes)) -- Martin Kröning ([@mkroening](https://github.com/mkroening)) +[@stlankes](https://github.com/stlankes) +[@mkroening](https://github.com/mkroening) ## Requirements diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md index cfd2b2bac9cc..be6e17883f4e 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md @@ -11,7 +11,7 @@ DSP architecture. ## Target maintainers -- [Brian Cain](https://github.com/androm3da), `bcain@quicinc.com` +[@androm3da](https://github.com/androm3da) ## Requirements The target is cross-compiled. This target supports `std`. By default, code diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md index c7726eacaf4e..b07b0bb08d60 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md @@ -10,7 +10,7 @@ Rust for baremetal Hexagon DSPs. ## Target maintainers -- [Brian Cain](https://github.com/androm3da), `bcain@quicinc.com` +[@androm3da](https://github.com/androm3da) ## Requirements diff --git a/src/doc/rustc/src/platform-support/hurd.md b/src/doc/rustc/src/platform-support/hurd.md index 2521f79dc5e6..6ecde1db5111 100644 --- a/src/doc/rustc/src/platform-support/hurd.md +++ b/src/doc/rustc/src/platform-support/hurd.md @@ -6,7 +6,7 @@ ## Target maintainers -- Samuel Thibault, `samuel.thibault@ens-lyon.org`, https://github.com/sthibaul/ +[@sthibaul](https://github.com/sthibaul) ## Requirements diff --git a/src/doc/rustc/src/platform-support/i686-apple-darwin.md b/src/doc/rustc/src/platform-support/i686-apple-darwin.md index abb64dcc986d..5f18a5e271ac 100644 --- a/src/doc/rustc/src/platform-support/i686-apple-darwin.md +++ b/src/doc/rustc/src/platform-support/i686-apple-darwin.md @@ -4,8 +4,8 @@ Apple macOS on 32-bit x86. ## Target maintainers -- [@thomcc](https://github.com/thomcc) -- [@madsmtm](https://github.com/madsmtm) +[@thomcc](https://github.com/thomcc) +[@madsmtm](https://github.com/madsmtm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/illumos.md b/src/doc/rustc/src/platform-support/illumos.md index dd2ae90f6741..c03238269d37 100644 --- a/src/doc/rustc/src/platform-support/illumos.md +++ b/src/doc/rustc/src/platform-support/illumos.md @@ -7,8 +7,8 @@ including advanced system debugging, next generation filesystem, networking, and ## Target maintainers -- Joshua M. Clulow ([@jclulow](https://github.com/jclulow)) -- Patrick Mooney ([@pfmooney](https://github.com/pfmooney)) +[@jclulow](https://github.com/jclulow) +[@pfmooney](https://github.com/pfmooney) ## Requirements diff --git a/src/doc/rustc/src/platform-support/kmc-solid.md b/src/doc/rustc/src/platform-support/kmc-solid.md index 44f47927286d..838662a3741a 100644 --- a/src/doc/rustc/src/platform-support/kmc-solid.md +++ b/src/doc/rustc/src/platform-support/kmc-solid.md @@ -14,9 +14,9 @@ The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARC | `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` | | `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` | -## Designated Developers +## Target Maintainers -- [@kawadakk](https://github.com/kawadakk) +[@kawadakk](https://github.com/kawadakk) ## Requirements diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index 2c9f712ce829..817d3a892303 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -22,10 +22,10 @@ Reference material: ## Target maintainers -- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn` -- [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` -- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` -- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` +[@heiher](https://github.com/heiher) +[@xiangzhai](https://github.com/xiangzhai) +[@zhaixiaojuan](https://github.com/zhaixiaojuan) +[@xen0n](https://github.com/xen0n) ## Requirements diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md index 6c5d86698301..a2bd6e5734cd 100644 --- a/src/doc/rustc/src/platform-support/loongarch-none.md +++ b/src/doc/rustc/src/platform-support/loongarch-none.md @@ -11,8 +11,8 @@ Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, e ## Target maintainers -- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn` -- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` +[@heiher](https://github.com/heiher) +[@xen0n](https://github.com/xen0n) ## Requirements diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md index b18a125f3b09..1efea86df92b 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md @@ -4,10 +4,10 @@ Motorola 680x0 Linux -## Designated Developers +## Target Maintainers -* [@glaubitz](https://github.com/glaubitz) -* [@ricky26](https://github.com/ricky26) +[@glaubitz](https://github.com/glaubitz) +[@ricky26](https://github.com/ricky26) ## Requirements diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md index 92780cb5a5ca..e390ba0aee96 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md @@ -4,9 +4,9 @@ Bare metal Motorola 680x0 -## Designated Developers +## Target Maintainers -* [@knickish](https://github.com/knickish) +[@knickish](https://github.com/knickish) ## Requirements diff --git a/src/doc/rustc/src/platform-support/mips-mti-none-elf.md b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md index 731f0a8c42f1..c060ebf7c7e0 100644 --- a/src/doc/rustc/src/platform-support/mips-mti-none-elf.md +++ b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md @@ -9,7 +9,7 @@ MIPS32r2 baremetal softfloat, Big Endian or Little Endian. ## Target maintainers -- YunQiang Su, `syq@debian.org`, https://github.com/wzssyqa +[@wzssyqa](https://github.com/wzssyqa) ## Background diff --git a/src/doc/rustc/src/platform-support/mips-release-6.md b/src/doc/rustc/src/platform-support/mips-release-6.md index b779477996d5..77f495751c15 100644 --- a/src/doc/rustc/src/platform-support/mips-release-6.md +++ b/src/doc/rustc/src/platform-support/mips-release-6.md @@ -16,10 +16,10 @@ The target name follow this format: `--`, where ## Target Maintainers -- [Xuan Chen](https://github.com/chenx97) -- [Walter Ji](https://github.com/709924470) -- [Xinhui Yang](https://github.com/Cyanoxygen) -- [Lain Yang](https://github.com/Fearyncess) +[@chenx97](https://github.com/chenx97) +[@709924470](https://github.com/709924470) +[@Cyanoxygen](https://github.com/Cyanoxygen) +[@Fearyncess](https://github.com/Fearyncess) ## Requirements diff --git a/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md b/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md index 07470eef051d..2ad33c9e20de 100644 --- a/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md +++ b/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md @@ -2,7 +2,8 @@ **Tier: 3** ## Target maintainers -- Donald Hoskins `grommish@gmail.com`, https://github.com/Itus-Shield + +[@Itus-Shield](https://github.com/Itus-Shield) ## Requirements This target is cross-compiled. There is no support for `std`. There is no diff --git a/src/doc/rustc/src/platform-support/mipsel-sony-psx.md b/src/doc/rustc/src/platform-support/mipsel-sony-psx.md index 589100e8888b..2343df227f5d 100644 --- a/src/doc/rustc/src/platform-support/mipsel-sony-psx.md +++ b/src/doc/rustc/src/platform-support/mipsel-sony-psx.md @@ -6,7 +6,7 @@ Sony PlayStation 1 (psx) ## Designated Developer -* [@ayrtonm](https://github.com/ayrtonm) +[@ayrtonm](https://github.com/ayrtonm) ## Requirements diff --git a/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md index b1ee8728c020..eed0ce4437ac 100644 --- a/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md @@ -6,7 +6,7 @@ Little-endian 32 bit MIPS for Linux with `glibc. ## Target maintainers -- [@LukasWoodtli](https://github.com/LukasWoodtli) +[@LukasWoodtli](https://github.com/LukasWoodtli) ## Requirements diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index 5c2ce0ee9005..9040ef637be3 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -31,9 +31,12 @@ are built for NetBSD 9.x, although some exceptions exist (some are built for NetBSD 8.x but also work on newer OS versions). -## Designated Developers +## Target Maintainers + +[@he32](https://github.com/he32) + +Further contacts: -- [@he32](https://github.com/he32), `he@NetBSD.org` - [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself @@ -46,7 +49,7 @@ bug reporting system. The `x86_64-unknown-netbsd` artifacts is being distributed by the rust project. -The other targets are built by the designated developers (see above), +The other targets are built by the target maintainers (see above), and the targets are initially cross-compiled, but many if not most of them are also built natively as part of testing. diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index e097d32277d3..9f8960899c16 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -13,10 +13,10 @@ and [QNX][qnx.com]. ## Target maintainers -- Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb -- Tristan Roach, `TRoach@blackberry.com`, https://github.com/gh-tr -- Jonathan Pallant `Jonathan.Pallant@ferrous-systems.com`, https://github.com/jonathanpallant -- Jorge Aparicio `Jorge.Aparicio@ferrous-systems.com`, https://github.com/japaric +[@flba-eb](https://github.com/flba-eb) +[@gh-tr](https://github.com/gh-tr) +[@jonathanpallant](https://github.com/jonathanpallant) +[@japaric](https://github.com/japaric) ## Requirements diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md index f76fe0887b5d..df3f4e7b394e 100644 --- a/src/doc/rustc/src/platform-support/nuttx.md +++ b/src/doc/rustc/src/platform-support/nuttx.md @@ -12,7 +12,7 @@ For brevity, many parts of the documentation will refer to Apache NuttX as simpl ## Target maintainers -- Qi Huang [@no1wudi](https://github.com/no1wudi) +[@no1wudi](https://github.com/no1wudi) ## Requirements 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 ab8641ff69ae..106ec562bfc7 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -7,8 +7,8 @@ platform. ## Target maintainers -- Riccardo D'Ambrosio, https://github.com/RDambrosio016 -- Kjetil Kjeka, https://github.com/kjetilkjeka +[@RDambrosio016](https://github.com/RDambrosio016) +[@kjetilkjeka](https://github.com/kjetilkjeka) $DIR/dont-probe-missing-item-name-2.rs:8:12 + | +LL | fn test>() {} + | ^^^------------------ help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/dont-probe-missing-item-name-2.rs:1:7 + | +LL | trait Foo { + | ^^^ + +error[E0220]: associated type `Assoc` not found for `Foo` + --> $DIR/dont-probe-missing-item-name-2.rs:8:21 + | +LL | fn test>() {} + | ^^^^^ associated type `Assoc` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs new file mode 100644 index 000000000000..db39bb354379 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs @@ -0,0 +1,11 @@ +trait Trait { + fn method() -> impl Sized; +} + +// Ensure that we don't try to probe the name of the RPITIT when looking for +// fixes to suggest for the missing associated type's trait path below. + +fn foo() -> i32::Assoc {} +//~^ ERROR ambiguous associated type + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr new file mode 100644 index 000000000000..f30d0228a3c8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/dont-probe-missing-item-name-3.rs:8:13 + | +LL | fn foo() -> i32::Assoc {} + | ^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Assoc` implemented for `i32`, you could use the fully-qualified path + | +LL - fn foo() -> i32::Assoc {} +LL + fn foo() -> ::Assoc {} + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0223`. From de9323973a4dd9e76fadd250c2ac13ecddb4374c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 19 Apr 2025 18:11:57 +0200 Subject: [PATCH 097/109] remove a couple clones --- compiler/rustc_builtin_macros/src/autodiff.rs | 10 ++++------ compiler/rustc_mir_build/src/builder/scope.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index daebd516499b..e60efdbefd92 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -596,15 +596,14 @@ mod llvm_enzyme { } }; let arg = ty.kind.is_simple_path().unwrap(); - let sl: Vec = vec![arg, kw::Default]; - let tmp = ecx.def_site_path(&sl); + let tmp = ecx.def_site_path(&[arg, kw::Default]); let default_call_expr = ecx.expr_path(ecx.path(span, tmp)); let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); body.stmts.push(ecx.stmt_expr(default_call_expr)); return body; } - let mut exprs: P = primal_call.clone(); + let mut exprs: P = primal_call; let d_ret_ty = match d_sig.decl.output { FnRetTy::Ty(ref ty) => ty.clone(), FnRetTy::Default(span) => { @@ -622,7 +621,7 @@ mod llvm_enzyme { // type due to the Const return activity. exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]); } else { - let q = QSelf { ty: d_ret_ty.clone(), path_span: span, position: 0 }; + let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 }; let y = ExprKind::Path(Some(P(q)), ecx.path_ident(span, Ident::from_str("default"))); let default_call_expr = ecx.expr(span, y); @@ -640,8 +639,7 @@ mod llvm_enzyme { let mut exprs2 = thin_vec![exprs]; for arg in args.iter().skip(1) { let arg = arg.kind.is_simple_path().unwrap(); - let sl: Vec = vec![arg, kw::Default]; - let tmp = ecx.def_site_path(&sl); + let tmp = ecx.def_site_path(&[arg, kw::Default]); let default_call_expr = ecx.expr_path(ecx.path(span, tmp)); let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index e42336a1dbbc..4e4b11b8fa6b 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1530,7 +1530,7 @@ fn build_scope_drops<'tcx>( // path, then don't generate the drop. (We only take this into // account for non-unwind paths so as not to disturb the // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { + if scope.moved_locals.contains(&local) { continue; } From bf8ce32558a4657d077a6761eaa293d0645c2e16 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 16 Apr 2025 16:13:50 +1000 Subject: [PATCH 098/109] Remove `token::{Open,Close}Delim`. By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`. PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing with delimiters. It also makes `ast::TokenKind` more similar to `parser::TokenType`. This requires a few new methods: - `TokenKind::is_{,open_,close_}delim()` replace various kinds of pattern matches. - `Delimiter::as_{open,close}_token_kind` are used to convert `Delimiter` values to `TokenKind`. Despite these additions, it's a net reduction in lines of code. This is because e.g. `token::OpenParen` is so much shorter than `token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms reduce to single line forms. And many places where the number of lines doesn't change are still easier to read, just because the names are shorter, e.g.: ``` - } else if self.token != token::CloseDelim(Delimiter::Brace) { + } else if self.token != token::CloseBrace { ``` --- compiler/rustc_ast/src/attr/mod.rs | 5 +- compiler/rustc_ast/src/token.rs | 131 ++++++++++++++---- compiler/rustc_ast_pretty/src/pprust/state.rs | 19 ++- compiler/rustc_attr_parsing/src/parser.rs | 4 +- compiler/rustc_expand/src/config.rs | 5 +- compiler/rustc_expand/src/expand.rs | 5 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 6 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 4 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 24 ++-- compiler/rustc_expand/src/mbe/quoted.rs | 8 +- .../rustc_expand/src/proc_macro_server.rs | 4 +- compiler/rustc_parse/src/lexer/mod.rs | 12 +- compiler/rustc_parse/src/lexer/tokentrees.rs | 85 ++++++------ .../rustc_parse/src/lexer/unicode_chars.rs | 14 +- .../rustc_parse/src/parser/attr_wrapper.rs | 44 +++--- .../rustc_parse/src/parser/diagnostics.rs | 83 +++++------ compiler/rustc_parse/src/parser/expr.rs | 91 ++++++------ compiler/rustc_parse/src/parser/generics.rs | 5 +- compiler/rustc_parse/src/parser/item.rs | 56 ++++---- compiler/rustc_parse/src/parser/mod.rs | 124 +++++++---------- .../rustc_parse/src/parser/nonterminal.rs | 14 +- compiler/rustc_parse/src/parser/pat.rs | 49 ++++--- compiler/rustc_parse/src/parser/path.rs | 11 +- compiler/rustc_parse/src/parser/stmt.rs | 33 ++--- compiler/rustc_parse/src/parser/tests.rs | 60 +++----- compiler/rustc_parse/src/parser/token_type.rs | 24 +--- compiler/rustc_parse/src/parser/ty.rs | 12 +- src/librustdoc/clean/render_macro_matchers.rs | 4 +- src/tools/rustfmt/src/macros.rs | 12 +- src/tools/rustfmt/src/parse/macros/cfg_if.rs | 6 +- 30 files changed, 456 insertions(+), 498 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d656d9b0b8af..3f0b9ea41389 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -416,10 +416,7 @@ impl MetaItem { // This path is currently unreachable in the test suite. unreachable!() } - Some(TokenTree::Token( - Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, - _, - )) => { + Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt); } _ => return None, diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 055481f5d878..54781e8235e2 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -32,6 +32,18 @@ pub enum InvisibleOrigin { ProcMacro, } +impl InvisibleOrigin { + // Should the parser skip these invisible delimiters? Ideally this function + // will eventually disappear and no invisible delimiters will be skipped. + #[inline] + pub fn skip(&self) -> bool { + match self { + InvisibleOrigin::MetaVar(_) => false, + InvisibleOrigin::ProcMacro => true, + } + } +} + impl PartialEq for InvisibleOrigin { #[inline] fn eq(&self, _other: &InvisibleOrigin) -> bool { @@ -125,8 +137,7 @@ impl Delimiter { pub fn skip(&self) -> bool { match self { Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false, - Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false, - Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true, + Delimiter::Invisible(origin) => origin.skip(), } } @@ -140,6 +151,24 @@ impl Delimiter { _ => false, } } + + pub fn as_open_token_kind(&self) -> TokenKind { + match *self { + Delimiter::Parenthesis => OpenParen, + Delimiter::Brace => OpenBrace, + Delimiter::Bracket => OpenBracket, + Delimiter::Invisible(origin) => OpenInvisible(origin), + } + } + + pub fn as_close_token_kind(&self) -> TokenKind { + match *self { + Delimiter::Parenthesis => CloseParen, + Delimiter::Brace => CloseBrace, + Delimiter::Bracket => CloseBracket, + Delimiter::Invisible(origin) => CloseInvisible(origin), + } + } } // Note that the suffix is *not* considered when deciding the `LitKind` in this @@ -194,9 +223,9 @@ impl Lit { match token.uninterpolate().kind { Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Literal | MetaVarKind::Expr { .. }, - ))) => { + )) => { // Unreachable with the current test suite. panic!("from_token metavar"); } @@ -426,10 +455,22 @@ pub enum TokenKind { Question, /// Used by proc macros for representing lifetimes, not generated by lexer right now. SingleQuote, - /// An opening delimiter (e.g., `{`). - OpenDelim(Delimiter), - /// A closing delimiter (e.g., `}`). - CloseDelim(Delimiter), + /// `(` + OpenParen, + /// `)` + CloseParen, + /// `{` + OpenBrace, + /// `}` + CloseBrace, + /// `[` + OpenBracket, + /// `]` + CloseBracket, + /// Invisible opening delimiter, produced by a macro. + OpenInvisible(InvisibleOrigin), + /// Invisible closing delimiter, produced by a macro. + CloseInvisible(InvisibleOrigin), /* Literals */ Literal(Lit), @@ -530,6 +571,37 @@ impl TokenKind { pub fn should_end_const_arg(&self) -> bool { matches!(self, Gt | Ge | Shr | ShrEq) } + + pub fn is_delim(&self) -> bool { + self.open_delim().is_some() || self.close_delim().is_some() + } + + pub fn open_delim(&self) -> Option { + match *self { + OpenParen => Some(Delimiter::Parenthesis), + OpenBrace => Some(Delimiter::Brace), + OpenBracket => Some(Delimiter::Bracket), + OpenInvisible(origin) => Some(Delimiter::Invisible(origin)), + _ => None, + } + } + + pub fn close_delim(&self) -> Option { + match *self { + CloseParen => Some(Delimiter::Parenthesis), + CloseBrace => Some(Delimiter::Brace), + CloseBracket => Some(Delimiter::Bracket), + CloseInvisible(origin) => Some(Delimiter::Invisible(origin)), + _ => None, + } + } + + pub fn is_close_delim_or_eof(&self) -> bool { + match self { + CloseParen | CloseBrace | CloseBracket | CloseInvisible(_) | Eof => true, + _ => false, + } + } } impl Token { @@ -559,7 +631,8 @@ impl Token { | DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true, - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) + OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket + | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | DocComment(..) | Ident(..) | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false, } } @@ -573,11 +646,12 @@ impl Token { /// **NB**: Take care when modifying this function, since it will change /// the stable set of tokens that are allowed to match an expr nonterminal. pub fn can_begin_expr(&self) -> bool { - use Delimiter::*; match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block + OpenParen | // tuple + OpenBrace | // block + OpenBracket | // array Literal(..) | // literal Bang | // operator not Minus | // unary minus @@ -591,12 +665,12 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path - ))) => true, + )) => true, _ => false, } } @@ -608,8 +682,8 @@ impl Token { match &self.uninterpolate().kind { // box, ref, mut, and other identifiers (can stricten) Ident(..) | NtIdent(..) | - OpenDelim(Delimiter::Parenthesis) | // tuple pattern - OpenDelim(Delimiter::Bracket) | // slice pattern + OpenParen | // tuple pattern + OpenBracket | // slice pattern And | // reference Minus | // negative literal AndAnd | // double reference @@ -620,14 +694,14 @@ impl Token { Lt | // path (UFCS constant) Shl => true, // path (double UFCS) Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Meta { .. } | MetaVarKind::Pat(_) | MetaVarKind::Path | MetaVarKind::Ty { .. } - ))) => true, + )) => true, _ => false, } } @@ -637,8 +711,8 @@ impl Token { match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword - OpenDelim(Delimiter::Parenthesis) | // tuple - OpenDelim(Delimiter::Bracket) | // array + OpenParen | // tuple + OpenBracket | // array Bang | // never Star | // raw pointer And | // reference @@ -647,10 +721,10 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | Shl | // associated path PathSep => true, // global path - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Ty { .. } | MetaVarKind::Path - ))) => true, + )) => true, // For anonymous structs or unions, which only appear in specific positions // (type of struct fields or union fields), we don't consider them as regular types _ => false, @@ -660,11 +734,11 @@ impl Token { /// Returns `true` if the token can appear at the start of a const param. pub fn can_begin_const_arg(&self) -> bool { match self.kind { - OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true, + OpenBrace | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, - ))) => true, + )) => true, _ => false, } } @@ -711,7 +785,7 @@ impl Token { match self.uninterpolate().kind { Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { + OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => { can_begin_literal_maybe_minus @@ -725,7 +799,7 @@ impl Token { pub fn can_begin_string_literal(&self) -> bool { match self.uninterpolate().kind { Literal(..) => true, - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { + OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal, _ => false, @@ -892,7 +966,7 @@ impl Token { /// from an expanded metavar? pub fn is_metavar_seq(&self) -> Option { match self.kind { - OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind), + OpenInvisible(InvisibleOrigin::MetaVar(kind)) => Some(kind), _ => None, } } @@ -970,7 +1044,8 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question - | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) + | OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket + | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | Ident(..) | NtIdent(..) | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof, _, ) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0985ebf945bb..6959cbd87f1f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -770,12 +770,12 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.bclose(span, empty); } delim => { - let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); + let token_str = self.token_kind_to_string(&delim.as_open_token_kind()); self.word(token_str); self.ibox(0); self.print_tts(tts, convert_dollar_crate); self.end(); - let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); + let token_str = self.token_kind_to_string(&delim.as_close_token_kind()); self.word(token_str); } } @@ -932,14 +932,13 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::RArrow => "->".into(), token::LArrow => "<-".into(), token::FatArrow => "=>".into(), - token::OpenDelim(Delimiter::Parenthesis) => "(".into(), - token::CloseDelim(Delimiter::Parenthesis) => ")".into(), - token::OpenDelim(Delimiter::Bracket) => "[".into(), - token::CloseDelim(Delimiter::Bracket) => "]".into(), - token::OpenDelim(Delimiter::Brace) => "{".into(), - token::CloseDelim(Delimiter::Brace) => "}".into(), - token::OpenDelim(Delimiter::Invisible(_)) - | token::CloseDelim(Delimiter::Invisible(_)) => "".into(), + token::OpenParen => "(".into(), + token::CloseParen => ")".into(), + token::OpenBracket => "[".into(), + token::CloseBracket => "]".into(), + token::OpenBrace => "{".into(), + token::CloseBrace => "}".into(), + token::OpenInvisible(_) | token::CloseInvisible(_) => "".into(), token::Pound => "#".into(), token::Dollar => "$".into(), token::Question => "?".into(), diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 384fae59873f..40aa39711d3e 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -430,9 +430,7 @@ impl<'a> MetaItemListParserContext<'a> { let span = span.with_hi(segments.last().unwrap().span.hi()); Some(AttrPath { segments: segments.into_boxed_slice(), span }) } - TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => { - None - } + TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None, _ => { // malformed attributes can get here. We can't crash, but somewhere else should've // already warned for this. diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index c70e259b2cd8..d2e45d717d90 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -237,10 +237,7 @@ impl<'a> StripUnconfigured<'a> { inner = self.configure_tokens(&inner); Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } - AttrTokenTree::Token( - Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, - _, - ) => { + AttrTokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); } AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1b539477d51e..db406fc9a72f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,13 +7,12 @@ use std::{iter, mem}; use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, - NodeId, PatKind, StmtKind, TyKind, + NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; @@ -1004,7 +1003,7 @@ pub fn parse_ast_fragment<'a>( AstFragmentKind::Stmts => { let mut stmts = SmallVec::new(); // Won't make progress on a `}`. - while this.token != token::Eof && this.token != token::CloseDelim(Delimiter::Brace) { + while this.token != token::Eof && this.token != token::CloseBrace { if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? { stmts.push(stmt); } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index b663e959744f..698492f42e28 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::TokenStream; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; @@ -66,8 +66,8 @@ pub(super) fn failed_to_match_macro( } if let MatcherLoc::Token { token: expected_token } = &remaining_matcher - && (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) - || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))) + && (matches!(expected_token.kind, token::OpenInvisible(_)) + || matches!(token.kind, token::OpenInvisible(_))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); err.note("see for more information"); diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 0065f83eb4ee..c78beb40688f 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -182,8 +182,8 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { locs.push(MatcherLoc::Token { token: *token }); } TokenTree::Delimited(span, _, delimited) => { - let open_token = Token::new(token::OpenDelim(delimited.delim), span.open); - let close_token = Token::new(token::CloseDelim(delimited.delim), span.close); + let open_token = Token::new(delimited.delim.as_open_token_kind(), span.open); + let close_token = Token::new(delimited.delim.as_close_token_kind(), span.close); locs.push(MatcherLoc::Delimited); locs.push(MatcherLoc::Token { token: open_token }); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c138b0908772..93604a149f1d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -6,7 +6,7 @@ use std::{mem, slice}; use ast::token::IdentIsRaw; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; -use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; +use rustc_ast::token::{self, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; @@ -784,7 +784,7 @@ impl<'tt> FirstSets<'tt> { TokenTree::Delimited(span, _, delimited) => { build_recur(sets, &delimited.tts); first.replace_with(TtHandle::from_token_kind( - token::OpenDelim(delimited.delim), + delimited.delim.as_open_token_kind(), span.open, )); } @@ -852,7 +852,7 @@ impl<'tt> FirstSets<'tt> { } TokenTree::Delimited(span, _, delimited) => { first.add_one(TtHandle::from_token_kind( - token::OpenDelim(delimited.delim), + delimited.delim.as_open_token_kind(), span.open, )); return first; @@ -1099,7 +1099,7 @@ fn check_matcher_core<'tt>( } TokenTree::Delimited(span, _, d) => { let my_suffix = TokenSet::singleton(TtHandle::from_token_kind( - token::CloseDelim(d.delim), + d.delim.as_close_token_kind(), span.close, )); check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?; @@ -1299,7 +1299,9 @@ enum IsInFollow { fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { use mbe::TokenTree; - if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok { + if let TokenTree::Token(Token { kind, .. }) = tok + && kind.close_delim().is_some() + { // closing a token tree can never be matched by any fragment; // iow, we always require that `(` and `)` match, etc. IsInFollow::Yes @@ -1358,16 +1360,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { ]; match tok { TokenTree::Token(token) => match token.kind { - OpenDelim(Delimiter::Brace) - | OpenDelim(Delimiter::Bracket) - | Comma - | FatArrow - | Colon - | Eq - | Gt - | Shr - | Semi - | Or => IsInFollow::Yes, + OpenBrace | OpenBracket | Comma | FatArrow | Colon | Eq | Gt | Shr + | Semi | Or => IsInFollow::Yes, Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => { IsInFollow::Yes } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 3f0372599565..0c2362f23bcf 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -181,7 +181,10 @@ fn parse_tree<'a>( if delim != Delimiter::Parenthesis { span_dollar_dollar_or_metavar_in_the_lhs_err( sess, - &Token { kind: token::OpenDelim(delim), span: delim_span.entire() }, + &Token { + kind: delim.as_open_token_kind(), + span: delim_span.entire(), + }, ); } } else { @@ -217,7 +220,8 @@ fn parse_tree<'a>( } Delimiter::Parenthesis => {} _ => { - let token = pprust::token_kind_to_string(&token::OpenDelim(delim)); + let token = + pprust::token_kind_to_string(&delim.as_open_token_kind()); sess.dcx().emit_err(errors::ExpectedParenOrBrace { span: delim_span.entire(), token, diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 4edaf68c89ae..f00201ad202a 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -308,8 +308,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec unreachable!(), - Eof => unreachable!(), + OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket + | OpenInvisible(_) | CloseInvisible(_) | Eof => unreachable!(), } } trees diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4935fc03256f..a8ec9a1e952e 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -371,12 +371,12 @@ impl<'psess, 'src> Lexer<'psess, 'src> { rustc_lexer::TokenKind::Semi => token::Semi, rustc_lexer::TokenKind::Comma => token::Comma, rustc_lexer::TokenKind::Dot => token::Dot, - rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis), - rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis), - rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace), - rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace), - rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket), - rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket), + rustc_lexer::TokenKind::OpenParen => token::OpenParen, + rustc_lexer::TokenKind::CloseParen => token::CloseParen, + rustc_lexer::TokenKind::OpenBrace => token::OpenBrace, + rustc_lexer::TokenKind::CloseBrace => token::CloseBrace, + rustc_lexer::TokenKind::OpenBracket => token::OpenBracket, + rustc_lexer::TokenKind::CloseBracket => token::CloseBracket, rustc_lexer::TokenKind::At => token::At, rustc_lexer::TokenKind::Pound => token::Pound, rustc_lexer::TokenKind::Tilde => token::Tilde, diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index b3f83a320241..0ddd9a85df86 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -18,38 +18,33 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let mut buf = Vec::new(); loop { - match self.token.kind { - token::OpenDelim(delim) => { - // Invisible delimiters cannot occur here because `TokenTreesReader` parses - // code directly from strings, with no macro expansion involved. - debug_assert!(!matches!(delim, Delimiter::Invisible(_))); - buf.push(match self.lex_token_tree_open_delim(delim) { - Ok(val) => val, - Err(errs) => return Err(errs), - }) - } - token::CloseDelim(delim) => { - // Invisible delimiters cannot occur here because `TokenTreesReader` parses - // code directly from strings, with no macro expansion involved. - debug_assert!(!matches!(delim, Delimiter::Invisible(_))); - return if is_delimited { - Ok((open_spacing, TokenStream::new(buf))) - } else { - Err(vec![self.close_delim_err(delim)]) - }; - } - token::Eof => { - return if is_delimited { - Err(vec![self.eof_err()]) - } else { - Ok((open_spacing, TokenStream::new(buf))) - }; - } - _ => { - // Get the next normal token. - let (this_tok, this_spacing) = self.bump(); - buf.push(TokenTree::Token(this_tok, this_spacing)); - } + if let Some(delim) = self.token.kind.open_delim() { + // Invisible delimiters cannot occur here because `TokenTreesReader` parses + // code directly from strings, with no macro expansion involved. + debug_assert!(!matches!(delim, Delimiter::Invisible(_))); + buf.push(match self.lex_token_tree_open_delim(delim) { + Ok(val) => val, + Err(errs) => return Err(errs), + }) + } else if let Some(delim) = self.token.kind.close_delim() { + // Invisible delimiters cannot occur here because `TokenTreesReader` parses + // code directly from strings, with no macro expansion involved. + debug_assert!(!matches!(delim, Delimiter::Invisible(_))); + return if is_delimited { + Ok((open_spacing, TokenStream::new(buf))) + } else { + Err(vec![self.close_delim_err(delim)]) + }; + } else if self.token.kind == token::Eof { + return if is_delimited { + Err(vec![self.eof_err()]) + } else { + Ok((open_spacing, TokenStream::new(buf))) + }; + } else { + // Get the next normal token. + let (this_tok, this_spacing) = self.bump(); + buf.push(TokenTree::Token(this_tok, this_spacing)); } } } @@ -111,9 +106,9 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let delim_span = DelimSpan::from_pair(pre_span, self.token.span); let sm = self.psess.source_map(); - let close_spacing = match self.token.kind { - // Correct delimiter. - token::CloseDelim(close_delim) if close_delim == open_delim => { + let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() { + if close_delim == open_delim { + // Correct delimiter. let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap(); let close_brace_span = self.token.span; @@ -134,9 +129,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // Move past the closing delimiter. self.bump_minimal() - } - // Incorrect delimiter. - token::CloseDelim(close_delim) => { + } else { + // Incorrect delimiter. let mut unclosed_delimiter = None; let mut candidate = None; @@ -182,14 +176,13 @@ impl<'psess, 'src> Lexer<'psess, 'src> { Spacing::Alone } } - token::Eof => { - // Silently recover, the EOF token will be seen again - // and an error emitted then. Thus we don't pop from - // self.open_braces here. The choice of spacing value here - // doesn't matter. - Spacing::Alone - } - _ => unreachable!(), + } else { + assert_eq!(self.token.kind, token::Eof); + // Silently recover, the EOF token will be seen again + // and an error emitted then. Thus we don't pop from + // self.open_braces here. The choice of spacing value here + // doesn't matter. + Spacing::Alone }; let spacing = DelimSpacing::new(open_spacing, close_spacing); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 2bfa1ea4e058..751d13af4331 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -5,7 +5,7 @@ use rustc_span::{BytePos, Pos, Span, kw}; use super::Lexer; use crate::errors::TokenSubstitution; -use crate::token::{self, Delimiter}; +use crate::token; #[rustfmt::skip] // for line breaks pub(super) static UNICODE_ARRAY: &[(char, &str, &str)] = &[ @@ -315,12 +315,12 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ("!", "Exclamation Mark", Some(token::Bang)), ("?", "Question Mark", Some(token::Question)), (".", "Period", Some(token::Dot)), - ("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))), - (")", "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))), - ("[", "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))), - ("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))), - ("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))), - ("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))), + ("(", "Left Parenthesis", Some(token::OpenParen)), + (")", "Right Parenthesis", Some(token::CloseParen)), + ("[", "Left Square Bracket", Some(token::OpenBracket)), + ("]", "Right Square Bracket", Some(token::CloseBracket)), + ("{", "Left Curly Brace", Some(token::OpenBrace)), + ("}", "Right Curly Brace", Some(token::CloseBrace)), ("*", "Asterisk", Some(token::Star)), ("/", "Slash", Some(token::Slash)), ("\\", "Backslash", None), diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index f1bd6a227309..6061c9cb4856 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::{iter, mem}; -use rustc_ast::token::{Delimiter, Token, TokenKind}; +use rustc_ast::token::{Delimiter, Token}; use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream, @@ -501,27 +501,27 @@ fn make_attr_token_stream( let mut stack_rest = vec![]; for flat_token in iter { match flat_token { - FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => { - stack_rest.push(mem::replace( - &mut stack_top, - FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, - )); - } - FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => { - let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); - let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); - assert!( - open_delim.eq_ignoring_invisible_origin(&delim), - "Mismatched open/close delims: open={open_delim:?} close={span:?}" - ); - let dspan = DelimSpan::from_pair(open_sp, span); - let dspacing = DelimSpacing::new(open_spacing, spacing); - let stream = AttrTokenStream::new(frame_data.inner); - let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); - stack_top.inner.push(delimited); - } - FlatToken::Token((token, spacing)) => { - stack_top.inner.push(AttrTokenTree::Token(token, spacing)) + FlatToken::Token((token @ Token { kind, span }, spacing)) => { + if let Some(delim) = kind.open_delim() { + stack_rest.push(mem::replace( + &mut stack_top, + FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }, + )); + } else if let Some(delim) = kind.close_delim() { + let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); + let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); + assert!( + open_delim.eq_ignoring_invisible_origin(&delim), + "Mismatched open/close delims: open={open_delim:?} close={span:?}" + ); + let dspan = DelimSpan::from_pair(open_sp, span); + let dspacing = DelimSpacing::new(open_spacing, spacing); + let stream = AttrTokenStream::new(frame_data.inner); + let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); + stack_top.inner.push(delimited); + } else { + stack_top.inner.push(AttrTokenTree::Token(token, spacing)) + } } FlatToken::AttrsTarget(target) => { stack_top.inner.push(AttrTokenTree::AttrsTarget(target)) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 7c8e0146c3d2..23c8db7bca78 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut}; use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; +use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, @@ -304,10 +304,10 @@ impl<'a> Parser<'a> { TokenKind::Comma, TokenKind::Semi, TokenKind::PathSep, - TokenKind::OpenDelim(Delimiter::Brace), - TokenKind::OpenDelim(Delimiter::Parenthesis), - TokenKind::CloseDelim(Delimiter::Brace), - TokenKind::CloseDelim(Delimiter::Parenthesis), + TokenKind::OpenBrace, + TokenKind::OpenParen, + TokenKind::CloseBrace, + TokenKind::CloseParen, ]; if let TokenKind::DocComment(..) = self.prev_token.kind && valid_follow.contains(&self.token.kind) @@ -507,7 +507,7 @@ impl<'a> Parser<'a> { } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { // The current token is in the same line as the prior token, not recoverable. } else if [token::Comma, token::Colon].contains(&self.token.kind) - && self.prev_token == token::CloseDelim(Delimiter::Parenthesis) + && self.prev_token == token::CloseParen { // Likely typo: The current token is on a new line and is expected to be // `.`, `;`, `?`, or an operator after a close delimiter token. @@ -518,8 +518,7 @@ impl<'a> Parser<'a> { // ^ // https://github.com/rust-lang/rust/issues/72253 } else if self.look_ahead(1, |t| { - t == &token::CloseDelim(Delimiter::Brace) - || t.can_begin_expr() && *t != token::Colon + t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon }) && [token::Comma, token::Colon].contains(&self.token.kind) { // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is @@ -537,7 +536,7 @@ impl<'a> Parser<'a> { self.bump(); return Ok(guar); } else if self.look_ahead(0, |t| { - t == &token::CloseDelim(Delimiter::Brace) + t == &token::CloseBrace || ((t.can_begin_expr() || t.can_begin_item()) && t != &token::Semi && t != &token::Pound) @@ -675,8 +674,7 @@ impl<'a> Parser<'a> { // `pub` may be used for an item or `pub(crate)` if self.prev_token.is_ident_named(sym::public) - && (self.token.can_begin_item() - || self.token == TokenKind::OpenDelim(Delimiter::Parenthesis)) + && (self.token.can_begin_item() || self.token == TokenKind::OpenParen) { err.span_suggestion_short( self.prev_token.span, @@ -843,9 +841,7 @@ impl<'a> Parser<'a> { if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" }, ), ); - if self.token == token::Pound - && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket)) - { + if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { // We have // #[attr] // expr @@ -1037,9 +1033,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); let guar = match before.kind { - token::OpenDelim(Delimiter::Brace) - if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => - { + token::OpenBrace if token.kind != token::OpenBrace => { // `{ || () }` should have been `|| { () }` err.multipart_suggestion( "you might have meant to open the body of the closure, instead of enclosing \ @@ -1054,9 +1048,7 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[exp!(CloseBrace)]); guar } - token::OpenDelim(Delimiter::Parenthesis) - if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => - { + token::OpenParen if token.kind != token::OpenBrace => { // We are within a function call or tuple, we can emit the error // and recover. self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]); @@ -1071,7 +1063,7 @@ impl<'a> Parser<'a> { ); err.emit() } - _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { + _ if token.kind != token::OpenBrace => { // We don't have a heuristic to correctly identify where the block // should be closed. err.multipart_suggestion_verbose( @@ -1225,7 +1217,7 @@ impl<'a> Parser<'a> { trailing_span = trailing_span.to(self.token.span); self.bump(); } - if self.token == token::OpenDelim(Delimiter::Parenthesis) { + if self.token == token::OpenParen { // Recover from bad turbofish: `foo.collect::Vec<_>()`. segment.args = Some(AngleBracketedArgs { args, span }.into()); @@ -1470,9 +1462,7 @@ impl<'a> Parser<'a> { let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)]; self.consume_tts(1, &modifiers); - if !&[token::OpenDelim(Delimiter::Parenthesis), token::PathSep] - .contains(&self.token.kind) - { + if !matches!(self.token.kind, token::OpenParen | token::PathSep) { // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the // parser and bail out. self.restore_snapshot(snapshot); @@ -1510,7 +1500,7 @@ impl<'a> Parser<'a> { Err(self.dcx().create_err(err)) } } - } else if self.token == token::OpenDelim(Delimiter::Parenthesis) { + } else if self.token == token::OpenParen { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` if let ExprKind::Binary(o, ..) = inner_op.kind @@ -1570,10 +1560,7 @@ impl<'a> Parser<'a> { self.bump(); // `(` // Consume the fn call arguments. - let modifiers = [ - (token::OpenDelim(Delimiter::Parenthesis), 1), - (token::CloseDelim(Delimiter::Parenthesis), -1), - ]; + let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)]; self.consume_tts(1, &modifiers); if self.token == token::Eof { @@ -1978,7 +1965,7 @@ impl<'a> Parser<'a> { fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P, bool)> { let is_question = self.eat(exp!(Question)); // Handle `await? `. - let expr = if self.token == token::OpenDelim(Delimiter::Brace) { + let expr = if self.token == token::OpenBrace { // Handle `await { }`. // This needs to be handled separately from the next arm to avoid // interpreting `await { }?` as `?.await`. @@ -2014,9 +2001,7 @@ impl<'a> Parser<'a> { /// If encountering `future.await()`, consumes and emits an error. pub(super) fn recover_from_await_method_call(&mut self) { - if self.token == token::OpenDelim(Delimiter::Parenthesis) - && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) - { + if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) { // future.await() let lo = self.token.span; self.bump(); // ( @@ -2029,9 +2014,7 @@ impl<'a> Parser<'a> { /// /// If encountering `x.use()`, consumes and emits an error. pub(super) fn recover_from_use(&mut self) { - if self.token == token::OpenDelim(Delimiter::Parenthesis) - && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) - { + if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) { // var.use() let lo = self.token.span; self.bump(); // ( @@ -2045,7 +2028,7 @@ impl<'a> Parser<'a> { pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P> { let is_try = self.token.is_keyword(kw::Try); let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for ! - let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(Delimiter::Parenthesis)); //check for ( + let is_open = self.look_ahead(2, |t| t == &token::OpenParen); //check for ( if is_try && is_questionmark && is_open { let lo = self.token.span; @@ -2053,7 +2036,7 @@ impl<'a> Parser<'a> { self.bump(); //remove ! let try_span = lo.to(self.token.span); //we take the try!( span self.bump(); //remove ( - let is_empty = self.token == token::CloseDelim(Delimiter::Parenthesis); //check if the block is empty + let is_empty = self.token == token::CloseParen; //check if the block is empty self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); //eat the block let hi = self.token.span; self.bump(); //remove ) @@ -2148,7 +2131,7 @@ impl<'a> Parser<'a> { loop { debug!("recover_stmt_ loop {:?}", self.token); match self.token.kind { - token::OpenDelim(Delimiter::Brace) => { + token::OpenBrace => { brace_depth += 1; self.bump(); if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0 @@ -2156,11 +2139,11 @@ impl<'a> Parser<'a> { in_block = true; } } - token::OpenDelim(Delimiter::Bracket) => { + token::OpenBracket => { bracket_depth += 1; self.bump(); } - token::CloseDelim(Delimiter::Brace) => { + token::CloseBrace => { if brace_depth == 0 { debug!("recover_stmt_ return - close delim {:?}", self.token); break; @@ -2172,7 +2155,7 @@ impl<'a> Parser<'a> { break; } } - token::CloseDelim(Delimiter::Bracket) => { + token::CloseBracket => { bracket_depth -= 1; if bracket_depth < 0 { bracket_depth = 0; @@ -2219,12 +2202,10 @@ impl<'a> Parser<'a> { if let token::DocComment(..) = self.token.kind { self.dcx().emit_err(DocCommentOnParamType { span: self.token.span }); self.bump(); - } else if self.token == token::Pound - && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket)) - { + } else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { let lo = self.token.span; // Skip every token until next possible arg. - while self.token != token::CloseDelim(Delimiter::Bracket) { + while self.token != token::CloseBracket { self.bump(); } let sp = lo.to(self.token.span); @@ -2243,9 +2224,7 @@ impl<'a> Parser<'a> { // If we find a pattern followed by an identifier, it could be an (incorrect) // C-style parameter declaration. if self.check_ident() - && self.look_ahead(1, |t| { - *t == token::Comma || *t == token::CloseDelim(Delimiter::Parenthesis) - }) + && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen) { // `fn foo(String s) {}` let ident = self.parse_ident().unwrap(); @@ -2261,7 +2240,7 @@ impl<'a> Parser<'a> { } else if require_name && (self.token == token::Comma || self.token == token::Lt - || self.token == token::CloseDelim(Delimiter::Parenthesis)) + || self.token == token::CloseParen) { let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; @@ -2872,7 +2851,7 @@ impl<'a> Parser<'a> { // Check for `'a : {` if !(self.check_lifetime() && self.look_ahead(1, |t| *t == token::Colon) - && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace))) + && self.look_ahead(2, |t| *t == token::OpenBrace)) { return false; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index df44b3cc23c8..9b71fa6a2b4b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -436,7 +436,7 @@ impl<'a> Parser<'a> { fn is_at_start_of_range_notation_rhs(&self) -> bool { if self.token.can_begin_expr() { // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. - if self.token == token::OpenDelim(Delimiter::Brace) { + if self.token == token::OpenBrace { return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); } true @@ -542,8 +542,8 @@ impl<'a> Parser<'a> { } // Recover from `++x`: token::Plus if this.look_ahead(1, |t| *t == token::Plus) => { - let starts_stmt = this.prev_token == token::Semi - || this.prev_token == token::CloseDelim(Delimiter::Brace); + let starts_stmt = + this.prev_token == token::Semi || this.prev_token == token::CloseBrace; let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span)); // Eat both `+`s. this.bump(); @@ -637,8 +637,8 @@ impl<'a> Parser<'a> { /// Returns the span of expr if it was not interpolated, or the span of the interpolated token. fn interpolated_or_expr_span(&self, expr: &Expr) -> Span { match self.prev_token.kind { - TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span, - TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span, + token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => { // `expr.span` is the interpolated span, because invisible open // and close delims both get marked with the same span, one // that covers the entire thing between them. (See @@ -912,8 +912,8 @@ impl<'a> Parser<'a> { return Ok(e); } e = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), - token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, + token::OpenParen => self.parse_expr_fn_call(lo, e), + token::OpenBracket => self.parse_expr_index(lo, e)?, _ => return Ok(e), } } @@ -1002,7 +1002,7 @@ impl<'a> Parser<'a> { (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => { (span.shrink_to_hi(), format!("`{}`", snippet)) } - (token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))), _) => { + (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => { // No need to report an error. This case will only occur when parsing a pasted // metavariable, and we should have emitted an error when parsing the macro call in // the first place. E.g. in this code: @@ -1202,7 +1202,7 @@ impl<'a> Parser<'a> { } } - if matches!(self.token.kind, token::CloseDelim(..) | token::Comma) { + if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma { break; } else if trailing_dot.is_none() { // This loop should only repeat if there is a trailing dot. @@ -1232,7 +1232,7 @@ impl<'a> Parser<'a> { /// Parse a function call expression, `expr(...)`. fn parse_expr_fn_call(&mut self, lo: Span, fun: P) -> P { - let snapshot = if self.token == token::OpenDelim(Delimiter::Parenthesis) { + let snapshot = if self.token == token::OpenParen { Some((self.create_snapshot_for_diagnostic(), fun.kind.clone())) } else { None @@ -1676,14 +1676,11 @@ impl<'a> Parser<'a> { self.parse_expr_for(label, lo) } else if self.eat_keyword(exp!(Loop)) { self.parse_expr_loop(label, lo) - } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) - || self.token.is_metavar_block() - { + } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() { self.parse_expr_block(label, lo, BlockCheckMode::Default) } else if !ate_colon && self.may_recover() - && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) - || self.token.is_punct()) + && (self.token.kind.close_delim().is_some() || self.token.is_punct()) && could_be_unclosed_char_literal(label_.ident) { let (lit, _) = @@ -1878,7 +1875,7 @@ impl<'a> Parser<'a> { }, }); Some(lexpr) - } else if self.token != token::OpenDelim(Delimiter::Brace) + } else if self.token != token::OpenBrace || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) { let mut expr = self.parse_expr_opt()?; @@ -2014,7 +2011,7 @@ impl<'a> Parser<'a> { // Eat tokens until the macro call ends. if self.may_recover() { - while !matches!(self.token.kind, token::CloseDelim(..) | token::Eof) { + while !self.token.kind.is_close_delim_or_eof() { self.bump(); } } @@ -2155,9 +2152,7 @@ impl<'a> Parser<'a> { self.bump(); Some(token_lit) } - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( - MetaVarKind::Literal, - ))) => { + token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => { let lit = self .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) .expect("metavar seq literal"); @@ -2166,9 +2161,9 @@ impl<'a> Parser<'a> { }; Some(token_lit) } - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + token::OpenInvisible(InvisibleOrigin::MetaVar( mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. }, - ))) => { + )) => { let expr = self .eat_metavar_seq(mv_kind, |this| this.parse_expr()) .expect("metavar seq expr"); @@ -2273,7 +2268,7 @@ impl<'a> Parser<'a> { } fn is_array_like_block(&mut self) -> bool { - matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + self.token.kind == TokenKind::OpenBrace && self .look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) && self.look_ahead(2, |t| t == &token::Comma) @@ -2326,8 +2321,8 @@ impl<'a> Parser<'a> { |p| p.parse_expr(), ) { Ok(_) - // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, - // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`. + // When the close delim is `)`, `token.kind` is expected to be `token::CloseParen`, + // but the actual `token.kind` is `token::CloseBracket`. // This is because the `token.kind` of the close delim is treated as the same as // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. // Therefore, `token.kind` should not be compared here. @@ -2482,7 +2477,7 @@ impl<'a> Parser<'a> { fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P> { if self.may_recover() && self.token.can_begin_expr() - && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + && self.token.kind != TokenKind::OpenBrace && !self.token.is_metavar_block() { let snapshot = self.create_snapshot_for_diagnostic(); @@ -2885,7 +2880,7 @@ impl<'a> Parser<'a> { } fn parse_for_head(&mut self) -> PResult<'a, (P, P)> { - let begin_paren = if self.token == token::OpenDelim(Delimiter::Parenthesis) { + let begin_paren = if self.token == token::OpenParen { // Record whether we are about to parse `for (`. // This is used below for recovery in case of `for ( $stuff ) $block` // in which case we will suggest `for $stuff $block`. @@ -2919,7 +2914,7 @@ impl<'a> Parser<'a> { return Err(err); } }; - return if self.token == token::CloseDelim(Delimiter::Parenthesis) { + return if self.token == token::CloseParen { // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the // parser state and emit a targeted suggestion. let span = vec![start_span, self.token.span]; @@ -2963,7 +2958,7 @@ impl<'a> Parser<'a> { let (pat, expr) = self.parse_for_head()?; // Recover from missing expression in `for` loop if matches!(expr.kind, ExprKind::Block(..)) - && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace)) + && self.token.kind != token::OpenBrace && self.may_recover() { let guar = self @@ -3112,7 +3107,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_inner_attributes()?; let mut arms = ThinVec::new(); - while self.token != token::CloseDelim(Delimiter::Brace) { + while self.token != token::CloseBrace { match self.parse_arm() { Ok(arm) => arms.push(arm), Err(e) => { @@ -3120,7 +3115,7 @@ impl<'a> Parser<'a> { let guar = e.emit(); self.recover_stmt(); let span = lo.to(self.token.span); - if self.token == token::CloseDelim(Delimiter::Brace) { + if self.token == token::CloseBrace { self.bump(); } // Always push at least one arm to make the match non-empty @@ -3181,7 +3176,7 @@ impl<'a> Parser<'a> { // We might have either a `,` -> `;` typo, or a block without braces. We need // a more subtle parsing strategy. loop { - if self.token == token::CloseDelim(Delimiter::Brace) { + if self.token == token::CloseBrace { // We have reached the closing brace of the `match` expression. return Some(err(self, stmts)); } @@ -3240,7 +3235,7 @@ impl<'a> Parser<'a> { // this avoids the compiler saying that a `,` or `}` was expected even though // the pattern isn't a never pattern (and thus an arm body is required) let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern()) - || matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace)); + || matches!(this.token.kind, token::Comma | token::CloseBrace); let mut result = if armless { // A pattern without a body, allowed for never patterns. @@ -3288,8 +3283,8 @@ impl<'a> Parser<'a> { err })?; - let require_comma = !classify::expr_is_complete(&expr) - && this.token != token::CloseDelim(Delimiter::Brace); + let require_comma = + !classify::expr_is_complete(&expr) && this.token != token::CloseBrace; if !require_comma { arm_body = Some(expr); @@ -3440,7 +3435,7 @@ impl<'a> Parser<'a> { } fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P, Option>)> { - if self.token == token::OpenDelim(Delimiter::Parenthesis) { + if self.token == token::OpenParen { let left = self.token.span; let pat = self.parse_pat_no_top_guard( None, @@ -3486,7 +3481,7 @@ impl<'a> Parser<'a> { match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) { Ok((expr, _)) => Ok(expr), Err(mut err) => { - if self.prev_token == token::OpenDelim(Delimiter::Brace) { + if self.prev_token == token::OpenBrace { let sugg_sp = self.prev_token.span.shrink_to_lo(); // Consume everything within the braces, let's avoid further parse // errors. @@ -3529,8 +3524,7 @@ impl<'a> Parser<'a> { fn is_do_catch_block(&self) -> bool { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) - && self - .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) + && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block()) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } @@ -3540,8 +3534,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) - && self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) + && self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block()) && self.token_uninterpolated_span().at_least_rust_2018() } @@ -3575,13 +3568,11 @@ impl<'a> Parser<'a> { // `async move {` self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() + *t == token::OpenBrace || t.is_metavar_block() }) ) || ( // `async {` - self.look_ahead(lookahead + 1, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() - }) + self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block()) )) } @@ -3705,11 +3696,7 @@ impl<'a> Parser<'a> { AssocOp::from_token(t).is_some() || matches!( t.kind, - token::OpenDelim( - Delimiter::Parenthesis - | Delimiter::Bracket - | Delimiter::Brace - ) + token::OpenParen | token::OpenBracket | token::OpenBrace ) || *t == token::Dot }) @@ -3866,8 +3853,8 @@ impl<'a> Parser<'a> { t == &token::Colon || t == &token::Eq || t == &token::Comma - || t == &token::CloseDelim(Delimiter::Brace) - || t == &token::CloseDelim(Delimiter::Parenthesis) + || t == &token::CloseBrace + || t == &token::CloseParen }); if is_wrong { return Err(this.dcx().create_err(errors::ExpectedStructField { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index c3f71dd8b306..c05479feb611 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -1,4 +1,3 @@ -use ast::token::Delimiter; use rustc_ast::{ self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause, token, @@ -437,7 +436,7 @@ impl<'a> Parser<'a> { if let Some(struct_) = struct_ && self.may_recover() - && self.token == token::OpenDelim(Delimiter::Parenthesis) + && self.token == token::OpenParen { snapshot = Some((struct_, self.create_snapshot_for_diagnostic())); }; @@ -548,7 +547,7 @@ impl<'a> Parser<'a> { matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq) // Recovery-only branch -- this could be removed, // since it only affects diagnostics currently. - || matches!(t.kind, token::Question) + || t.kind == token::Question }) || self.is_keyword_ahead(start + 1, &[kw::Const])) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 39a0291cb1ef..39251f1ce273 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -399,14 +399,9 @@ impl<'a> Parser<'a> { let insert_span = ident_span.shrink_to_lo(); let ident = if self.token.is_ident() - && (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis))) + && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen)) && self.look_ahead(1, |t| { - [ - token::Lt, - token::OpenDelim(Delimiter::Brace), - token::OpenDelim(Delimiter::Parenthesis), - ] - .contains(&t.kind) + matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen) }) { self.parse_ident().unwrap() } else { @@ -422,7 +417,7 @@ impl<'a> Parser<'a> { let err = if self.check(exp!(OpenBrace)) { // possible struct or enum definition where `struct` or `enum` was forgotten - if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Brace)) { + if self.look_ahead(1, |t| *t == token::CloseBrace) { // `S {}` could be unit enum or struct Some(errors::MissingKeywordForItemDefinition::EnumOrStruct { span }) } else if self.look_ahead(2, |t| *t == token::Colon) @@ -764,11 +759,12 @@ impl<'a> Parser<'a> { match parse_item(self) { Ok(None) => { let mut is_unnecessary_semicolon = !items.is_empty() - // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, - // but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`. - // This is because the `token.kind` of the close delim is treated as the same as - // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. - // Therefore, `token.kind` should not be compared here. + // When the close delim is `)` in a case like the following, `token.kind` + // is expected to be `token::CloseParen`, but the actual `token.kind` is + // `token::CloseBrace`. This is because the `token.kind` of the close delim + // is treated as the same as that of the open delim in + // `TokenTreesReader::parse_token_tree`, even if the delimiters of them are + // different. Therefore, `token.kind` should not be compared here. // // issue-60075.rs // ``` @@ -787,8 +783,8 @@ impl<'a> Parser<'a> { let mut semicolon_span = self.token.span; if !is_unnecessary_semicolon { // #105369, Detect spurious `;` before assoc fn body - is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace) - && self.prev_token == token::Semi; + is_unnecessary_semicolon = + self.token == token::OpenBrace && self.prev_token == token::Semi; semicolon_span = self.prev_token.span; } // We have to bail or we'll potentially never make progress. @@ -840,7 +836,7 @@ impl<'a> Parser<'a> { /// Recover on a doc comment before `}`. fn recover_doc_comment_before_brace(&mut self) -> bool { if let token::DocComment(..) = self.token.kind { - if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) { + if self.look_ahead(1, |tok| tok == &token::CloseBrace) { // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585) struct_span_code_err!( self.dcx(), @@ -1206,7 +1202,7 @@ impl<'a> Parser<'a> { // FIXME: This recovery should be tested better. if safety == Safety::Default && self.token.is_keyword(kw::Unsafe) - && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) + && self.look_ahead(1, |t| *t == token::OpenBrace) { self.expect(exp!(OpenBrace)).unwrap_err().emit(); safety = Safety::Unsafe(self.token.span); @@ -1718,7 +1714,7 @@ impl<'a> Parser<'a> { } else if self.eat(exp!(Semi)) { VariantData::Unit(DUMMY_NODE_ID) // Record-style struct definition - } else if self.token == token::OpenDelim(Delimiter::Brace) { + } else if self.token == token::OpenBrace { let (fields, recovered) = self.parse_record_struct_body( "struct", ident.span, @@ -1726,7 +1722,7 @@ impl<'a> Parser<'a> { )?; VariantData::Struct { fields, recovered } // Tuple-style struct definition with optional where-clause. - } else if self.token == token::OpenDelim(Delimiter::Parenthesis) { + } else if self.token == token::OpenParen { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID); generics.where_clause = self.parse_where_clause()?; self.expect_semi()?; @@ -1753,7 +1749,7 @@ impl<'a> Parser<'a> { generics.where_clause.has_where_token, )?; VariantData::Struct { fields, recovered } - } else if self.token == token::OpenDelim(Delimiter::Brace) { + } else if self.token == token::OpenBrace { let (fields, recovered) = self.parse_record_struct_body( "union", ident.span, @@ -1784,7 +1780,7 @@ impl<'a> Parser<'a> { let mut fields = ThinVec::new(); let mut recovered = Recovered::No; if self.eat(exp!(OpenBrace)) { - while self.token != token::CloseDelim(Delimiter::Brace) { + while self.token != token::CloseBrace { match self.parse_field_def(adt_ty) { Ok(field) => { fields.push(field); @@ -1941,7 +1937,7 @@ impl<'a> Parser<'a> { token::Comma => { self.bump(); } - token::CloseDelim(Delimiter::Brace) => {} + token::CloseBrace => {} token::DocComment(..) => { let previous_span = self.prev_token.span; let mut err = errors::DocCommentDoesNotDocumentAnything { @@ -1955,7 +1951,7 @@ impl<'a> Parser<'a> { if !seen_comma && comma_after_doc_seen { seen_comma = true; } - if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) { + if comma_after_doc_seen || self.token == token::CloseBrace { self.dcx().emit_err(err); } else { if !seen_comma { @@ -1993,7 +1989,7 @@ impl<'a> Parser<'a> { if self.token.is_ident() || (self.token == TokenKind::Pound - && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket)))) + && (self.look_ahead(1, |t| t == &token::OpenBracket))) { // This is likely another field, TokenKind::Pound is used for `#[..]` // attribute for next field. Emit the diagnostic and continue parsing. @@ -2447,7 +2443,7 @@ impl<'a> Parser<'a> { match self.expected_one_of_not_found(&[], expected) { Ok(error_guaranteed) => Ok(error_guaranteed), Err(mut err) => { - if self.token == token::CloseDelim(Delimiter::Brace) { + if self.token == token::CloseBrace { // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in // the AST for typechecking. err.span_label(ident_span, "while parsing this `fn`"); @@ -2874,7 +2870,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec> { let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... - if self.token != TokenKind::OpenDelim(Delimiter::Parenthesis) + if self.token != TokenKind::OpenParen // might be typo'd trait impl, handled elsewhere && !self.token.is_keyword(kw::For) { @@ -2892,7 +2888,7 @@ impl<'a> Parser<'a> { // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. // For example when parsing `*mut Self` in function `fn oof(*mut Self)`. - let lo = if let TokenKind::OpenDelim(Delimiter::Parenthesis) = p.prev_token.kind { + let lo = if let TokenKind::OpenParen = p.prev_token.kind { p.prev_token.span.shrink_to_hi() } else { p.prev_token.span @@ -2969,9 +2965,7 @@ impl<'a> Parser<'a> { } } - if this.token != token::Comma - && this.token != token::CloseDelim(Delimiter::Parenthesis) - { + if this.token != token::Comma && this.token != token::CloseParen { // This wasn't actually a type, but a pattern looking like a type, // so we are going to rollback and re-parse for recovery. ty = this.unexpected_any(); @@ -3153,7 +3147,7 @@ impl<'a> Parser<'a> { fn is_named_param(&self) -> bool { let offset = match &self.token.kind { - token::OpenDelim(Delimiter::Invisible(origin)) => match origin { + token::OpenInvisible(origin) => match origin { InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => { return self.check_noexpect_past_close_delim(&token::Colon); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2221a261b4c5..d73adb39826f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -23,8 +23,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, - TokenKind, + self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -327,10 +326,7 @@ impl TokenCursor { if let Some(tree) = self.curr.curr() { match tree { &TokenTree::Token(token, spacing) => { - debug_assert!(!matches!( - token.kind, - token::OpenDelim(_) | token::CloseDelim(_) - )); + debug_assert!(!token.kind.is_delim()); let res = (token, spacing); self.curr.bump(); return res; @@ -339,7 +335,7 @@ impl TokenCursor { let trees = TokenTreeCursor::new(tts.clone()); self.stack.push(mem::replace(&mut self.curr, trees)); if !delim.skip() { - return (Token::new(token::OpenDelim(delim), sp.open), spacing.open); + return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open); } // No open delimiter to return; continue on to the next iteration. } @@ -352,7 +348,7 @@ impl TokenCursor { self.curr = parent; self.curr.bump(); // move past the `Delimited` if !delim.skip() { - return (Token::new(token::CloseDelim(delim), span.close), spacing.close); + return (Token::new(delim.as_close_token_kind(), span.close), spacing.close); } // No close delimiter to return; continue on to the next iteration. } else { @@ -423,7 +419,7 @@ impl TokenDescription { _ if token.is_used_keyword() => Some(TokenDescription::Keyword), _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword), token::DocComment(..) => Some(TokenDescription::DocComment), - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { + token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => { Some(TokenDescription::MetaVar(kind)) } _ => None, @@ -620,9 +616,8 @@ impl<'a> Parser<'a> { // past the entire `TokenTree::Delimited` in a single step, avoiding the // need for unbounded token lookahead. // - // Primarily used when `self.token` matches - // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current - // metavar expansion. + // Primarily used when `self.token` matches `OpenInvisible(_))`, to look + // ahead through the current metavar expansion. fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool { let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone(); tree_cursor.bump(); @@ -756,8 +751,7 @@ impl<'a> Parser<'a> { match_mv_kind: impl Fn(MetaVarKind) -> bool, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> Option { - if let token::OpenDelim(delim) = self.token.kind - && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim + if let token::OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind && match_mv_kind(mv_kind) { self.bump(); @@ -776,8 +770,7 @@ impl<'a> Parser<'a> { } }; - if let token::CloseDelim(delim) = self.token.kind - && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim + if let token::CloseInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind && match_mv_kind(mv_kind) { self.bump(); @@ -838,10 +831,8 @@ impl<'a> Parser<'a> { fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { - token::OpenDelim(Delimiter::Brace) => true, - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( - MetaVarKind::Block, - ))) => true, + token::OpenBrace => true, + token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Block)) => true, _ => false, }) } @@ -960,7 +951,7 @@ impl<'a> Parser<'a> { let mut v = ThinVec::new(); while !self.expect_any_with_type(closes_expected, closes_not_expected) { - if let token::CloseDelim(..) | token::Eof = self.token.kind { + if self.token.kind.is_close_delim_or_eof() { break; } if let Some(exp) = sep.sep { @@ -1244,7 +1235,7 @@ impl<'a> Parser<'a> { } debug_assert!(!matches!( next.0.kind, - token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip() + token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip() )); self.inlined_bump_with(next) } @@ -1269,7 +1260,7 @@ impl<'a> Parser<'a> { TokenTree::Token(token, _) => return looker(token), &TokenTree::Delimited(dspan, _, delim, _) => { if !delim.skip() { - return looker(&Token::new(token::OpenDelim(delim), dspan.open)); + return looker(&Token::new(delim.as_open_token_kind(), dspan.open)); } } } @@ -1283,7 +1274,7 @@ impl<'a> Parser<'a> { { // We are not in the outermost token stream, so we have // delimiters. Also, those delimiters are not skipped. - return looker(&Token::new(token::CloseDelim(delim), span.close)); + return looker(&Token::new(delim.as_close_token_kind(), span.close)); } } } @@ -1298,7 +1289,7 @@ impl<'a> Parser<'a> { token = cursor.next().0; if matches!( token.kind, - token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip() + token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip() ) { continue; } @@ -1386,8 +1377,7 @@ impl<'a> Parser<'a> { fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const { // Avoid const blocks and const closures to be parsed as const items if (self.check_const_closure() == is_closure) - && !self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) + && !self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block()) && self.eat_keyword_case(exp!(Const), case) { Const::Yes(self.prev_token_uninterpolated_span()) @@ -1486,48 +1476,46 @@ impl<'a> Parser<'a> { /// Parses a single token tree from the input. pub fn parse_token_tree(&mut self) -> TokenTree { - match self.token.kind { - token::OpenDelim(..) => { - // Clone the `TokenTree::Delimited` that we are currently - // within. That's what we are going to return. - let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone(); - debug_assert_matches!(tree, TokenTree::Delimited(..)); + if self.token.kind.open_delim().is_some() { + // Clone the `TokenTree::Delimited` that we are currently + // within. That's what we are going to return. + let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone(); + debug_assert_matches!(tree, TokenTree::Delimited(..)); - // Advance the token cursor through the entire delimited - // sequence. After getting the `OpenDelim` we are *within* the - // delimited sequence, i.e. at depth `d`. After getting the - // matching `CloseDelim` we are *after* the delimited sequence, - // i.e. at depth `d - 1`. - let target_depth = self.token_cursor.stack.len() - 1; - loop { - // Advance one token at a time, so `TokenCursor::next()` - // can capture these tokens if necessary. - self.bump(); - if self.token_cursor.stack.len() == target_depth { - debug_assert_matches!(self.token.kind, token::CloseDelim(_)); - break; - } + // Advance the token cursor through the entire delimited + // sequence. After getting the `OpenDelim` we are *within* the + // delimited sequence, i.e. at depth `d`. After getting the + // matching `CloseDelim` we are *after* the delimited sequence, + // i.e. at depth `d - 1`. + let target_depth = self.token_cursor.stack.len() - 1; + loop { + // Advance one token at a time, so `TokenCursor::next()` + // can capture these tokens if necessary. + self.bump(); + if self.token_cursor.stack.len() == target_depth { + debug_assert!(self.token.kind.close_delim().is_some()); + break; } + } - // Consume close delimiter - self.bump(); - tree - } - token::CloseDelim(_) | token::Eof => unreachable!(), - _ => { - let prev_spacing = self.token_spacing; - self.bump(); - TokenTree::Token(self.prev_token, prev_spacing) - } + // Consume close delimiter + self.bump(); + tree + } else { + assert!(!self.token.kind.is_close_delim_or_eof()); + let prev_spacing = self.token_spacing; + self.bump(); + TokenTree::Token(self.prev_token, prev_spacing) } } pub fn parse_tokens(&mut self) -> TokenStream { let mut result = Vec::new(); loop { - match self.token.kind { - token::Eof | token::CloseDelim(..) => break, - _ => result.push(self.parse_token_tree()), + if self.token.kind.is_close_delim_or_eof() { + break; + } else { + result.push(self.parse_token_tree()); } } TokenStream::new(result) @@ -1590,7 +1578,7 @@ impl<'a> Parser<'a> { kind: vis, tokens: None, }); - } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + } else if self.look_ahead(2, |t| t == &token::CloseParen) && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower]) { // Parse `pub(crate)`, `pub(self)`, or `pub(super)`. @@ -1687,9 +1675,7 @@ impl<'a> Parser<'a> { /// `::{` or `::*` fn is_import_coupler(&mut self) -> bool { - self.check_path_sep_and_look_ahead(|t| { - matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::Star) - }) + self.check_path_sep_and_look_ahead(|t| matches!(t.kind, token::OpenBrace | token::Star)) } // Debug view of the parser's token stream, up to `{lookahead}` tokens. @@ -1744,9 +1730,7 @@ impl<'a> Parser<'a> { pub fn token_uninterpolated_span(&self) -> Span { match &self.token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { - self.look_ahead(1, |t| t.span) - } + token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(1, |t| t.span), _ => self.token.span, } } @@ -1755,9 +1739,7 @@ impl<'a> Parser<'a> { pub fn prev_token_uninterpolated_span(&self) -> Span { match &self.prev_token.kind { token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { - self.look_ahead(0, |t| t.span) - } + token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(0, |t| t.span), _ => self.prev_token.span, } } @@ -1776,7 +1758,7 @@ pub(crate) fn make_unclosed_delims_error( }; let err = psess.dcx().create_err(MismatchedClosingDelimiter { spans, - delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(), + delimiter: pprust::token_kind_to_string(&found_delim.as_close_token_kind()).to_string(), unmatched: unmatched.found_span, opening_candidate: unmatched.candidate_span, unclosed: unmatched.unclosed_span, diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index b6e89cd7fa46..7c83e96c160c 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,7 +1,7 @@ use rustc_ast::ptr::P; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; +use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; use rustc_errors::PResult; use rustc_span::{Ident, kw}; @@ -69,13 +69,13 @@ impl<'a> Parser<'a> { | token::Ident(..) | token::NtIdent(..) | token::NtLifetime(..) - | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true, + | token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => true, _ => token.can_begin_type(), }, NonterminalKind::Block => match &token.kind { - token::OpenDelim(Delimiter::Brace) => true, + token::OpenBrace => true, token::NtLifetime(..) => true, - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { + token::OpenInvisible(InvisibleOrigin::MetaVar(k)) => match k { MetaVarKind::Block | MetaVarKind::Stmt | MetaVarKind::Expr { .. } @@ -94,9 +94,7 @@ impl<'a> Parser<'a> { }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::PathSep | token::Ident(..) | token::NtIdent(..) => true, - token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { - may_be_ident(*kind) - } + token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => may_be_ident(*kind), _ => false, }, NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind), @@ -105,7 +103,7 @@ impl<'a> Parser<'a> { _ => false, }, NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { - !matches!(token.kind, token::CloseDelim(_)) + token.kind.close_delim().is_none() } } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d5f469f9aa9e..d6ff80b2eb4c 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -3,7 +3,7 @@ use std::ops::Bound; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token}; +use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token}; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ @@ -323,7 +323,7 @@ impl<'a> Parser<'a> { fn eat_or_separator(&mut self, lo: Option) -> EatOrResult { if self.recover_trailing_vert(lo) { EatOrResult::TrailingVert - } else if matches!(self.token.kind, token::OrOr) { + } else if self.token.kind == token::OrOr { // Found `||`; Recover and pretend we parsed `|`. self.dcx().emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo }); self.bump(); @@ -352,9 +352,9 @@ impl<'a> Parser<'a> { | token::Semi // e.g. `let a |;`. | token::Colon // e.g. `let a | :`. | token::Comma // e.g. `let (a |,)`. - | token::CloseDelim(Delimiter::Bracket) // e.g. `let [a | ]`. - | token::CloseDelim(Delimiter::Parenthesis) // e.g. `let (a | )`. - | token::CloseDelim(Delimiter::Brace) // e.g. `let A { f: a | }`. + | token::CloseBracket // e.g. `let [a | ]`. + | token::CloseParen // e.g. `let (a | )`. + | token::CloseBrace // e.g. `let A { f: a | }`. ) }); match (is_end_ahead, &self.token.kind) { @@ -364,7 +364,7 @@ impl<'a> Parser<'a> { span: self.token.span, start: lo, token: self.token, - note_double_vert: matches!(self.token.kind, token::OrOr), + note_double_vert: self.token.kind == token::OrOr, }); self.bump(); true @@ -438,8 +438,8 @@ impl<'a> Parser<'a> { | token::Caret | token::And | token::Shl | token::Shr // excludes `Or` ) || self.token == token::Question - || (self.token == token::OpenDelim(Delimiter::Bracket) - && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))) // excludes `[]` + || (self.token == token::OpenBracket + && self.look_ahead(1, |t| *t != token::CloseBracket)) // excludes `[]` || self.token.is_keyword(kw::As); if !has_dot_expr && !has_trailing_operator { @@ -481,7 +481,7 @@ impl<'a> Parser<'a> { let is_bound = is_end_bound // is_start_bound: either `..` or `)..` || self.token.is_range_separator() - || self.token == token::CloseDelim(Delimiter::Parenthesis) + || self.token == token::CloseParen && self.look_ahead(1, Token::is_range_separator); let span = expr.span; @@ -835,7 +835,7 @@ impl<'a> Parser<'a> { // because we never have `'a: label {}` in a pattern position anyways, but it does // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..` && could_be_unclosed_char_literal(lt) - && !self.look_ahead(1, |token| matches!(token.kind, token::Colon)) + && !self.look_ahead(1, |token| token.kind == token::Colon) { // Recover a `'a` as a `'a'` literal let lt = self.expect_lifetime(); @@ -1255,8 +1255,8 @@ impl<'a> Parser<'a> { || t.is_metavar_expr() || t.is_lifetime() // recover `'a` instead of `'a'` || (self.may_recover() // recover leading `(` - && *t == token::OpenDelim(Delimiter::Parenthesis) - && self.look_ahead(dist + 1, |t| *t != token::OpenDelim(Delimiter::Parenthesis)) + && *t == token::OpenParen + && self.look_ahead(dist + 1, |t| *t != token::OpenParen) && self.is_pat_range_end_start(dist + 1)) }) } @@ -1264,9 +1264,8 @@ impl<'a> Parser<'a> { /// Parse a range pattern end bound fn parse_pat_range_end(&mut self) -> PResult<'a, P> { // recover leading `(` - let open_paren = (self.may_recover() - && self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis))) - .then_some(self.prev_token.span); + let open_paren = (self.may_recover() && self.eat_noexpect(&token::OpenParen)) + .then_some(self.prev_token.span); let bound = if self.check_inline_const(0) { self.parse_const_block(self.token.span, true) @@ -1322,8 +1321,8 @@ impl<'a> Parser<'a> { // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`. && !self.token.is_keyword(kw::In) // Try to do something more complex? - && self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(Delimiter::Parenthesis) // A tuple struct pattern. - | token::OpenDelim(Delimiter::Brace) // A struct pattern. + && self.look_ahead(1, |t| !matches!(t.kind, token::OpenParen // A tuple struct pattern. + | token::OpenBrace // A struct pattern. | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::PathSep // A tuple / struct variant pattern. | token::Bang)) // A macro expanding to a pattern. @@ -1361,7 +1360,7 @@ impl<'a> Parser<'a> { // This shortly leads to a parse error. Note that if there is no explicit // binding mode then we do not end up here, because the lookahead // will direct us over to `parse_enum_variant()`. - if self.token == token::OpenDelim(Delimiter::Parenthesis) { + if self.token == token::OpenParen { return Err(self .dcx() .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span })); @@ -1429,9 +1428,9 @@ impl<'a> Parser<'a> { token::Comma, token::Semi, token::At, - token::OpenDelim(Delimiter::Brace), - token::CloseDelim(Delimiter::Brace), - token::CloseDelim(Delimiter::Parenthesis), + token::OpenBrace, + token::CloseBrace, + token::CloseParen, ] .contains(&self.token.kind) } @@ -1489,7 +1488,7 @@ impl<'a> Parser<'a> { let mut first_etc_and_maybe_comma_span = None; let mut last_non_comma_dotdot_span = None; - while self.token != token::CloseDelim(Delimiter::Brace) { + while self.token != token::CloseBrace { // check that a comma comes after every field if !ate_comma { let err = if self.token == token::At { @@ -1538,7 +1537,7 @@ impl<'a> Parser<'a> { self.recover_bad_dot_dot(); self.bump(); // `..` || `...` || `_` - if self.token == token::CloseDelim(Delimiter::Brace) { + if self.token == token::CloseBrace { break; } let token_str = super::token_descr(&self.token); @@ -1561,7 +1560,7 @@ impl<'a> Parser<'a> { ate_comma = true; } - if self.token == token::CloseDelim(Delimiter::Brace) { + if self.token == token::CloseBrace { // If the struct looks otherwise well formed, recover and continue. if let Some(sp) = comma_sp { err.span_suggestion_short( @@ -1681,7 +1680,7 @@ impl<'a> Parser<'a> { // We found `ref mut? ident:`, try to parse a `name,` or `name }`. && let Some(name_span) = self.look_ahead(1, |t| t.is_ident().then(|| t.span)) && self.look_ahead(2, |t| { - t == &token::Comma || t == &token::CloseDelim(Delimiter::Brace) + t == &token::Comma || t == &token::CloseBrace }) { let span = last.pat.span.with_hi(ident.span.lo()); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 028836556623..1a02d45f0e3c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -2,7 +2,7 @@ use std::mem; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind}; +use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, @@ -302,10 +302,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; let is_args_start = |token: &Token| { - matches!( - token.kind, - token::Lt | token::Shl | token::OpenDelim(Delimiter::Parenthesis) | token::LArrow - ) + matches!(token.kind, token::Lt | token::Shl | token::OpenParen | token::LArrow) }; let check_args_start = |this: &mut Self| { this.expected_token_types.insert(TokenType::Lt); @@ -366,7 +363,7 @@ impl<'a> Parser<'a> { })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() - } else if self.token == token::OpenDelim(Delimiter::Parenthesis) + } else if self.token == token::OpenParen // FIXME(return_type_notation): Could also recover `...` here. && self.look_ahead(1, |t| *t == token::DotDot) { @@ -852,7 +849,7 @@ impl<'a> Parser<'a> { /// the caller. pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { // Parse const argument. - let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind { + let value = if self.token.kind == token::OpenBrace { self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)? } else { self.handle_unambiguous_unbraced_const_arg()? diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0cc8b6050186..885a65d4de7a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -162,7 +162,7 @@ impl<'a> Parser<'a> { // Do not attempt to parse an expression if we're done here. self.error_outer_attrs(attrs); self.mk_stmt(lo, StmtKind::Empty) - } else if self.token != token::CloseDelim(Delimiter::Brace) { + } else if self.token != token::CloseBrace { // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // above. let restrictions = @@ -254,9 +254,7 @@ impl<'a> Parser<'a> { self.token.kind, token::Semi | token::Eof - | token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( - MetaVarKind::Stmt - ))) + | token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt)) ) { StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) } else { @@ -547,7 +545,7 @@ impl<'a> Parser<'a> { // + + Ok(Some(_)) if (!self.token.is_keyword(kw::Else) - && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))) + && self.look_ahead(1, |t| t == &token::OpenBrace)) || do_not_suggest_help => {} // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836). Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {} @@ -584,9 +582,7 @@ impl<'a> Parser<'a> { stmt_kind: &StmtKind, ) { match (&self.token.kind, &stmt_kind) { - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Call(..) = expr.kind => - { + (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Call(..) = expr.kind => { // for _ in x y() {} e.span_suggestion_verbose( between, @@ -595,9 +591,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Field(..) = expr.kind => - { + (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Field(..) = expr.kind => { // for _ in x y.z {} e.span_suggestion_verbose( between, @@ -606,7 +600,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr)) + (token::CloseBrace, StmtKind::Expr(expr)) if let ExprKind::Struct(expr) = &expr.kind && let None = expr.qself && expr.path.segments.len() == 1 => @@ -621,7 +615,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Lit(lit) = expr.kind && let None = lit.suffix && let token::LitKind::Integer | token::LitKind::Float = lit.kind => @@ -635,7 +629,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Loop(..) | ExprKind::If(..) | ExprKind::While(..) @@ -658,7 +652,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - (token::OpenDelim(Delimiter::Brace), _) => {} + (token::OpenBrace, _) => {} (_, _) => { e.multipart_suggestion( "you might have meant to write this as part of a block", @@ -809,7 +803,7 @@ impl<'a> Parser<'a> { // Likely `foo bar` } else if self.prev_token.kind == token::Question { // `foo? bar` - } else if self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis) { + } else if self.prev_token.kind == token::CloseParen { // `foo() bar` } else { return; @@ -826,7 +820,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - if self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)) { + if self.look_ahead(1, |t| t.kind == token::OpenParen) { err.span_suggestion_verbose( self.prev_token.span.between(self.token.span), "you might have meant to write a method call", @@ -870,8 +864,7 @@ impl<'a> Parser<'a> { StmtKind::Expr(expr) if classify::expr_requires_semi_to_be_stmt(expr) && !expr.attrs.is_empty() - && ![token::Eof, token::Semi, token::CloseDelim(Delimiter::Brace)] - .contains(&self.token.kind) => + && !matches!(self.token.kind, token::Eof | token::Semi | token::CloseBrace) => { // The user has written `#[attr] expr` which is unsupported. (#106020) let guar = self.attr_on_non_tail_expr(&expr); @@ -919,7 +912,7 @@ impl<'a> Parser<'a> { token::Ident( kw::For | kw::Loop | kw::While, token::IdentIsRaw::No - ) | token::OpenDelim(Delimiter::Brace) + ) | token::OpenBrace ) }) { diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 2f958f4d4927..8285070839aa 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2573,14 +2573,14 @@ fn look_ahead() { // Current position is the `fn`. look(&p, 0, token::Ident(kw::Fn, raw_no)); look(&p, 1, token::Ident(sym_f, raw_no)); - look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 2, token::OpenParen); look(&p, 3, token::Ident(sym_x, raw_no)); look(&p, 4, token::Colon); look(&p, 5, token::Ident(sym::u32, raw_no)); - look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 6, token::CloseParen); + look(&p, 7, token::OpenBrace); look(&p, 8, token::Ident(sym_x, raw_no)); - look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 9, token::CloseBrace); look(&p, 10, token::Ident(kw::Struct, raw_no)); look(&p, 11, token::Ident(sym_S, raw_no)); look(&p, 12, token::Semi); @@ -2597,10 +2597,10 @@ fn look_ahead() { look(&p, 0, token::Ident(sym_x, raw_no)); look(&p, 1, token::Colon); look(&p, 2, token::Ident(sym::u32, raw_no)); - look(&p, 3, token::CloseDelim(Delimiter::Parenthesis)); - look(&p, 4, token::OpenDelim(Delimiter::Brace)); + look(&p, 3, token::CloseParen); + look(&p, 4, token::OpenBrace); look(&p, 5, token::Ident(sym_x, raw_no)); - look(&p, 6, token::CloseDelim(Delimiter::Brace)); + look(&p, 6, token::CloseBrace); look(&p, 7, token::Ident(kw::Struct, raw_no)); look(&p, 8, token::Ident(sym_S, raw_no)); look(&p, 9, token::Semi); @@ -2652,18 +2652,18 @@ fn look_ahead_non_outermost_stream() { } look(&p, 0, token::Ident(kw::Fn, raw_no)); look(&p, 1, token::Ident(sym_f, raw_no)); - look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 2, token::OpenParen); look(&p, 3, token::Ident(sym_x, raw_no)); look(&p, 4, token::Colon); look(&p, 5, token::Ident(sym::u32, raw_no)); - look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 6, token::CloseParen); + look(&p, 7, token::OpenBrace); look(&p, 8, token::Ident(sym_x, raw_no)); - look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 9, token::CloseBrace); look(&p, 10, token::Ident(kw::Struct, raw_no)); look(&p, 11, token::Ident(sym_S, raw_no)); look(&p, 12, token::Semi); - look(&p, 13, token::CloseDelim(Delimiter::Brace)); + look(&p, 13, token::CloseBrace); // Any lookahead past the end of the token stream returns `Eof`. look(&p, 14, token::Eof); look(&p, 15, token::Eof); @@ -2723,9 +2723,7 @@ fn debug_lookahead() { \"f\", No, ), - OpenDelim( - Parenthesis, - ), + OpenParen, Ident( \"x\", No, @@ -2735,9 +2733,7 @@ fn debug_lookahead() { \"u32\", No, ), - CloseDelim( - Parenthesis, - ), + CloseParen, ], approx_token_stream_pos: 0, .. @@ -2768,9 +2764,7 @@ fn debug_lookahead() { \"f\", No, ), - OpenDelim( - Parenthesis, - ), + OpenParen, Ident( \"x\", No, @@ -2780,19 +2774,13 @@ fn debug_lookahead() { \"u32\", No, ), - CloseDelim( - Parenthesis, - ), - OpenDelim( - Brace, - ), + CloseParen, + OpenBrace, Ident( \"x\", No, ), - CloseDelim( - Brace, - ), + CloseBrace, Ident( \"struct\", No, @@ -2817,9 +2805,7 @@ fn debug_lookahead() { &format!("{:#?}", p.debug_lookahead(1)), "Parser { prev_token: Token { - kind: OpenDelim( - Brace, - ), + kind: OpenBrace, span: Span { lo: BytePos( 13, @@ -2844,9 +2830,7 @@ fn debug_lookahead() { &format!("{:#?}", p.debug_lookahead(4)), "Parser { prev_token: Token { - kind: OpenDelim( - Brace, - ), + kind: OpenBrace, span: Span { lo: BytePos( 13, @@ -2862,9 +2846,7 @@ fn debug_lookahead() { \"x\", No, ), - CloseDelim( - Brace, - ), + CloseBrace, Ident( \"struct\", No, diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index add3c9702019..b91548196a30 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -448,18 +448,6 @@ macro_rules! exp { token_type: $crate::parser::token_type::TokenType::$tok } }; - (@open, $delim:ident, $token_type:ident) => { - $crate::parser::token_type::ExpTokenPair { - tok: &rustc_ast::token::OpenDelim(rustc_ast::token::Delimiter::$delim), - token_type: $crate::parser::token_type::TokenType::$token_type, - } - }; - (@close, $delim:ident, $token_type:ident) => { - $crate::parser::token_type::ExpTokenPair { - tok: &rustc_ast::token::CloseDelim(rustc_ast::token::Delimiter::$delim), - token_type: $crate::parser::token_type::TokenType::$token_type, - } - }; // `ExpKeywordPair` helper rules. (@kw, $kw:ident, $token_type:ident) => { @@ -504,12 +492,12 @@ macro_rules! exp { (Question) => { exp!(@tok, Question) }; (Eof) => { exp!(@tok, Eof) }; - (OpenParen) => { exp!(@open, Parenthesis, OpenParen) }; - (OpenBrace) => { exp!(@open, Brace, OpenBrace) }; - (OpenBracket) => { exp!(@open, Bracket, OpenBracket) }; - (CloseParen) => { exp!(@close, Parenthesis, CloseParen) }; - (CloseBrace) => { exp!(@close, Brace, CloseBrace) }; - (CloseBracket) => { exp!(@close, Bracket, CloseBracket) }; + (OpenParen) => { exp!(@tok, OpenParen) }; + (OpenBrace) => { exp!(@tok, OpenBrace) }; + (OpenBracket) => { exp!(@tok, OpenBracket) }; + (CloseParen) => { exp!(@tok, CloseParen) }; + (CloseBrace) => { exp!(@tok, CloseBrace) }; + (CloseBracket) => { exp!(@tok, CloseBracket) }; (As) => { exp!(@kw, As, KwAs) }; (Async) => { exp!(@kw, Async, KwAsync) }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 42ebf26784df..17481731b110 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind}; +use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, @@ -98,7 +98,7 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { || t.is_lifetime() || t == &TokenKind::Question || t.is_keyword(kw::For) - || t == &TokenKind::OpenDelim(Delimiter::Parenthesis) + || t == &TokenKind::OpenParen } impl<'a> Parser<'a> { @@ -355,7 +355,7 @@ impl<'a> Parser<'a> { } } } else if self.check_keyword(exp!(Unsafe)) - && self.look_ahead(1, |tok| matches!(tok.kind, token::Lt)) + && self.look_ahead(1, |tok| tok.kind == token::Lt) { self.parse_unsafe_binder_ty()? } else { @@ -534,7 +534,7 @@ impl<'a> Parser<'a> { let elt_ty = match self.parse_ty() { Ok(ty) => ty, Err(err) - if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Bracket)) + if self.look_ahead(1, |t| *t == token::CloseBracket) | self.look_ahead(1, |t| *t == token::Semi) => { // Recover from `[LIT; EXPR]` and `[LIT]` @@ -1154,7 +1154,7 @@ impl<'a> Parser<'a> { } let mut path = if self.token.is_keyword(kw::Fn) - && self.look_ahead(1, |t| *t == TokenKind::OpenDelim(Delimiter::Parenthesis)) + && self.look_ahead(1, |t| *t == TokenKind::OpenParen) && let Some(path) = self.recover_path_from_fn() { path @@ -1208,7 +1208,7 @@ impl<'a> Parser<'a> { self.parse_path(PathStyle::Type)? }; - if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) { + if self.may_recover() && self.token == TokenKind::OpenParen { self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?; } diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 31f9c284d7dd..fc99dd08b78a 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -96,7 +96,7 @@ fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) { } } TokenTree::Delimited(_span, _spacing, delim, tts) => { - let open_delim = printer.token_kind_to_string(&token::OpenDelim(*delim)); + let open_delim = printer.token_kind_to_string(&delim.as_open_token_kind()); printer.word(open_delim); if !tts.is_empty() { if *delim == Delimiter::Brace { @@ -107,7 +107,7 @@ fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) { printer.space(); } } - let close_delim = printer.token_kind_to_string(&token::CloseDelim(*delim)); + let close_delim = printer.token_kind_to_string(&delim.as_close_token_kind()); printer.word(close_delim); } } diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 1e16aace3041..0ff0aad7a2d0 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -722,7 +722,7 @@ fn last_tok(tt: &TokenTree) -> Token { match *tt { TokenTree::Token(ref t, _) => t.clone(), TokenTree::Delimited(delim_span, _, delim, _) => Token { - kind: TokenKind::CloseDelim(delim), + kind: delim.as_open_token_kind(), span: delim_span.close, }, } @@ -1124,8 +1124,14 @@ fn next_space(tok: &TokenKind) -> SpaceState { TokenKind::PathSep | TokenKind::Pound | TokenKind::Dollar - | TokenKind::OpenDelim(_) - | TokenKind::CloseDelim(_) => SpaceState::Never, + | TokenKind::OpenParen + | TokenKind::CloseParen + | TokenKind::OpenBrace + | TokenKind::CloseBrace + | TokenKind::OpenBracket + | TokenKind::CloseBracket + | TokenKind::OpenInvisible(_) + | TokenKind::CloseInvisible(_) => SpaceState::Never, TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => { SpaceState::Ident diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 0b7b6c4d3614..30b83373c170 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -1,7 +1,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::ast; -use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::token::TokenKind; use rustc_parse::exp; use rustc_parse::parser::ForceCollect; use rustc_span::symbol::kw; @@ -60,9 +60,7 @@ fn parse_cfg_if_inner<'a>( return Err("Expected an opening brace"); } - while parser.token != TokenKind::CloseDelim(Delimiter::Brace) - && parser.token.kind != TokenKind::Eof - { + while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { let item = match parser.parse_item(ForceCollect::No) { Ok(Some(item_ptr)) => item_ptr.into_inner(), Ok(None) => continue, From 49b62eeacc0b57c01464577c5f3437f2f29f9683 Mon Sep 17 00:00:00 2001 From: The rustc-dev-guide Cronjob Bot Date: Mon, 21 Apr 2025 04:03:02 +0000 Subject: [PATCH 099/109] Preparing for merge from rustc --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 67de4a981655..dc52e0928cc4 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -a7c39b68616668a45f0afd62849a1da7c8ad2516 +b8005bff3248cfc6e327faf4fa631ac49bb49ba9 From dd2d6b222b7a7ad615e612b55fcf3933d4036be3 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 18 Apr 2025 00:44:11 +0900 Subject: [PATCH 100/109] Cleaned up 5 tests in `tests/ui` --- .../writing-to-immutable-vec.rs | 0 .../writing-to-immutable-vec.stderr | 0 .../{ => deref-patterns}/deref-non-pointer.rs | 0 .../deref-non-pointer.stderr | 0 tests/ui/lazy-and-or.rs | 12 --------- tests/ui/list.rs | 9 ------- tests/ui/minus-string.rs | 1 - tests/ui/or-patterns/lazy-and-or.rs | 25 +++++++++++++++++++ tests/ui/recursion/recursive-enum-box.rs | 21 ++++++++++++++++ tests/ui/typeck/minus-string.rs | 7 ++++++ tests/ui/{ => typeck}/minus-string.stderr | 6 ++--- 11 files changed, 56 insertions(+), 25 deletions(-) rename tests/ui/{ => borrowck}/writing-to-immutable-vec.rs (100%) rename tests/ui/{ => borrowck}/writing-to-immutable-vec.stderr (100%) rename tests/ui/{ => deref-patterns}/deref-non-pointer.rs (100%) rename tests/ui/{ => deref-patterns}/deref-non-pointer.stderr (100%) delete mode 100644 tests/ui/lazy-and-or.rs delete mode 100644 tests/ui/list.rs delete mode 100644 tests/ui/minus-string.rs create mode 100644 tests/ui/or-patterns/lazy-and-or.rs create mode 100644 tests/ui/recursion/recursive-enum-box.rs create mode 100644 tests/ui/typeck/minus-string.rs rename tests/ui/{ => typeck}/minus-string.stderr (69%) diff --git a/tests/ui/writing-to-immutable-vec.rs b/tests/ui/borrowck/writing-to-immutable-vec.rs similarity index 100% rename from tests/ui/writing-to-immutable-vec.rs rename to tests/ui/borrowck/writing-to-immutable-vec.rs diff --git a/tests/ui/writing-to-immutable-vec.stderr b/tests/ui/borrowck/writing-to-immutable-vec.stderr similarity index 100% rename from tests/ui/writing-to-immutable-vec.stderr rename to tests/ui/borrowck/writing-to-immutable-vec.stderr diff --git a/tests/ui/deref-non-pointer.rs b/tests/ui/deref-patterns/deref-non-pointer.rs similarity index 100% rename from tests/ui/deref-non-pointer.rs rename to tests/ui/deref-patterns/deref-non-pointer.rs diff --git a/tests/ui/deref-non-pointer.stderr b/tests/ui/deref-patterns/deref-non-pointer.stderr similarity index 100% rename from tests/ui/deref-non-pointer.stderr rename to tests/ui/deref-patterns/deref-non-pointer.stderr diff --git a/tests/ui/lazy-and-or.rs b/tests/ui/lazy-and-or.rs deleted file mode 100644 index f9dbeb68959a..000000000000 --- a/tests/ui/lazy-and-or.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass - -fn incr(x: &mut isize) -> bool { *x += 1; assert!((false)); return false; } - -pub fn main() { - let x = 1 == 2 || 3 == 3; - assert!((x)); - let mut y: isize = 10; - println!("{}", x || incr(&mut y)); - assert_eq!(y, 10); - if true && x { assert!((true)); } else { assert!((false)); } -} diff --git a/tests/ui/list.rs b/tests/ui/list.rs deleted file mode 100644 index 443c4c9f28f8..000000000000 --- a/tests/ui/list.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] - -enum list { #[allow(dead_code)] cons(isize, Box), nil, } - -pub fn main() { - list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil)))))); -} diff --git a/tests/ui/minus-string.rs b/tests/ui/minus-string.rs deleted file mode 100644 index b83347b937ed..000000000000 --- a/tests/ui/minus-string.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() { -"foo".to_string(); } //~ ERROR cannot apply unary operator `-` to type `String` diff --git a/tests/ui/or-patterns/lazy-and-or.rs b/tests/ui/or-patterns/lazy-and-or.rs new file mode 100644 index 000000000000..3d69553132b9 --- /dev/null +++ b/tests/ui/or-patterns/lazy-and-or.rs @@ -0,0 +1,25 @@ +//@ run-pass +// This test verifies the short-circuiting behavior of logical operators `||` and `&&`. +// It ensures that the right-hand expression is not evaluated when the left-hand +// expression is sufficient to determine the result. + +fn would_panic_if_called(x: &mut isize) -> bool { + *x += 1; + assert!(false, "This function should never be called due to short-circuiting"); + false +} + +fn main() { + let x = 1 == 2 || 3 == 3; + assert!(x); + + let mut y: isize = 10; + println!("Result of short-circuit: {}", x || would_panic_if_called(&mut y)); + assert_eq!(y, 10, "y should remain 10 if short-circuiting works correctly"); + + if true && x { + assert!(true); + } else { + assert!(false, "This branch should not be reached"); + } +} diff --git a/tests/ui/recursion/recursive-enum-box.rs b/tests/ui/recursion/recursive-enum-box.rs new file mode 100644 index 000000000000..540b0c553603 --- /dev/null +++ b/tests/ui/recursion/recursive-enum-box.rs @@ -0,0 +1,21 @@ +//@ run-pass +// A smoke test for recursive enum structures using Box. +// This test constructs a linked list-like structure to exercise memory allocation and ownership. +// Originally introduced in 2010, this is one of Rust’s earliest test cases. + +#![allow(dead_code)] + +enum List { + Cons(isize, Box), + Nil, +} + +fn main() { + List::Cons( + 10, + Box::new(List::Cons( + 11, + Box::new(List::Cons(12, Box::new(List::Nil))), + )), + ); +} diff --git a/tests/ui/typeck/minus-string.rs b/tests/ui/typeck/minus-string.rs new file mode 100644 index 000000000000..1c0f73a37132 --- /dev/null +++ b/tests/ui/typeck/minus-string.rs @@ -0,0 +1,7 @@ +// Regression test for issue #813. +// This ensures that the unary negation operator `-` cannot be applied to an owned `String`. +// Previously, due to a type-checking bug, this was mistakenly accepted by the compiler. + +fn main() { + -"foo".to_string(); //~ ERROR cannot apply unary operator `-` to type `String` +} diff --git a/tests/ui/minus-string.stderr b/tests/ui/typeck/minus-string.stderr similarity index 69% rename from tests/ui/minus-string.stderr rename to tests/ui/typeck/minus-string.stderr index 153965c810ea..d2ebcd01ff9c 100644 --- a/tests/ui/minus-string.stderr +++ b/tests/ui/typeck/minus-string.stderr @@ -1,8 +1,8 @@ error[E0600]: cannot apply unary operator `-` to type `String` - --> $DIR/minus-string.rs:1:13 + --> $DIR/minus-string.rs:6:5 | -LL | fn main() { -"foo".to_string(); } - | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` +LL | -"foo".to_string(); + | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` | note: the foreign item type `String` doesn't implement `Neg` --> $SRC_DIR/alloc/src/string.rs:LL:COL From 6fe881c788ebb4d8126cdd603a89e08ca94b4bdb Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 20 Apr 2025 19:52:26 +0800 Subject: [PATCH 101/109] Construct OutputType using macro and print [=FILENAME] help info Signed-off-by: xizheyin --- compiler/rustc_session/src/config.rs | 320 +++++++++++------- .../dash-separated_something-extra.expected.d | 4 +- tests/run-make/rustc-help/help-v.diff | 2 +- tests/run-make/rustc-help/help-v.stdout | 14 +- tests/run-make/rustc-help/help.stdout | 14 +- .../emit-output-types-without-args.rs | 1 + .../emit-output-types-without-args.stderr | 15 +- 7 files changed, 243 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ff7ea5bd7189..bc92b95ce711 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -568,122 +568,203 @@ impl FromStr for SplitDwarfKind { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)] -#[derive(Encodable, Decodable)] -pub enum OutputType { - /// This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode, - /// depending on the specific request type. - Bitcode, - /// This is the summary or index data part of the ThinLTO bitcode. - ThinLinkBitcode, - Assembly, - LlvmAssembly, - Mir, - Metadata, - Object, - Exe, - DepInfo, -} +macro_rules! define_output_types { + ( + $( + $(#[doc = $doc:expr])* + $Variant:ident => { + shorthand: $shorthand:expr, + extension: $extension:expr, + description: $description:expr, + default_filename: $default_filename:expr, + is_text: $is_text:expr, + compatible_with_cgus_and_single_output: $compatible:expr + } + ),* $(,)? + ) => { + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)] + #[derive(Encodable, Decodable)] + pub enum OutputType { + $( + $(#[doc = $doc])* + $Variant, + )* + } -impl StableOrd for OutputType { - const CAN_USE_UNSTABLE_SORT: bool = true; - // Trivial C-Style enums have a stable sort order across compilation sessions. - const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); -} + impl StableOrd for OutputType { + const CAN_USE_UNSTABLE_SORT: bool = true; -impl ToStableHashKey for OutputType { - type KeyType = Self; + // Trivial C-Style enums have a stable sort order across compilation sessions. + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); + } - fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { - *self + impl ToStableHashKey for OutputType { + type KeyType = Self; + + fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { + *self + } + } + + + impl OutputType { + pub fn iter_all() -> impl Iterator { + static ALL_VARIANTS: &[OutputType] = &[ + $( + OutputType::$Variant, + )* + ]; + ALL_VARIANTS.iter().copied() + } + + fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { + match *self { + $( + OutputType::$Variant => $compatible, + )* + } + } + + pub fn shorthand(&self) -> &'static str { + match *self { + $( + OutputType::$Variant => $shorthand, + )* + } + } + + fn from_shorthand(shorthand: &str) -> Option { + match shorthand { + $( + s if s == $shorthand => Some(OutputType::$Variant), + )* + _ => None, + } + } + + fn shorthands_display() -> String { + let shorthands = vec![ + $( + format!("`{}`", $shorthand), + )* + ]; + shorthands.join(", ") + } + + pub fn extension(&self) -> &'static str { + match *self { + $( + OutputType::$Variant => $extension, + )* + } + } + + pub fn is_text_output(&self) -> bool { + match *self { + $( + OutputType::$Variant => $is_text, + )* + } + } + + pub fn description(&self) -> &'static str { + match *self { + $( + OutputType::$Variant => $description, + )* + } + } + + pub fn default_filename(&self) -> &'static str { + match *self { + $( + OutputType::$Variant => $default_filename, + )* + } + } + + + } } } -impl OutputType { - fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { - match *self { - OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true, - OutputType::Bitcode - | OutputType::ThinLinkBitcode - | OutputType::Assembly - | OutputType::LlvmAssembly - | OutputType::Mir - | OutputType::Object => false, - } - } - - pub fn shorthand(&self) -> &'static str { - match *self { - OutputType::Bitcode => "llvm-bc", - OutputType::ThinLinkBitcode => "thin-link-bitcode", - OutputType::Assembly => "asm", - OutputType::LlvmAssembly => "llvm-ir", - OutputType::Mir => "mir", - OutputType::Object => "obj", - OutputType::Metadata => "metadata", - OutputType::Exe => "link", - OutputType::DepInfo => "dep-info", - } - } - - fn from_shorthand(shorthand: &str) -> Option { - Some(match shorthand { - "asm" => OutputType::Assembly, - "llvm-ir" => OutputType::LlvmAssembly, - "mir" => OutputType::Mir, - "llvm-bc" => OutputType::Bitcode, - "thin-link-bitcode" => OutputType::ThinLinkBitcode, - "obj" => OutputType::Object, - "metadata" => OutputType::Metadata, - "link" => OutputType::Exe, - "dep-info" => OutputType::DepInfo, - _ => return None, - }) - } - - fn shorthands_display() -> String { - format!( - "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", - OutputType::Bitcode.shorthand(), - OutputType::ThinLinkBitcode.shorthand(), - OutputType::Assembly.shorthand(), - OutputType::LlvmAssembly.shorthand(), - OutputType::Mir.shorthand(), - OutputType::Object.shorthand(), - OutputType::Metadata.shorthand(), - OutputType::Exe.shorthand(), - OutputType::DepInfo.shorthand(), - ) - } - - pub fn extension(&self) -> &'static str { - match *self { - OutputType::Bitcode => "bc", - OutputType::ThinLinkBitcode => "indexing.o", - OutputType::Assembly => "s", - OutputType::LlvmAssembly => "ll", - OutputType::Mir => "mir", - OutputType::Object => "o", - OutputType::Metadata => "rmeta", - OutputType::DepInfo => "d", - OutputType::Exe => "", - } - } - - pub fn is_text_output(&self) -> bool { - match *self { - OutputType::Assembly - | OutputType::LlvmAssembly - | OutputType::Mir - | OutputType::DepInfo => true, - OutputType::Bitcode - | OutputType::ThinLinkBitcode - | OutputType::Object - | OutputType::Metadata - | OutputType::Exe => false, - } - } +define_output_types! { + Assembly => { + shorthand: "asm", + extension: "s", + description: "Generates a file with the crate's assembly code", + default_filename: "CRATE_NAME.s", + is_text: true, + compatible_with_cgus_and_single_output: false + }, + #[doc = "This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,"] + #[doc = "depending on the specific request type."] + Bitcode => { + shorthand: "llvm-bc", + extension: "bc", + description: "Generates a binary file containing the LLVM bitcode", + default_filename: "CRATE_NAME.bc", + is_text: false, + compatible_with_cgus_and_single_output: false + }, + DepInfo => { + shorthand: "dep-info", + extension: "d", + description: "Generates a file with Makefile syntax that indicates all the source files that were loaded to generate the crate", + default_filename: "CRATE_NAME.d", + is_text: true, + compatible_with_cgus_and_single_output: true + }, + Exe => { + shorthand: "link", + extension: "", + description: "Generates the crates specified by --crate-type. This is the default if --emit is not specified", + default_filename: "(platform and crate-type dependent)", + is_text: false, + compatible_with_cgus_and_single_output: true + }, + LlvmAssembly => { + shorthand: "llvm-ir", + extension: "ll", + description: "Generates a file containing LLVM IR", + default_filename: "CRATE_NAME.ll", + is_text: true, + compatible_with_cgus_and_single_output: false + }, + Metadata => { + shorthand: "metadata", + extension: "rmeta", + description: "Generates a file containing metadata about the crate", + default_filename: "libCRATE_NAME.rmeta", + is_text: false, + compatible_with_cgus_and_single_output: true + }, + Mir => { + shorthand: "mir", + extension: "mir", + description: "Generates a file containing rustc's mid-level intermediate representation", + default_filename: "CRATE_NAME.mir", + is_text: true, + compatible_with_cgus_and_single_output: false + }, + Object => { + shorthand: "obj", + extension: "o", + description: "Generates a native object file", + default_filename: "CRATE_NAME.o", + is_text: false, + compatible_with_cgus_and_single_output: false + }, + #[doc = "This is the summary or index data part of the ThinLTO bitcode."] + ThinLinkBitcode => { + shorthand: "thin-link-bitcode", + extension: "indexing.o", + description: "Generates the ThinLTO summary as bitcode", + default_filename: "CRATE_NAME.indexing.o", + is_text: false, + compatible_with_cgus_and_single_output: false + }, } /// The type of diagnostics output to generate. @@ -1570,6 +1651,18 @@ static PRINT_HELP: LazyLock = LazyLock::new(|| { ) }); +static EMIT_HELP: LazyLock = LazyLock::new(|| { + let mut result = + String::from("Comma separated list of types of output for the compiler to emit.\n"); + result.push_str("Each TYPE has the default FILE name:\n"); + + for output in OutputType::iter_all() { + result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename())); + } + + result +}); + /// Returns all rustc command line options, including metadata for /// each option, such as whether the option is stable. pub fn rustc_optgroups() -> Vec { @@ -1616,14 +1709,7 @@ pub fn rustc_optgroups() -> Vec { make_crate_type_option(), opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"), opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST), - opt( - Stable, - Multi, - "", - "emit", - "Comma separated list of types of output for the compiler to emit", - "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", - ), + opt(Stable, Multi, "", "emit", &EMIT_HELP, "TYPE[=FILE]"), opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"), opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""), diff --git a/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d b/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d index 497d76b4ea12..43e8f9185a30 100644 --- a/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d +++ b/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d @@ -1,5 +1,5 @@ -libdash_separated_something-extra.rmeta: dash-separated.rs - dash-separated_something-extra.d: dash-separated.rs +libdash_separated_something-extra.rmeta: dash-separated.rs + dash-separated.rs: diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff index 30703f6424e7..0ea79f3e5573 100644 --- a/tests/run-make/rustc-help/help-v.diff +++ b/tests/run-make/rustc-help/help-v.diff @@ -1,4 +1,4 @@ -@@ -53,10 +53,27 @@ +@@ -63,10 +63,27 @@ Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index 13af6e21060b..744453d6e856 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -26,9 +26,19 @@ Options: Specify which edition of the compiler to use when compiling code. The default is 2015 and the latest stable edition is 2024. - --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + --emit TYPE[=FILE] Comma separated list of types of output for the - compiler to emit + compiler to emit. + Each TYPE has the default FILE name: + * asm - CRATE_NAME.s + * llvm-bc - CRATE_NAME.bc + * dep-info - CRATE_NAME.d + * link - (platform and crate-type dependent) + * llvm-ir - CRATE_NAME.ll + * metadata - libCRATE_NAME.rmeta + * mir - CRATE_NAME.mir + * obj - CRATE_NAME.o + * thin-link-bitcode - CRATE_NAME.indexing.o --print INFO[=FILE] Compiler information to print on stdout (or to a file) INFO may be one of diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 62757d989eb3..3043755207a6 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -26,9 +26,19 @@ Options: Specify which edition of the compiler to use when compiling code. The default is 2015 and the latest stable edition is 2024. - --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + --emit TYPE[=FILE] Comma separated list of types of output for the - compiler to emit + compiler to emit. + Each TYPE has the default FILE name: + * asm - CRATE_NAME.s + * llvm-bc - CRATE_NAME.bc + * dep-info - CRATE_NAME.d + * link - (platform and crate-type dependent) + * llvm-ir - CRATE_NAME.ll + * metadata - libCRATE_NAME.rmeta + * mir - CRATE_NAME.mir + * obj - CRATE_NAME.o + * thin-link-bitcode - CRATE_NAME.indexing.o --print INFO[=FILE] Compiler information to print on stdout (or to a file) INFO may be one of diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs index 793931e99d9c..a96eeb0a5ce0 100644 --- a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs +++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs @@ -1 +1,2 @@ //@ compile-flags: --emit +//@ error-pattern: Argument to option 'emit' missing diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr index dad81dcb13c0..669913b57653 100644 --- a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr +++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr @@ -1,6 +1,15 @@ error: Argument to option 'emit' missing Usage: - --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] - Comma separated list of types of output for the - compiler to emit + --emit TYPE[=FILE] Comma separated list of types of output for the + compiler to emit. + Each TYPE has the default FILE name: + * asm - CRATE_NAME.s + * llvm-bc - CRATE_NAME.bc + * dep-info - CRATE_NAME.d + * link - (platform and crate-type dependent) + * llvm-ir - CRATE_NAME.ll + * metadata - libCRATE_NAME.rmeta + * mir - CRATE_NAME.mir + * obj - CRATE_NAME.o + * thin-link-bitcode - CRATE_NAME.indexing.o From 2039b36f908b20e7be8a60e903a2a26b21c65ace Mon Sep 17 00:00:00 2001 From: Jonathan Gruner Date: Mon, 21 Apr 2025 14:15:32 +0200 Subject: [PATCH 102/109] cleanup redundant pattern instances --- compiler/rustc_transmute/src/layout/tree.rs | 2 +- library/std/src/path.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index a21be5dda4ee..70ecc75403fd 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -514,7 +514,7 @@ pub(crate) mod rustc { } } ty::Tuple(fields) => fields[i.as_usize()], - kind @ _ => unimplemented!( + kind => unimplemented!( "only a subset of `Ty::ty_and_layout_field`'s functionality is implemented. implementation needed for {:?}", kind ), diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 980213be7ea9..50f403ba411b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3265,7 +3265,7 @@ impl Hash for Path { if !verbatim { component_start += match tail { [b'.'] => 1, - [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1, + [b'.', sep, ..] if is_sep_byte(*sep) => 1, _ => 0, }; } From aedbd2d1ec91339954573b691022f89d169f9b84 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Apr 2025 11:25:46 -0400 Subject: [PATCH 103/109] Replace colon with parentheses, add missing period --- library/core/src/bstr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index 07d4fd911d3a..13127d645a25 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -36,7 +36,7 @@ use crate::ops::{Deref, DerefMut, DerefPure}; /// presented as hex escape sequences. /// /// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a -/// `str`, with invalid UTF-8 presented as the Unicode replacement character: � +/// `str`, with invalid UTF-8 presented as the Unicode replacement character (�). #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[doc(alias = "BStr")] From 5e202a3c71f3ae85e773d054922a24c0302e6f72 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 21 Apr 2025 14:55:06 +0000 Subject: [PATCH 104/109] Use output dir for mir_dump_dir --- src/tools/compiletest/src/runtest.rs | 13 +------------ src/tools/compiletest/src/runtest/mir_opt.rs | 4 ++-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d11f5c1a3a6f..cc09463c358a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1395,14 +1395,6 @@ impl<'test> TestCx<'test> { matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json") } - fn get_mir_dump_dir(&self) -> Utf8PathBuf { - let mut mir_dump_dir = self.config.build_test_suite_root.clone(); - debug!("input_file: {}", self.testpaths.file); - mir_dump_dir.push(&self.testpaths.relative_dir); - mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); - mir_dump_dir - } - fn make_compile_args( &self, input_file: &Utf8Path, @@ -1511,10 +1503,7 @@ impl<'test> TestCx<'test> { } let set_mir_dump_dir = |rustc: &mut Command| { - let mir_dump_dir = self.get_mir_dump_dir(); - remove_and_create_dir_all(&mir_dump_dir).unwrap_or_else(|e| { - panic!("failed to remove and recreate output directory `{mir_dump_dir}`: {e}") - }); + let mir_dump_dir = self.output_base_dir(); let mut dir_opt = "-Zdump-mir-dir=".to_string(); dir_opt.push_str(mir_dump_dir.as_str()); debug!("dir_opt: {:?}", dir_opt); diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index ded6a68fe587..efdb131bf14a 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -56,7 +56,7 @@ impl TestCx<'_> { self.diff_mir_files(from_file.into(), after.into()) } else { let mut output_file = Utf8PathBuf::new(); - output_file.push(self.get_mir_dump_dir()); + output_file.push(self.output_base_dir()); output_file.push(&from_file); debug!("comparing the contents of: {} with {:?}", output_file, expected_file); if !output_file.exists() { @@ -100,7 +100,7 @@ impl TestCx<'_> { fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String { let to_full_path = |path: Utf8PathBuf| { - let full = self.get_mir_dump_dir().join(&path); + let full = self.output_base_dir().join(&path); if !full.exists() { panic!( "the mir dump file for {} does not exist (requested in {})", From 619ed1540a7704afd08ca91b3a7ddece94ba9720 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 21 Apr 2025 17:36:36 +0200 Subject: [PATCH 105/109] Document why CodeStats::type_sizes is public --- compiler/rustc_session/src/code_stats.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index 6b18d450e9e5..80603b4a1567 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -72,6 +72,8 @@ pub struct TypeSizeInfo { #[derive(Default)] pub struct CodeStats { + /// The hash set that actually holds all the type size information. + /// The field is public for use in external tools. See #139876. pub type_sizes: Lock>, } From 834e476a0c3d275d267d10425aa3a22666e9376e Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 21 Apr 2025 22:14:44 +0500 Subject: [PATCH 106/109] Add diagnostics and suggestions for raw pointer arithmetic assignments --- compiler/rustc_hir_typeck/src/op.rs | 52 ++++++++++++++++++++- tests/ui/typeck/pointer-arith-assign.fixed | 20 ++++++++ tests/ui/typeck/pointer-arith-assign.rs | 20 ++++++++ tests/ui/typeck/pointer-arith-assign.stderr | 31 ++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tests/ui/typeck/pointer-arith-assign.fixed create mode 100644 tests/ui/typeck/pointer-arith-assign.rs create mode 100644 tests/ui/typeck/pointer-arith-assign.stderr diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 0e42a84ca32a..b86991f81ad8 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -234,7 +234,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(rhs_expr.span); - let result = self.lookup_op_method( (lhs_expr, lhs_ty), Some((rhs_expr, rhs_ty_var)), @@ -698,6 +697,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + let lhs_name_str = match lhs_expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => { + path.segments.last().map_or("_".to_string(), |s| s.ident.to_string()) + } + _ => self + .tcx + .sess + .source_map() + .span_to_snippet(lhs_expr.span) + .unwrap_or("_".to_string()), + }; + + if op.span().can_be_used_for_suggestions() { + match op { + Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. }) + if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() => + { + err.multipart_suggestion( + "consider using `add` or `wrapping_add` to do pointer arithmetic", + vec![ + (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)), + ( + lhs_expr.span.between(rhs_expr.span), + ".wrapping_add(".to_owned(), + ), + (rhs_expr.span.shrink_to_hi(), ")".to_owned()), + ], + Applicability::MaybeIncorrect, + ); + } + Op::AssignOp(Spanned { node: hir::AssignOpKind::SubAssign, .. }) => { + if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() { + err.multipart_suggestion( + "consider using `sub` or `wrapping_sub` to do pointer arithmetic", + vec![ + (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)), + ( + lhs_expr.span.between(rhs_expr.span), + ".wrapping_sub(".to_owned(), + + ), + (rhs_expr.span.shrink_to_hi(), ")".to_owned()), + ], + Applicability::MaybeIncorrect, + ); + } + } + _ => {} + } + } + let reported = err.emit(); Ty::new_error(self.tcx, reported) } diff --git a/tests/ui/typeck/pointer-arith-assign.fixed b/tests/ui/typeck/pointer-arith-assign.fixed new file mode 100644 index 000000000000..907208579e7c --- /dev/null +++ b/tests/ui/typeck/pointer-arith-assign.fixed @@ -0,0 +1,20 @@ +//@ run-rustfix +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn test_add_assign_raw_pointer() { + let mut arr = [0u8; 10]; + let mut _ptr = arr.as_mut_ptr(); + + _ptr = _ptr.wrapping_add(2); //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368] +} + +fn test_sub_assign_raw_pointer() { + let mut arr = [0u8; 10]; + let mut _ptr = arr.as_mut_ptr(); + + _ptr = _ptr.wrapping_sub(2); //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368] +} + +fn main() {} diff --git a/tests/ui/typeck/pointer-arith-assign.rs b/tests/ui/typeck/pointer-arith-assign.rs new file mode 100644 index 000000000000..0f4ef6ab74c0 --- /dev/null +++ b/tests/ui/typeck/pointer-arith-assign.rs @@ -0,0 +1,20 @@ +//@ run-rustfix +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_assignments)] + +fn test_add_assign_raw_pointer() { + let mut arr = [0u8; 10]; + let mut _ptr = arr.as_mut_ptr(); + + _ptr += 2; //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368] +} + +fn test_sub_assign_raw_pointer() { + let mut arr = [0u8; 10]; + let mut _ptr = arr.as_mut_ptr(); + + _ptr -= 2; //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368] +} + +fn main() {} diff --git a/tests/ui/typeck/pointer-arith-assign.stderr b/tests/ui/typeck/pointer-arith-assign.stderr new file mode 100644 index 000000000000..a2bebe5e2475 --- /dev/null +++ b/tests/ui/typeck/pointer-arith-assign.stderr @@ -0,0 +1,31 @@ +error[E0368]: binary assignment operation `+=` cannot be applied to type `*mut u8` + --> $DIR/pointer-arith-assign.rs:10:5 + | +LL | _ptr += 2; + | ----^^^^^ + | | + | cannot use `+=` on type `*mut u8` + | +help: consider using `add` or `wrapping_add` to do pointer arithmetic + | +LL - _ptr += 2; +LL + _ptr = _ptr.wrapping_add(2); + | + +error[E0368]: binary assignment operation `-=` cannot be applied to type `*mut u8` + --> $DIR/pointer-arith-assign.rs:17:5 + | +LL | _ptr -= 2; + | ----^^^^^ + | | + | cannot use `-=` on type `*mut u8` + | +help: consider using `sub` or `wrapping_sub` to do pointer arithmetic + | +LL - _ptr -= 2; +LL + _ptr = _ptr.wrapping_sub(2); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0368`. From da2b32925a7eac8ec49350c2cebfcdc333618661 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Apr 2025 21:11:56 +0200 Subject: [PATCH 107/109] Use correct annotation for CSS pseudo elements --- src/librustdoc/html/static/css/rustdoc.css | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 74d23b3143f4..a6dd06b76ea9 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -585,7 +585,7 @@ img { margin-left: -140px; border-left: none; } -.sidebar-resizer.active:before { +.sidebar-resizer.active::before { border-left: solid 2px var(--sidebar-resizer-active); display: block; height: 100%; @@ -2044,7 +2044,7 @@ button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible { text-decoration: none; } -#settings-menu > a:before { +#settings-menu > a::before { /* Wheel */ content: url('data:image/svg+xml,\ @@ -2064,7 +2064,7 @@ button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible { filter: var(--settings-menu-filter); } -button#toggle-all-docs:before { +button#toggle-all-docs::before { /* Custom arrow icon */ content: url('data:image/svg+xml,\ @@ -2074,14 +2074,14 @@ button#toggle-all-docs:before { filter: var(--settings-menu-filter); } -button#toggle-all-docs.will-expand:before { +button#toggle-all-docs.will-expand::before { /* Custom arrow icon */ content: url('data:image/svg+xml,\ '); } -#help-button > a:before { +#help-button > a::before { /* Question mark with circle */ content: url('data:image/svg+xml,\ @@ -2093,17 +2093,17 @@ button#toggle-all-docs.will-expand:before { filter: var(--settings-menu-filter); } -button#toggle-all-docs:before, -#help-button > a:before, -#settings-menu > a:before { +button#toggle-all-docs::before, +#help-button > a::before, +#settings-menu > a::before { filter: var(--settings-menu-filter); margin: 8px; } @media not (pointer: coarse) { - button#toggle-all-docs:hover:before, - #help-button > a:hover:before, - #settings-menu > a:hover:before { + button#toggle-all-docs:hover::before, + #help-button > a:hover::before, + #settings-menu > a:hover::before { filter: var(--settings-menu-hover-filter); } } @@ -2125,7 +2125,7 @@ rustdoc-toolbar span.label { padding-bottom: 4px; } -#sidebar-button > a:before { +#sidebar-button > a::before { /* sidebar resizer image */ content: url('data:image/svg+xml,\ @@ -2400,21 +2400,21 @@ However, it's not needed with smaller screen width because the doc/code block is /* sidebar button opens modal use hamburger button */ -.src #sidebar-button > a:before, .sidebar-menu-toggle:before { +.src #sidebar-button > a::before, .sidebar-menu-toggle::before { /* hamburger button image */ content: url('data:image/svg+xml,\ '); opacity: 0.75; } -.sidebar-menu-toggle:hover:before, -.sidebar-menu-toggle:active:before, -.sidebar-menu-toggle:focus:before { +.sidebar-menu-toggle:hover::before, +.sidebar-menu-toggle:active::before, +.sidebar-menu-toggle:focus::before { opacity: 1; } /* src sidebar button opens a folder view */ -.src #sidebar-button > a:before { +.src #sidebar-button > a::before { /* folder image */ content: url('data:image/svg+xml,\ @@ -2599,7 +2599,7 @@ in src-script.js and main.js } /* sidebar button becomes topbar button */ - #sidebar-button > a:before { + #sidebar-button > a::before { content: url('data:image/svg+xml,\ \ @@ -2608,7 +2608,7 @@ in src-script.js and main.js width: 22px; height: 22px; } - .sidebar-menu-toggle:before { + .sidebar-menu-toggle::before { filter: var(--mobile-sidebar-menu-filter); } .sidebar-menu-toggle:hover { @@ -3287,7 +3287,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) } :root[data-theme="ayu"] #settings-menu > a img, -:root[data-theme="ayu"] #sidebar-button > a:before { +:root[data-theme="ayu"] #sidebar-button > a::before { filter: invert(100); } /* End theme: ayu */ From d05469004931c04433465e399f1440fd1b386233 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 22 Apr 2025 16:10:52 +0800 Subject: [PATCH 108/109] Unify the format of rustc cli flags Signed-off-by: xizheyin --- compiler/rustc_session/src/config.rs | 72 +++++++++--------- compiler/rustc_span/src/edition.rs | 2 +- tests/run-make/rustc-help/help-v.diff | 23 +++--- tests/run-make/rustc-help/help-v.stdout | 75 ++++++++++--------- tests/run-make/rustc-help/help.stdout | 54 ++++++------- .../output-default.stdout | 2 +- .../compile-flags-last.stderr | 2 +- .../emit-output-types-without-args.stderr | 3 +- .../print-without-arg.stderr | 5 +- 9 files changed, 123 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index bc92b95ce711..c06f3c97da76 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1646,7 +1646,7 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE static PRINT_HELP: LazyLock = LazyLock::new(|| { format!( "Compiler information to print on stdout (or to a file)\n\ - INFO may be one of ({}).", + INFO may be one of <{}>.", PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::>().join("|") ) }); @@ -1679,18 +1679,18 @@ pub fn rustc_optgroups() -> Vec { "", "cfg", "Configure the compilation environment.\n\ - SPEC supports the syntax `NAME[=\"VALUE\"]`.", - "SPEC", + SPEC supports the syntax `[=\"\"]`.", + "", ), - opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"), + opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", ""), opt( Stable, Multi, "L", "", "Add a directory to the library search path. \ - The optional KIND can be one of dependency, crate, native, framework, or all (the default).", - "[KIND=]PATH", + The optional KIND can be one of (default: all).", + "[=]", ), opt( Stable, @@ -1699,46 +1699,46 @@ pub fn rustc_optgroups() -> Vec { "", "Link the generated crate(s) to the specified native\n\ library NAME. The optional KIND can be one of\n\ - static, framework, or dylib (the default).\n\ + (default: dylib).\n\ Optional comma separated MODIFIERS\n\ - (bundle|verbatim|whole-archive|as-needed)\n\ + \n\ may be specified each with a prefix of either '+' to\n\ enable or '-' to disable.", - "[KIND[:MODIFIERS]=]NAME[:RENAME]", + "[[:]=][:]", ), make_crate_type_option(), - opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"), + opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", ""), opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST), - opt(Stable, Multi, "", "emit", &EMIT_HELP, "TYPE[=FILE]"), - opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"), + opt(Stable, Multi, "", "emit", &EMIT_HELP, "[=]"), + opt(Stable, Multi, "", "print", &PRINT_HELP, "[=]"), opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""), - opt(Stable, Opt, "o", "", "Write output to ", "FILENAME"), - opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in ", "DIR"), + opt(Stable, Opt, "o", "", "Write output to FILENAME", ""), + opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", ""), opt( Stable, Opt, "", "explain", "Provide a detailed explanation of an error message", - "OPT", + "", ), opt(Stable, Flag, "", "test", "Build a test harness", ""), - opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"), - opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"), - opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"), - opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"), - opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"), - opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"), + opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", ""), + opt(Stable, Multi, "A", "allow", "Set lint allowed", ""), + opt(Stable, Multi, "W", "warn", "Set lint warnings", ""), + opt(Stable, Multi, "", "force-warn", "Set lint force-warn", ""), + opt(Stable, Multi, "D", "deny", "Set lint denied", ""), + opt(Stable, Multi, "F", "forbid", "Set lint forbidden", ""), opt( Stable, Multi, "", "cap-lints", "Set the most restrictive lint level. More restrictive lints are capped at this level", - "LEVEL", + "", ), - opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"), + opt(Stable, Multi, "C", "codegen", "Set a codegen option", "[=]"), opt(Stable, Flag, "V", "version", "Print version info and exit", ""), opt(Stable, Flag, "v", "verbose", "Use verbose output", ""), ]; @@ -1752,29 +1752,29 @@ pub fn rustc_optgroups() -> Vec { "", "extern", "Specify where an external rust library is located", - "NAME[=PATH]", + "[=]", ), - opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"), - opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"), + opt(Stable, Opt, "", "sysroot", "Override the system root", ""), + opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", ""), opt( Stable, Opt, "", "error-format", "How errors and other messages are produced", - "human|json|short", + "", ), - opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"), + opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", ""), opt( Stable, Opt, "", "color", "Configure coloring of output: - auto = colorize, if output goes to a tty (default); - always = always colorize output; - never = never colorize output", - "auto|always|never", + * auto = colorize, if output goes to a tty (default); + * always = always colorize output; + * never = never colorize output", + "", ), opt( Stable, @@ -1782,7 +1782,7 @@ pub fn rustc_optgroups() -> Vec { "", "diagnostic-width", "Inform rustc of the width of the output so that diagnostics can be truncated to fit", - "WIDTH", + "", ), opt( Stable, @@ -1790,9 +1790,9 @@ pub fn rustc_optgroups() -> Vec { "", "remap-path-prefix", "Remap source names in all output (compiler messages and output files)", - "FROM=TO", + "=", ), - opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"), + opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "="), ]; options.extend(verbose_only.into_iter().map(|mut opt| { opt.is_verbose_help_only = true; @@ -2792,7 +2792,7 @@ pub fn make_crate_type_option() -> RustcOptGroup { "crate-type", "Comma separated list of types of crates for the compiler to emit", - "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", + "", ) } diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index da298080ed2f..28335734f4de 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -45,7 +45,7 @@ pub const ALL_EDITIONS: &[Edition] = &[ Edition::EditionFuture, ]; -pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024"; +pub const EDITION_NAME_LIST: &str = "<2015|2018|2021|2024|future>"; pub const DEFAULT_EDITION: Edition = Edition::Edition2015; diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff index 0ea79f3e5573..60a9dfbe201d 100644 --- a/tests/run-make/rustc-help/help-v.diff +++ b/tests/run-make/rustc-help/help-v.diff @@ -1,22 +1,23 @@ -@@ -63,10 +63,27 @@ +@@ -65,10 +65,28 @@ Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output -+ --extern NAME[=PATH] ++ --extern [=] + Specify where an external rust library is located -+ --sysroot PATH Override the system root -+ --error-format human|json|short ++ --sysroot ++ Override the system root ++ --error-format + How errors and other messages are produced -+ --json CONFIG Configure the JSON output of the compiler -+ --color auto|always|never ++ --json Configure the JSON output of the compiler ++ --color + Configure coloring of output: -+ auto = colorize, if output goes to a tty (default); -+ always = always colorize output; -+ never = never colorize output -+ --diagnostic-width WIDTH ++ * auto = colorize, if output goes to a tty (default); ++ * always = always colorize output; ++ * never = never colorize output ++ --diagnostic-width + Inform rustc of the width of the output so that + diagnostics can be truncated to fit -+ --remap-path-prefix FROM=TO ++ --remap-path-prefix = + Remap source names in all output (compiler messages + and output files) + @path Read newline separated options from `path` diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index 744453d6e856..3fc297fb08e7 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -2,31 +2,32 @@ Usage: rustc [OPTIONS] INPUT Options: -h, --help Display this message - --cfg SPEC Configure the compilation environment. - SPEC supports the syntax `NAME[="VALUE"]`. - --check-cfg SPEC + --cfg Configure the compilation environment. + SPEC supports the syntax `[=""]`. + --check-cfg Provide list of expected cfgs for checking - -L [KIND=]PATH Add a directory to the library search path. The - optional KIND can be one of dependency, crate, native, - framework, or all (the default). - -l [KIND[:MODIFIERS]=]NAME[:RENAME] + -L [=] Add a directory to the library search path. The + optional KIND can be one of + (default: + all). + -l [[:]=][:] Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of - static, framework, or dylib (the default). + (default: dylib). Optional comma separated MODIFIERS - (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to enable or '-' to disable. - --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + --crate-type Comma separated list of types of crates for the compiler to emit - --crate-name NAME + --crate-name Specify the name of the crate being built - --edition 2015|2018|2021|2024 + --edition <2015|2018|2021|2024|future> Specify which edition of the compiler to use when compiling code. The default is 2015 and the latest stable edition is 2024. - --emit TYPE[=FILE] + --emit [=] Comma separated list of types of output for the compiler to emit. Each TYPE has the default FILE name: @@ -39,45 +40,47 @@ Options: * mir - CRATE_NAME.mir * obj - CRATE_NAME.o * thin-link-bitcode - CRATE_NAME.indexing.o - --print INFO[=FILE] + --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 - -o FILENAME Write output to - --out-dir DIR Write output to compiler-chosen filename in - --explain OPT Provide a detailed explanation of an error message + -o Write output to FILENAME + --out-dir Write output to compiler-chosen filename in DIR + --explain Provide a detailed explanation of an error message --test Build a test harness - --target TARGET Target triple for which the code is compiled - -A, --allow LINT Set lint allowed - -W, --warn LINT Set lint warnings - --force-warn LINT + --target + Target triple for which the code is compiled + -A, --allow Set lint allowed + -W, --warn Set lint warnings + --force-warn Set lint force-warn - -D, --deny LINT Set lint denied - -F, --forbid LINT Set lint forbidden - --cap-lints LEVEL + -D, --deny Set lint denied + -F, --forbid Set lint forbidden + --cap-lints Set the most restrictive lint level. More restrictive lints are capped at this level - -C, --codegen OPT[=VALUE] + -C, --codegen [=] Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output - --extern NAME[=PATH] + --extern [=] Specify where an external rust library is located - --sysroot PATH Override the system root - --error-format human|json|short + --sysroot + Override the system root + --error-format How errors and other messages are produced - --json CONFIG Configure the JSON output of the compiler - --color auto|always|never + --json Configure the JSON output of the compiler + --color Configure coloring of output: - auto = colorize, if output goes to a tty (default); - always = always colorize output; - never = never colorize output - --diagnostic-width WIDTH + * auto = colorize, if output goes to a tty (default); + * always = always colorize output; + * never = never colorize output + --diagnostic-width Inform rustc of the width of the output so that diagnostics can be truncated to fit - --remap-path-prefix FROM=TO + --remap-path-prefix = Remap source names in all output (compiler messages and output files) @path Read newline separated options from `path` diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 3043755207a6..caffe28f4989 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -2,31 +2,32 @@ Usage: rustc [OPTIONS] INPUT Options: -h, --help Display this message - --cfg SPEC Configure the compilation environment. - SPEC supports the syntax `NAME[="VALUE"]`. - --check-cfg SPEC + --cfg Configure the compilation environment. + SPEC supports the syntax `[=""]`. + --check-cfg Provide list of expected cfgs for checking - -L [KIND=]PATH Add a directory to the library search path. The - optional KIND can be one of dependency, crate, native, - framework, or all (the default). - -l [KIND[:MODIFIERS]=]NAME[:RENAME] + -L [=] Add a directory to the library search path. The + optional KIND can be one of + (default: + all). + -l [[:]=][:] Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of - static, framework, or dylib (the default). + (default: dylib). Optional comma separated MODIFIERS - (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to enable or '-' to disable. - --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + --crate-type Comma separated list of types of crates for the compiler to emit - --crate-name NAME + --crate-name Specify the name of the crate being built - --edition 2015|2018|2021|2024 + --edition <2015|2018|2021|2024|future> Specify which edition of the compiler to use when compiling code. The default is 2015 and the latest stable edition is 2024. - --emit TYPE[=FILE] + --emit [=] Comma separated list of types of output for the compiler to emit. Each TYPE has the default FILE name: @@ -39,27 +40,28 @@ Options: * mir - CRATE_NAME.mir * obj - CRATE_NAME.o * thin-link-bitcode - CRATE_NAME.indexing.o - --print INFO[=FILE] + --print [=] Compiler information to print on stdout (or to a file) INFO may be one of - (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). + . -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 - -o FILENAME Write output to - --out-dir DIR Write output to compiler-chosen filename in - --explain OPT Provide a detailed explanation of an error message + -o Write output to FILENAME + --out-dir Write output to compiler-chosen filename in DIR + --explain Provide a detailed explanation of an error message --test Build a test harness - --target TARGET Target triple for which the code is compiled - -A, --allow LINT Set lint allowed - -W, --warn LINT Set lint warnings - --force-warn LINT + --target + Target triple for which the code is compiled + -A, --allow Set lint allowed + -W, --warn Set lint warnings + --force-warn Set lint force-warn - -D, --deny LINT Set lint denied - -F, --forbid LINT Set lint forbidden - --cap-lints LEVEL + -D, --deny Set lint denied + -F, --forbid Set lint forbidden + --cap-lints Set the most restrictive lint level. More restrictive lints are capped at this level - -C, --codegen OPT[=VALUE] + -C, --codegen [=] Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 01f470f6e162..3f47623cb031 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -11,7 +11,7 @@ Options: -o, --out-dir PATH which directory to place the output --crate-name NAME specify the name of this crate - --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + --crate-type Comma separated list of types of crates for the compiler to emit -L, --library-path DIR diff --git a/tests/ui/compiletest-self-test/compile-flags-last.stderr b/tests/ui/compiletest-self-test/compile-flags-last.stderr index 72d92206e2bb..5a48361cfc0d 100644 --- a/tests/ui/compiletest-self-test/compile-flags-last.stderr +++ b/tests/ui/compiletest-self-test/compile-flags-last.stderr @@ -1,5 +1,5 @@ error: Argument to option 'cap-lints' missing Usage: - --cap-lints LEVEL Set the most restrictive lint level. More restrictive + --cap-lints Set the most restrictive lint level. More restrictive lints are capped at this level diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr index 669913b57653..9e4486a272f9 100644 --- a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr +++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr @@ -1,6 +1,7 @@ error: Argument to option 'emit' missing Usage: - --emit TYPE[=FILE] Comma separated list of types of output for the + --emit [=] + Comma separated list of types of output for the compiler to emit. Each TYPE has the default FILE name: * asm - CRATE_NAME.s diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index fd2a36e761be..3048a59d0d00 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -1,6 +1,7 @@ error: Argument to option 'print' missing Usage: - --print INFO[=FILE] Compiler information to print on stdout (or to a file) + --print [=] + Compiler information to print on stdout (or to a file) INFO may be one of - (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models). + . From 999b9069dd1062efa46d893c0024955d499f8cd8 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 25 Apr 2025 19:37:42 +0800 Subject: [PATCH 109/109] Add option style comment for `rustc_optgroups` Signed-off-by: xizheyin --- compiler/rustc_session/src/config.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c06f3c97da76..cc506b0164ee 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1665,6 +1665,13 @@ static EMIT_HELP: LazyLock = LazyLock::new(|| { /// Returns all rustc command line options, including metadata for /// each option, such as whether the option is stable. +/// +/// # Option style guidelines +/// +/// - ``: Indicates a required parameter +/// - `[param]`: Indicates an optional parameter +/// - `|`: Indicates a mutually exclusive option +/// - `*`: a list element with description pub fn rustc_optgroups() -> Vec { use OptionKind::{Flag, FlagMulti, Multi, Opt}; use OptionStability::{Stable, Unstable};