Auto merge of #102975 - Dylan-DPC:rollup-vzuwsh2, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #102623 (translation: eager translation) - #102719 (Enforce alphabetical sorting with tidy) - #102830 (Unify `tcx.constness` query and param env constness checks) - #102883 (Fix stabilization of `feature(half_open_range_patterns)`) - #102927 (Fix `let` keyword removal suggestion in structs) - #102936 (rustdoc: remove unused CSS `nav.sum`) - #102940 (Update books) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c0983a9aac
compiler
rustc_ast/src
rustc_ast_lowering/src
rustc_ast_passes/src
rustc_codegen_ssa/src/back
rustc_const_eval/src
rustc_error_messages
rustc_errors/src
rustc_feature/src
rustc_hir/src
rustc_infer/src/errors
rustc_interface/src
rustc_lint/src
rustc_macros/src/diagnostics
rustc_metadata/src/rmeta
rustc_middle/src
rustc_parse/src/parser
rustc_query_system/src
rustc_session/src
rustc_target/src/abi/call
rustc_ty_utils/src
src
doc
librustdoc
test
rustdoc-ui
ui-fulldeps
internal-lints
session-diagnostic
ui/parser
tools/tidy/src
@ -3039,7 +3039,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(AssocItem, 104);
|
||||
static_assert_size!(AssocItemKind, 32);
|
||||
static_assert_size!(Attribute, 32);
|
||||
@ -3060,11 +3060,12 @@ mod size_asserts {
|
||||
static_assert_size!(Local, 72);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 120);
|
||||
static_assert_size!(PatKind, 96);
|
||||
static_assert_size!(Path, 40);
|
||||
static_assert_size!(PathSegment, 24);
|
||||
static_assert_size!(PatKind, 96);
|
||||
static_assert_size!(Stmt, 32);
|
||||
static_assert_size!(StmtKind, 16);
|
||||
static_assert_size!(Ty, 96);
|
||||
static_assert_size!(TyKind, 72);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -889,10 +889,11 @@ where
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Lit, 12);
|
||||
static_assert_size!(LitKind, 2);
|
||||
static_assert_size!(Nonterminal, 16);
|
||||
static_assert_size!(Token, 24);
|
||||
static_assert_size!(TokenKind, 16);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -646,10 +646,11 @@ impl DelimSpan {
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(AttrTokenStream, 8);
|
||||
static_assert_size!(AttrTokenTree, 32);
|
||||
static_assert_size!(LazyAttrTokenStream, 8);
|
||||
static_assert_size!(TokenStream, 8);
|
||||
static_assert_size!(TokenTree, 32);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay};
|
||||
use rustc_errors::{
|
||||
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay,
|
||||
SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
@ -19,7 +22,10 @@ pub struct UseAngleBrackets {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for UseAngleBrackets {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.multipart_suggestion(
|
||||
fluent::ast_lowering::use_angle_brackets,
|
||||
vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
|
||||
@ -69,7 +75,10 @@ pub enum AssocTyParenthesesSub {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for AssocTyParenthesesSub {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
Self::Empty { parentheses_span } => diag.multipart_suggestion(
|
||||
fluent::ast_lowering::remove_parentheses,
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic};
|
||||
use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
@ -17,7 +17,10 @@ pub struct ForbiddenLet {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for ForbiddenLetReason {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
Self::GenericForbidden => {}
|
||||
Self::NotSupportedOr(span) => {
|
||||
@ -228,7 +231,10 @@ pub struct ExternBlockSuggestion {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for ExternBlockSuggestion {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let start_suggestion = if let Some(abi) = self.abi {
|
||||
format!("extern \"{}\" {{", abi)
|
||||
} else {
|
||||
|
@ -15,7 +15,10 @@ use rustc_data_structures::profiling::TimingGuard;
|
||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
|
||||
use rustc_errors::{
|
||||
translation::{to_fluent_args, Translate},
|
||||
DiagnosticId, FatalError, Handler, Level,
|
||||
};
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_incremental::{
|
||||
@ -1740,7 +1743,7 @@ impl Translate for SharedEmitter {
|
||||
|
||||
impl Emitter for SharedEmitter {
|
||||
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
||||
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
||||
code: diag.code.clone(),
|
||||
|
@ -25,12 +25,10 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
|
||||
/// `Constness::NotConst`.
|
||||
fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
|
||||
let def_id = def_id.expect_local();
|
||||
let node = tcx.hir().get_by_def_id(def_id);
|
||||
|
||||
match node {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir().get(hir_id) {
|
||||
hir::Node::Ctor(_) => hir::Constness::Const,
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
|
||||
|
||||
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
|
||||
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
||||
// foreign items cannot be evaluated at compile-time.
|
||||
@ -41,20 +39,62 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
|
||||
};
|
||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
||||
}
|
||||
_ => {
|
||||
if let Some(fn_kind) = node.fn_kind() {
|
||||
if fn_kind.constness() == hir::Constness::Const {
|
||||
return hir::Constness::Const;
|
||||
}
|
||||
|
||||
// If the function itself is not annotated with `const`, it may still be a `const fn`
|
||||
// if it resides in a const trait impl.
|
||||
let is_const = is_parent_const_impl_raw(tcx, def_id);
|
||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
||||
if tcx.is_const_default_method(def_id) =>
|
||||
{
|
||||
hir::Constness::Const
|
||||
}
|
||||
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
|
||||
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
|
||||
| hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind:
|
||||
hir::ImplItemKind::Fn(
|
||||
hir::FnSig {
|
||||
header: hir::FnHeader { constness: hir::Constness::Const, .. },
|
||||
..
|
||||
},
|
||||
..,
|
||||
),
|
||||
..
|
||||
}) => hir::Constness::Const,
|
||||
|
||||
hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
|
||||
..
|
||||
}) => {
|
||||
let parent_hir_id = tcx.hir().get_parent_node(hir_id);
|
||||
match tcx.hir().get(parent_hir_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
||||
..
|
||||
}) => *constness,
|
||||
_ => span_bug!(
|
||||
tcx.def_span(parent_hir_id.owner),
|
||||
"impl item's parent node is not an impl",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind:
|
||||
hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
||||
..
|
||||
}) => *constness,
|
||||
|
||||
_ => hir::Constness::NotConst,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -788,9 +788,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Immediate, 48);
|
||||
static_assert_size!(ImmTy<'_>, 64);
|
||||
static_assert_size!(Operand, 56);
|
||||
static_assert_size!(OpTy<'_>, 80);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -892,10 +892,11 @@ where
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
static_assert_size!(MemPlaceMeta, 24);
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(MemPlace, 40);
|
||||
static_assert_size!(MemPlaceMeta, 24);
|
||||
static_assert_size!(MPlaceTy<'_>, 64);
|
||||
static_assert_size!(Place, 40);
|
||||
static_assert_size!(PlaceTy<'_>, 64);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ query_system_cycle_usage = cycle used when {$usage}
|
||||
|
||||
query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
|
||||
|
||||
query_system_cycle_stack_middle = ...which requires {$desc}...
|
||||
|
||||
query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
|
||||
|
||||
query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
|
||||
|
@ -35,6 +35,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
|
||||
|
||||
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
||||
fluent_messages! {
|
||||
// tidy-alphabetical-start
|
||||
ast_lowering => "../locales/en-US/ast_lowering.ftl",
|
||||
ast_passes => "../locales/en-US/ast_passes.ftl",
|
||||
attr => "../locales/en-US/attr.ftl",
|
||||
@ -64,6 +65,7 @@ fluent_messages! {
|
||||
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
|
||||
trait_selection => "../locales/en-US/trait_selection.ftl",
|
||||
ty_utils => "../locales/en-US/ty_utils.ftl",
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
|
||||
@ -277,6 +279,18 @@ pub enum SubdiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
/// Identifier of a Fluent message. Instances of this variant are generated by the
|
||||
/// `Subdiagnostic` derive.
|
||||
FluentIdentifier(FluentId),
|
||||
@ -304,8 +318,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
|
||||
#[rustc_diagnostic_item = "DiagnosticMessage"]
|
||||
pub enum DiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
|
||||
/// message.
|
||||
///
|
||||
@ -324,6 +350,7 @@ impl DiagnosticMessage {
|
||||
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
|
||||
let attr = match sub {
|
||||
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
|
||||
SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
|
||||
SubdiagnosticMessage::FluentIdentifier(id) => {
|
||||
return DiagnosticMessage::FluentIdentifier(id, None);
|
||||
}
|
||||
@ -332,6 +359,7 @@ impl DiagnosticMessage {
|
||||
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
|
||||
DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
|
||||
DiagnosticMessage::FluentIdentifier(id, _) => {
|
||||
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
|
||||
}
|
||||
@ -367,6 +395,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
|
||||
fn into(self) -> SubdiagnosticMessage {
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
|
||||
DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
|
||||
DiagnosticMessage::FluentIdentifier(id, None) => {
|
||||
SubdiagnosticMessage::FluentIdentifier(id)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
use crate::emitter::FileWithAnnotatedLines;
|
||||
use crate::snippet::Line;
|
||||
use crate::translation::Translate;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
||||
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
||||
@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
|
||||
impl Emitter for AnnotateSnippetEmitterWriter {
|
||||
/// The entry point for the diagnostics generation
|
||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
|
||||
let mut children = diag.children.clone();
|
||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
||||
|
@ -27,7 +27,11 @@ pub struct SuggestionsDisabled;
|
||||
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
|
||||
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
||||
/// diagnostic emission.
|
||||
pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>);
|
||||
pub type DiagnosticArg<'iter, 'source> =
|
||||
(&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>);
|
||||
|
||||
/// Name of a diagnostic argument.
|
||||
pub type DiagnosticArgName<'source> = Cow<'source, str>;
|
||||
|
||||
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
|
||||
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
||||
@ -199,9 +203,20 @@ impl IntoDiagnosticArg for ast::token::TokenKind {
|
||||
/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
|
||||
#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
|
||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
|
||||
pub trait AddToDiagnostic {
|
||||
pub trait AddToDiagnostic
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Add a subdiagnostic to an existing diagnostic.
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic);
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
self.add_to_diagnostic_with(diag, |_, m| m);
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
|
||||
/// (to optionally perform eager translation).
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage;
|
||||
}
|
||||
|
||||
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
|
||||
@ -229,7 +244,7 @@ pub struct Diagnostic {
|
||||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
args: Vec<DiagnosticArg<'static>>,
|
||||
args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
|
||||
|
||||
/// This is not used for highlighting or rendering any error message. Rather, it can be used
|
||||
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
|
||||
@ -321,7 +336,7 @@ impl Diagnostic {
|
||||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
suggestions: Ok(vec![]),
|
||||
args: vec![],
|
||||
args: Default::default(),
|
||||
sort_span: DUMMY_SP,
|
||||
is_lint: false,
|
||||
}
|
||||
@ -917,13 +932,30 @@ impl Diagnostic {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` - see
|
||||
/// [rustc_macros::Subdiagnostic].
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]).
|
||||
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
|
||||
subdiagnostic.add_to_diagnostic(self);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
|
||||
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
|
||||
/// interpolated variables).
|
||||
pub fn eager_subdiagnostic(
|
||||
&mut self,
|
||||
handler: &crate::Handler,
|
||||
subdiagnostic: impl AddToDiagnostic,
|
||||
) -> &mut Self {
|
||||
subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
|
||||
let args = diag.args();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
handler.eagerly_translate(msg, args)
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
|
||||
self.span = sp.into();
|
||||
if let Some(span) = self.span.primary_span() {
|
||||
@ -956,8 +988,11 @@ impl Diagnostic {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn args(&self) -> &[DiagnosticArg<'static>] {
|
||||
&self.args
|
||||
// Exact iteration order of diagnostic arguments shouldn't make a difference to output because
|
||||
// they're only used in interpolation.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
pub fn set_arg(
|
||||
@ -965,7 +1000,7 @@ impl Diagnostic {
|
||||
name: impl Into<Cow<'static, str>>,
|
||||
arg: impl IntoDiagnosticArg,
|
||||
) -> &mut Self {
|
||||
self.args.push((name.into(), arg.into_diagnostic_arg()));
|
||||
self.args.insert(name.into(), arg.into_diagnostic_arg());
|
||||
self
|
||||
}
|
||||
|
||||
@ -976,7 +1011,7 @@ impl Diagnostic {
|
||||
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
|
||||
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||
/// passes the user's string along).
|
||||
fn subdiagnostic_message_to_diagnostic_message(
|
||||
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||
&self,
|
||||
attr: impl Into<SubdiagnosticMessage>,
|
||||
) -> DiagnosticMessage {
|
||||
|
@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span};
|
||||
|
||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
||||
use crate::styled_buffer::StyledBuffer;
|
||||
use crate::translation::Translate;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
||||
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
||||
@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
|
||||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
|
||||
let mut children = diag.children.clone();
|
||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
||||
|
@ -13,7 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
|
||||
use crate::emitter::{Emitter, HumanReadableErrorType};
|
||||
use crate::registry::Registry;
|
||||
use crate::translation::Translate;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::DiagnosticId;
|
||||
use crate::{
|
||||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
||||
@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
|
||||
|
||||
impl Diagnostic {
|
||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
|
||||
let args = je.to_fluent_args(diag.args());
|
||||
let args = to_fluent_args(diag.args());
|
||||
let sugg = diag.suggestions.iter().flatten().map(|sugg| {
|
||||
let translated_message = je.translate_message(&sugg.msg, &args);
|
||||
Diagnostic {
|
||||
|
@ -598,6 +598,17 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args`.
|
||||
pub fn eagerly_translate<'a>(
|
||||
&self,
|
||||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
let inner = self.inner.borrow();
|
||||
let args = crate::translation::to_fluent_args(args);
|
||||
SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string())
|
||||
}
|
||||
|
||||
// This is here to not allow mutation of flags;
|
||||
// as of this writing it's only used in tests in librustc_middle.
|
||||
pub fn can_emit_warnings(&self) -> bool {
|
||||
|
@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_messages::FluentArgs;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Convert diagnostic arguments (a rustc internal type that exists to implement
|
||||
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
|
||||
///
|
||||
/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
|
||||
/// passed around as a reference thereafter.
|
||||
pub fn to_fluent_args<'iter, 'arg: 'iter>(
|
||||
iter: impl Iterator<Item = DiagnosticArg<'iter, 'arg>>,
|
||||
) -> FluentArgs<'arg> {
|
||||
let mut args = if let Some(size) = iter.size_hint().1 {
|
||||
FluentArgs::with_capacity(size)
|
||||
} else {
|
||||
FluentArgs::new()
|
||||
};
|
||||
|
||||
for (k, v) in iter {
|
||||
args.set(k.clone(), v.clone());
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
pub trait Translate {
|
||||
/// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
|
||||
/// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
|
||||
@ -15,15 +36,6 @@ pub trait Translate {
|
||||
/// unavailable for the requested locale.
|
||||
fn fallback_fluent_bundle(&self) -> &FluentBundle;
|
||||
|
||||
/// Convert diagnostic arguments (a rustc internal type that exists to implement
|
||||
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
|
||||
///
|
||||
/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
|
||||
/// passed around as a reference thereafter.
|
||||
fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
|
||||
FromIterator::from_iter(args.iter().cloned())
|
||||
}
|
||||
|
||||
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
|
||||
fn translate_messages(
|
||||
&self,
|
||||
@ -43,7 +55,9 @@ pub trait Translate {
|
||||
) -> Cow<'_, str> {
|
||||
trace!(?message, ?args);
|
||||
let (identifier, attr) = match message {
|
||||
DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
|
||||
return Cow::Borrowed(&msg);
|
||||
}
|
||||
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
|
||||
};
|
||||
|
||||
|
@ -412,8 +412,6 @@ declare_features! (
|
||||
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
|
||||
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
||||
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
||||
/// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
|
||||
(active, half_open_range_patterns, "1.41.0", Some(67264), None),
|
||||
/// Allows using `..=X` as a patterns in slices.
|
||||
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
|
||||
/// Allows `if let` guard in match arms.
|
||||
|
@ -3514,7 +3514,7 @@ impl<'hir> Node<'hir> {
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Block<'_>, 48);
|
||||
static_assert_size!(Body<'_>, 32);
|
||||
static_assert_size!(Expr<'_>, 64);
|
||||
@ -3533,9 +3533,9 @@ mod size_asserts {
|
||||
static_assert_size!(Local<'_>, 64);
|
||||
static_assert_size!(Param<'_>, 32);
|
||||
static_assert_size!(Pat<'_>, 72);
|
||||
static_assert_size!(PatKind<'_>, 48);
|
||||
static_assert_size!(Path<'_>, 40);
|
||||
static_assert_size!(PathSegment<'_>, 48);
|
||||
static_assert_size!(PatKind<'_>, 48);
|
||||
static_assert_size!(QPath<'_>, 24);
|
||||
static_assert_size!(Res, 12);
|
||||
static_assert_size!(Stmt<'_>, 32);
|
||||
@ -3544,4 +3544,5 @@ mod size_asserts {
|
||||
static_assert_size!(TraitItemKind<'_>, 48);
|
||||
static_assert_size!(Ty<'_>, 48);
|
||||
static_assert_size!(TyKind<'_>, 32);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use hir::GenericParamKind;
|
||||
use rustc_errors::{
|
||||
fluent, AddToDiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
|
||||
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
|
||||
MultiSpan, SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{FnRetTy, Ty};
|
||||
@ -229,7 +230,10 @@ pub enum RegionOriginNote<'a> {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for RegionOriginNote<'_> {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let mut label_or_note = |span, msg: DiagnosticMessage| {
|
||||
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
|
||||
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
|
||||
@ -290,7 +294,10 @@ pub enum LifetimeMismatchLabels {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for LifetimeMismatchLabels {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
||||
diag.span_label(param_span, fluent::infer::declared_different);
|
||||
@ -340,7 +347,10 @@ pub struct AddLifetimeParamsSuggestion<'a> {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let mut mk_suggestion = || {
|
||||
let (
|
||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
|
||||
@ -439,7 +449,10 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
|
||||
fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
self.unmet_requirements
|
||||
.push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
|
||||
diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
|
||||
@ -451,7 +464,10 @@ pub struct ImplNote {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for ImplNote {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self.impl_span {
|
||||
Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
|
||||
None => diag.note(fluent::infer::msl_impl_note),
|
||||
@ -466,7 +482,10 @@ pub enum TraitSubdiag {
|
||||
|
||||
// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
|
||||
impl AddToDiagnostic for TraitSubdiag {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
TraitSubdiag::Note { span } => {
|
||||
diag.span_note(span, "this has an implicit `'static` lifetime requirement");
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::infer::error_reporting::nice_region_error::find_anon_type;
|
||||
use rustc_errors::{self, fluent, AddToDiagnostic, IntoDiagnosticArg};
|
||||
use rustc_errors::{
|
||||
self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::{symbol::kw, Span};
|
||||
|
||||
@ -159,7 +161,10 @@ impl RegionExplanation<'_> {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for RegionExplanation<'_> {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
if let Some(span) = self.desc.span {
|
||||
diag.span_note(span, fluent::infer::region_explanation);
|
||||
} else {
|
||||
|
@ -540,7 +540,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
}
|
||||
|
||||
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
|
||||
// This list is in alphabetical order.
|
||||
// tidy-alphabetical-start
|
||||
untracked!(ar, String::from("abc"));
|
||||
untracked!(codegen_units, Some(42));
|
||||
untracked!(default_linker_libraries, true);
|
||||
@ -556,6 +556,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
untracked!(rpath, true);
|
||||
untracked!(save_temps, true);
|
||||
untracked!(strip, Strip::Debuginfo);
|
||||
// tidy-alphabetical-end
|
||||
|
||||
macro_rules! tracked {
|
||||
($name: ident, $non_default_value: expr) => {
|
||||
@ -567,7 +568,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
}
|
||||
|
||||
// Make sure that changing a [TRACKED] option changes the hash.
|
||||
// This list is in alphabetical order.
|
||||
// tidy-alphabetical-start
|
||||
tracked!(code_model, Some(CodeModel::Large));
|
||||
tracked!(control_flow_guard, CFGuard::Checks);
|
||||
tracked!(debug_assertions, Some(true));
|
||||
@ -577,8 +578,8 @@ fn test_codegen_options_tracking_hash() {
|
||||
tracked!(force_unwind_tables, Some(true));
|
||||
tracked!(inline_threshold, Some(0xf007ba11));
|
||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
||||
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
||||
tracked!(link_dead_code, Some(true));
|
||||
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
||||
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
||||
tracked!(lto, LtoCli::Fat);
|
||||
tracked!(metadata, vec![String::from("A"), String::from("B")]);
|
||||
@ -599,6 +600,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
|
||||
tracked!(target_cpu, Some(String::from("abc")));
|
||||
tracked!(target_feature, String::from("all the features, all of them"));
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -619,12 +621,13 @@ fn test_top_level_options_tracked_no_crate() {
|
||||
}
|
||||
|
||||
// Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash.
|
||||
// This list is in alphabetical order.
|
||||
tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
|
||||
// tidy-alphabetical-start
|
||||
tracked!(
|
||||
real_rust_source_base_dir,
|
||||
Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
|
||||
);
|
||||
tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -641,7 +644,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
}
|
||||
|
||||
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
|
||||
// This list is in alphabetical order.
|
||||
// tidy-alphabetical-start
|
||||
untracked!(assert_incr_state, Some(String::from("loaded")));
|
||||
untracked!(deduplicate_diagnostics, false);
|
||||
untracked!(dep_tasks, true);
|
||||
@ -678,12 +681,12 @@ fn test_unstable_options_tracking_hash() {
|
||||
untracked!(perf_stats, true);
|
||||
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
|
||||
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
|
||||
untracked!(profile_closures, true);
|
||||
untracked!(print_llvm_passes, true);
|
||||
untracked!(print_mono_items, Some(String::from("abc")));
|
||||
untracked!(print_type_sizes, true);
|
||||
untracked!(proc_macro_backtrace, true);
|
||||
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
|
||||
untracked!(profile_closures, true);
|
||||
untracked!(query_dep_graph, true);
|
||||
untracked!(save_analysis, true);
|
||||
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
|
||||
@ -701,6 +704,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
untracked!(unstable_options, true);
|
||||
untracked!(validate_mir, true);
|
||||
untracked!(verbose, true);
|
||||
// tidy-alphabetical-end
|
||||
|
||||
macro_rules! tracked {
|
||||
($name: ident, $non_default_value: expr) => {
|
||||
@ -712,7 +716,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
}
|
||||
|
||||
// Make sure that changing a [TRACKED] option changes the hash.
|
||||
// This list is in alphabetical order.
|
||||
// tidy-alphabetical-start
|
||||
tracked!(allow_features, Some(vec![String::from("lang_items")]));
|
||||
tracked!(always_encode_mir, true);
|
||||
tracked!(asm_comments, true);
|
||||
@ -733,10 +737,10 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(debug_macros, true);
|
||||
tracked!(dep_info_omit_d_target, true);
|
||||
tracked!(drop_tracking, true);
|
||||
tracked!(export_executable_symbols, true);
|
||||
tracked!(dual_proc_macros, true);
|
||||
tracked!(dwarf_version, Some(5));
|
||||
tracked!(emit_thin_lto, false);
|
||||
tracked!(export_executable_symbols, true);
|
||||
tracked!(fewer_names, Some(true));
|
||||
tracked!(force_unstable_if_unmarked, true);
|
||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||
@ -759,8 +763,8 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(mutable_noalias, Some(true));
|
||||
tracked!(no_generate_arange_section, true);
|
||||
tracked!(no_link, true);
|
||||
tracked!(no_unique_section_names, true);
|
||||
tracked!(no_profiler_runtime, true);
|
||||
tracked!(no_unique_section_names, true);
|
||||
tracked!(oom, OomStrategy::Panic);
|
||||
tracked!(osx_rpath_install_name, true);
|
||||
tracked!(packed_bundled_libs, true);
|
||||
@ -773,8 +777,8 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(print_fuel, Some("abc".to_string()));
|
||||
tracked!(profile, true);
|
||||
tracked!(profile_emit, Some(PathBuf::from("abc")));
|
||||
tracked!(profiler_runtime, "abc".to_string());
|
||||
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
||||
tracked!(profiler_runtime, "abc".to_string());
|
||||
tracked!(relax_elf_relocations, Some(true));
|
||||
tracked!(relro_level, Some(RelroLevel::Full));
|
||||
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
||||
@ -803,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(verify_llvm_ir, true);
|
||||
tracked!(virtual_function_elimination, true);
|
||||
tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
|
||||
// tidy-alphabetical-end
|
||||
|
||||
macro_rules! tracked_no_crate_hash {
|
||||
($name: ident, $non_default_value: expr) => {
|
||||
|
@ -1,4 +1,7 @@
|
||||
use rustc_errors::{fluent, AddToDiagnostic, ErrorGuaranteed, Handler, IntoDiagnostic};
|
||||
use rustc_errors::{
|
||||
fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
|
||||
SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::{Span, Symbol};
|
||||
@ -23,7 +26,10 @@ pub enum OverruledAttributeSub {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for OverruledAttributeSub {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
OverruledAttributeSub::DefaultSource { id } => {
|
||||
diag.note(fluent::lint::default_source);
|
||||
@ -88,7 +94,10 @@ pub struct RequestedLevel {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for RequestedLevel {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.note(fluent::lint::requested_level);
|
||||
diag.set_arg(
|
||||
"level",
|
||||
|
@ -10,27 +10,31 @@ use synstructure::Structure;
|
||||
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
||||
pub(crate) struct DiagnosticDerive<'a> {
|
||||
structure: Structure<'a>,
|
||||
handler: syn::Ident,
|
||||
builder: DiagnosticDeriveBuilder,
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticDerive<'a> {
|
||||
pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
|
||||
Self {
|
||||
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
|
||||
handler,
|
||||
builder: DiagnosticDeriveBuilder {
|
||||
diag,
|
||||
kind: DiagnosticDeriveKind::Diagnostic { handler },
|
||||
},
|
||||
structure,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let DiagnosticDerive { mut structure, handler, mut builder } = self;
|
||||
let DiagnosticDerive { mut structure, mut builder } = self;
|
||||
|
||||
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||
let preamble = builder.preamble(&variant);
|
||||
let body = builder.body(&variant);
|
||||
|
||||
let diag = &builder.parent.diag;
|
||||
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
|
||||
unreachable!()
|
||||
};
|
||||
let init = match builder.slug.value_ref() {
|
||||
None => {
|
||||
span_err(builder.span, "diagnostic slug not specified")
|
||||
@ -48,14 +52,17 @@ impl<'a> DiagnosticDerive<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let formatting_init = &builder.formatting_init;
|
||||
quote! {
|
||||
#init
|
||||
#formatting_init
|
||||
#preamble
|
||||
#body
|
||||
#diag
|
||||
}
|
||||
});
|
||||
|
||||
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
|
||||
structure.gen_impl(quote! {
|
||||
gen impl<'__diagnostic_handler_sess, G>
|
||||
rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
|
||||
@ -96,17 +103,18 @@ impl<'a> LintDiagnosticDerive<'a> {
|
||||
let body = builder.body(&variant);
|
||||
|
||||
let diag = &builder.parent.diag;
|
||||
|
||||
let formatting_init = &builder.formatting_init;
|
||||
quote! {
|
||||
#preamble
|
||||
#formatting_init
|
||||
#body
|
||||
#diag
|
||||
}
|
||||
});
|
||||
|
||||
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||
// HACK(wafflelapkin): initialize slug (???)
|
||||
let _preamble = builder.preamble(&variant);
|
||||
// Collect the slug by generating the preamble.
|
||||
let _ = builder.preamble(&variant);
|
||||
|
||||
match builder.slug.value_ref() {
|
||||
None => {
|
||||
@ -125,7 +133,10 @@ impl<'a> LintDiagnosticDerive<'a> {
|
||||
let diag = &builder.diag;
|
||||
structure.gen_impl(quote! {
|
||||
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
|
||||
fn decorate_lint<'__b>(self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
|
||||
fn decorate_lint<'__b>(
|
||||
self,
|
||||
#diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
|
||||
) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
|
||||
use rustc_errors::IntoDiagnosticArg;
|
||||
#implementation
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ use crate::diagnostics::error::{
|
||||
DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
bind_style_of_field, build_field_mapping, report_error_if_not_applied_to_span,
|
||||
report_type_error, should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo,
|
||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
|
||||
should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
|
||||
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@ -17,9 +17,9 @@ use syn::{
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) enum DiagnosticDeriveKind {
|
||||
Diagnostic,
|
||||
Diagnostic { handler: syn::Ident },
|
||||
LintDiagnostic,
|
||||
}
|
||||
|
||||
@ -40,6 +40,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
|
||||
/// The parent builder for the entire type.
|
||||
pub parent: &'parent DiagnosticDeriveBuilder,
|
||||
|
||||
/// Initialization of format strings for code suggestions.
|
||||
pub formatting_init: TokenStream,
|
||||
|
||||
/// Span of the struct or the enum variant.
|
||||
pub span: proc_macro::Span,
|
||||
|
||||
@ -88,19 +91,7 @@ impl DiagnosticDeriveBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
for variant in structure.variants_mut() {
|
||||
// First, change the binding style of each field based on the code that will be
|
||||
// generated for the field - e.g. `set_arg` calls needs by-move bindings, whereas
|
||||
// `set_primary_span` only needs by-ref.
|
||||
variant.bind_with(|bi| bind_style_of_field(bi.ast()).0);
|
||||
|
||||
// Then, perform a stable sort on bindings which generates code for by-ref bindings
|
||||
// before code generated for by-move bindings. Any code generated for the by-ref
|
||||
// bindings which creates a reference to the by-move fields will happen before the
|
||||
// by-move bindings move those fields and make them inaccessible.
|
||||
variant.bindings_mut().sort_by_cached_key(|bi| bind_style_of_field(bi.ast()));
|
||||
}
|
||||
|
||||
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||
let variants = structure.each_variant(|variant| {
|
||||
let span = match structure.ast().data {
|
||||
syn::Data::Struct(..) => span,
|
||||
@ -112,6 +103,7 @@ impl DiagnosticDeriveBuilder {
|
||||
parent: &self,
|
||||
span,
|
||||
field_map: build_field_mapping(variant),
|
||||
formatting_init: TokenStream::new(),
|
||||
slug: None,
|
||||
code: None,
|
||||
};
|
||||
@ -143,16 +135,14 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
|
||||
/// Generates calls to `span_label` and similar functions based on the attributes on fields or
|
||||
/// calls to `set_arg` when no attributes are present.
|
||||
///
|
||||
/// Expects use of `Self::each_variant` which will have sorted bindings so that by-ref bindings
|
||||
/// (which may create references to by-move bindings) have their code generated first -
|
||||
/// necessary as code for suggestions uses formatting machinery and the value of other fields
|
||||
/// (any given field can be referenced multiple times, so must be accessed through a borrow);
|
||||
/// and when passing fields to `add_subdiagnostic` or `set_arg` for Fluent, fields must be
|
||||
/// accessed by-move.
|
||||
pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
|
||||
let mut body = quote! {};
|
||||
for binding in variant.bindings() {
|
||||
// Generate `set_arg` calls first..
|
||||
for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
|
||||
body.extend(self.generate_field_code(binding));
|
||||
}
|
||||
// ..and then subdiagnostic additions.
|
||||
for binding in variant.bindings().iter().filter(|bi| !should_generate_set_arg(bi.ast())) {
|
||||
body.extend(self.generate_field_attrs_code(binding));
|
||||
}
|
||||
body
|
||||
@ -274,24 +264,27 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_field_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
|
||||
let diag = &self.parent.diag;
|
||||
|
||||
let field = binding_info.ast();
|
||||
let field_binding = &binding_info.binding;
|
||||
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
|
||||
|
||||
quote! {
|
||||
#diag.set_arg(
|
||||
stringify!(#ident),
|
||||
#field_binding
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
|
||||
let field = binding_info.ast();
|
||||
let field_binding = &binding_info.binding;
|
||||
|
||||
if should_generate_set_arg(&field) {
|
||||
let diag = &self.parent.diag;
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
// strip `r#` prefix, if present
|
||||
let ident = format_ident!("{}", ident);
|
||||
return quote! {
|
||||
#diag.set_arg(
|
||||
stringify!(#ident),
|
||||
#field_binding
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let needs_move = bind_style_of_field(&field).is_move();
|
||||
let inner_ty = FieldInnerTy::from_type(&field.ty);
|
||||
|
||||
field
|
||||
@ -304,10 +297,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
let (binding, needs_destructure) = if needs_clone {
|
||||
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
||||
(quote! { #field_binding.clone() }, false)
|
||||
} else if needs_move {
|
||||
(quote! { #field_binding }, true)
|
||||
} else {
|
||||
(quote! { *#field_binding }, true)
|
||||
(quote! { #field_binding }, true)
|
||||
};
|
||||
|
||||
let generated_code = self
|
||||
@ -340,18 +331,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
let diag = &self.parent.diag;
|
||||
let meta = attr.parse_meta()?;
|
||||
|
||||
if let Meta::Path(_) = meta {
|
||||
let ident = &attr.path.segments.last().unwrap().ident;
|
||||
let name = ident.to_string();
|
||||
let name = name.as_str();
|
||||
match name {
|
||||
"skip_arg" => {
|
||||
// Don't need to do anything - by virtue of the attribute existing, the
|
||||
// `set_arg` call will not be generated.
|
||||
return Ok(quote! {});
|
||||
}
|
||||
"primary_span" => match self.parent.kind {
|
||||
DiagnosticDeriveKind::Diagnostic => {
|
||||
let ident = &attr.path.segments.last().unwrap().ident;
|
||||
let name = ident.to_string();
|
||||
match (&meta, name.as_str()) {
|
||||
// Don't need to do anything - by virtue of the attribute existing, the
|
||||
// `set_arg` call will not be generated.
|
||||
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
|
||||
(Meta::Path(_), "primary_span") => {
|
||||
match self.parent.kind {
|
||||
DiagnosticDeriveKind::Diagnostic { .. } => {
|
||||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
|
||||
return Ok(quote! {
|
||||
@ -363,10 +351,50 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
|
||||
})
|
||||
}
|
||||
},
|
||||
"subdiagnostic" => return Ok(quote! { #diag.subdiagnostic(#binding); }),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(Meta::Path(_), "subdiagnostic") => {
|
||||
return Ok(quote! { #diag.subdiagnostic(#binding); });
|
||||
}
|
||||
(Meta::NameValue(_), "subdiagnostic") => {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
|
||||
})
|
||||
}
|
||||
(Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
|
||||
if nested.len() != 1 {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help(
|
||||
"`eager` is the only supported nested attribute for `subdiagnostic`",
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let handler = match &self.parent.kind {
|
||||
DiagnosticDeriveKind::Diagnostic { handler } => handler,
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("eager subdiagnostics are not supported on lints")
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let nested_attr = nested.first().expect("pop failed for single element list");
|
||||
match nested_attr {
|
||||
NestedMeta::Meta(meta @ Meta::Path(_))
|
||||
if meta.path().segments.last().unwrap().ident.to_string().as_str()
|
||||
== "eager" =>
|
||||
{
|
||||
return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
|
||||
}
|
||||
_ => {
|
||||
throw_invalid_nested_attr!(attr, nested_attr, |diag| {
|
||||
diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
|
||||
@ -389,7 +417,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
suggestion_kind,
|
||||
applicability: static_applicability,
|
||||
code,
|
||||
code_field,
|
||||
code_init,
|
||||
} => {
|
||||
let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
|
||||
|
||||
@ -402,11 +431,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
.unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
|
||||
let style = suggestion_kind.to_suggestion_style();
|
||||
|
||||
self.formatting_init.extend(code_init);
|
||||
Ok(quote! {
|
||||
#diag.span_suggestion_with_style(
|
||||
#span_field,
|
||||
rustc_errors::fluent::#slug,
|
||||
#code,
|
||||
#code_field,
|
||||
#applicability,
|
||||
#style
|
||||
);
|
||||
@ -451,7 +481,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
|
||||
ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
|
||||
let binding = &info.binding.binding;
|
||||
Ok((quote!(*#binding), None))
|
||||
Ok((quote!(#binding), None))
|
||||
}
|
||||
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
|
||||
Type::Tuple(tup) => {
|
||||
|
@ -9,7 +9,7 @@ use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
|
||||
pub(crate) use fluent::fluent_messages;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::format_ident;
|
||||
use subdiagnostic::SubdiagnosticDerive;
|
||||
use subdiagnostic::SubdiagnosticDeriveBuilder;
|
||||
use synstructure::Structure;
|
||||
|
||||
/// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
|
||||
@ -155,5 +155,5 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
|
||||
/// ```
|
||||
pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
SubdiagnosticDerive::new(s).into_tokens()
|
||||
SubdiagnosticDeriveBuilder::new().into_tokens(s)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::diagnostics::error::{
|
||||
DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
build_field_mapping, report_error_if_not_applied_to_applicability,
|
||||
build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
|
||||
report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
||||
SpannedOption, SubdiagnosticKind,
|
||||
};
|
||||
@ -15,19 +15,19 @@ use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
||||
pub(crate) struct SubdiagnosticDerive<'a> {
|
||||
structure: Structure<'a>,
|
||||
pub(crate) struct SubdiagnosticDeriveBuilder {
|
||||
diag: syn::Ident,
|
||||
f: syn::Ident,
|
||||
}
|
||||
|
||||
impl<'a> SubdiagnosticDerive<'a> {
|
||||
pub(crate) fn new(structure: Structure<'a>) -> Self {
|
||||
impl SubdiagnosticDeriveBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
let diag = format_ident!("diag");
|
||||
Self { structure, diag }
|
||||
let f = format_ident!("f");
|
||||
Self { diag, f }
|
||||
}
|
||||
|
||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let SubdiagnosticDerive { mut structure, diag } = self;
|
||||
pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream {
|
||||
let implementation = {
|
||||
let ast = structure.ast();
|
||||
let span = ast.span().unwrap();
|
||||
@ -53,10 +53,11 @@ impl<'a> SubdiagnosticDerive<'a> {
|
||||
|
||||
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||
let variants_ = structure.each_variant(|variant| {
|
||||
let mut builder = SubdiagnosticDeriveBuilder {
|
||||
diag: &diag,
|
||||
let mut builder = SubdiagnosticDeriveVariantBuilder {
|
||||
parent: &self,
|
||||
variant,
|
||||
span,
|
||||
formatting_init: TokenStream::new(),
|
||||
fields: build_field_mapping(variant),
|
||||
span_field: None,
|
||||
applicability: None,
|
||||
@ -72,9 +73,17 @@ impl<'a> SubdiagnosticDerive<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let diag = &self.diag;
|
||||
let f = &self.f;
|
||||
let ret = structure.gen_impl(quote! {
|
||||
gen impl rustc_errors::AddToDiagnostic for @Self {
|
||||
fn add_to_diagnostic(self, #diag: &mut rustc_errors::Diagnostic) {
|
||||
fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
|
||||
where
|
||||
__F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
use rustc_errors::{Applicability, IntoDiagnosticArg};
|
||||
#implementation
|
||||
}
|
||||
@ -88,15 +97,18 @@ impl<'a> SubdiagnosticDerive<'a> {
|
||||
/// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
|
||||
/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
|
||||
/// double mut borrow later on.
|
||||
struct SubdiagnosticDeriveBuilder<'a> {
|
||||
struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
/// The identifier to use for the generated `DiagnosticBuilder` instance.
|
||||
diag: &'a syn::Ident,
|
||||
parent: &'parent SubdiagnosticDeriveBuilder,
|
||||
|
||||
/// Info for the current variant (or the type if not an enum).
|
||||
variant: &'a VariantInfo<'a>,
|
||||
/// Span for the entire type.
|
||||
span: proc_macro::Span,
|
||||
|
||||
/// Initialization of format strings for code suggestions.
|
||||
formatting_init: TokenStream,
|
||||
|
||||
/// Store a map of field name to its corresponding field. This is built on construction of the
|
||||
/// derive builder.
|
||||
fields: FieldMap,
|
||||
@ -112,7 +124,7 @@ struct SubdiagnosticDeriveBuilder<'a> {
|
||||
has_suggestion_parts: bool,
|
||||
}
|
||||
|
||||
impl<'a> HasFieldMap for SubdiagnosticDeriveBuilder<'a> {
|
||||
impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||
self.fields.get(field)
|
||||
}
|
||||
@ -156,7 +168,7 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||
let mut kind_slugs = vec![];
|
||||
|
||||
@ -187,7 +199,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
let ast = binding.ast();
|
||||
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
|
||||
|
||||
let diag = &self.diag;
|
||||
let diag = &self.parent.diag;
|
||||
let ident = ast.ident.as_ref().unwrap();
|
||||
// strip `r#` prefix, if present
|
||||
let ident = format_ident!("{}", ident);
|
||||
@ -222,7 +234,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
};
|
||||
|
||||
let generated = self
|
||||
.generate_field_code_inner(kind_stats, attr, info)
|
||||
.generate_field_code_inner(kind_stats, attr, info, inner_ty.will_iterate())
|
||||
.unwrap_or_else(|v| v.to_compile_error());
|
||||
|
||||
inner_ty.with(binding, generated)
|
||||
@ -235,13 +247,18 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
kind_stats: KindsStatistics,
|
||||
attr: &Attribute,
|
||||
info: FieldInfo<'_>,
|
||||
clone_suggestion_code: bool,
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let meta = attr.parse_meta()?;
|
||||
match meta {
|
||||
Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
|
||||
Meta::List(list @ MetaList { .. }) => {
|
||||
self.generate_field_code_inner_list(kind_stats, attr, info, list)
|
||||
}
|
||||
Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
|
||||
kind_stats,
|
||||
attr,
|
||||
info,
|
||||
list,
|
||||
clone_suggestion_code,
|
||||
),
|
||||
_ => throw_invalid_attr!(attr, &meta),
|
||||
}
|
||||
}
|
||||
@ -345,6 +362,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
attr: &Attribute,
|
||||
info: FieldInfo<'_>,
|
||||
list: MetaList,
|
||||
clone_suggestion_code: bool,
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let span = attr.span().unwrap();
|
||||
let ident = &list.path.segments.last().unwrap().ident;
|
||||
@ -382,7 +400,8 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
match nested_name {
|
||||
"code" => {
|
||||
let formatted_str = self.build_format(&value.value(), value.span());
|
||||
code.set_once(formatted_str, span);
|
||||
let code_field = new_code_ident();
|
||||
code.set_once((code_field, formatted_str), span);
|
||||
}
|
||||
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||
diag.help("`code` is the only valid nested attribute")
|
||||
@ -390,14 +409,20 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let Some((code, _)) = code else {
|
||||
let Some((code_field, formatted_str)) = code.value() else {
|
||||
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
||||
.emit();
|
||||
return Ok(quote! {});
|
||||
};
|
||||
let binding = info.binding;
|
||||
|
||||
Ok(quote! { suggestions.push((#binding, #code)); })
|
||||
self.formatting_init.extend(quote! { let #code_field = #formatted_str; });
|
||||
let code_field = if clone_suggestion_code {
|
||||
quote! { #code_field.clone() }
|
||||
} else {
|
||||
quote! { #code_field }
|
||||
};
|
||||
Ok(quote! { suggestions.push((#binding, #code_field)); })
|
||||
}
|
||||
_ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
|
||||
let mut span_attrs = vec![];
|
||||
@ -442,13 +467,23 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
|
||||
let span_field = self.span_field.value_ref();
|
||||
|
||||
let diag = &self.diag;
|
||||
let diag = &self.parent.diag;
|
||||
let f = &self.parent.f;
|
||||
let mut calls = TokenStream::new();
|
||||
for (kind, slug) in kind_slugs {
|
||||
let message = format_ident!("__message");
|
||||
calls.extend(quote! { let #message = #f(#diag, rustc_errors::fluent::#slug.into()); });
|
||||
|
||||
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||
let message = quote! { rustc_errors::fluent::#slug };
|
||||
let call = match kind {
|
||||
SubdiagnosticKind::Suggestion { suggestion_kind, applicability, code } => {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
suggestion_kind,
|
||||
applicability,
|
||||
code_init,
|
||||
code_field,
|
||||
} => {
|
||||
self.formatting_init.extend(code_init);
|
||||
|
||||
let applicability = applicability
|
||||
.value()
|
||||
.map(|a| quote! { #a })
|
||||
@ -457,8 +492,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
|
||||
if let Some(span) = span_field {
|
||||
let style = suggestion_kind.to_suggestion_style();
|
||||
|
||||
quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
|
||||
quote! { #diag.#name(#span, #message, #code_field, #applicability, #style); }
|
||||
} else {
|
||||
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
|
||||
quote! { unreachable!(); }
|
||||
@ -499,6 +533,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
calls.extend(call);
|
||||
}
|
||||
|
||||
@ -510,11 +545,13 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||
.map(|binding| self.generate_field_set_arg(binding))
|
||||
.collect();
|
||||
|
||||
let formatting_init = &self.formatting_init;
|
||||
Ok(quote! {
|
||||
#init
|
||||
#formatting_init
|
||||
#attr_args
|
||||
#calls
|
||||
#plain_args
|
||||
#calls
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,29 @@ use crate::diagnostics::error::{
|
||||
use proc_macro::Span;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use std::cmp::Ordering;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
|
||||
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
|
||||
use synstructure::{BindStyle, BindingInfo, VariantInfo};
|
||||
use synstructure::{BindingInfo, VariantInfo};
|
||||
|
||||
use super::error::invalid_nested_attr;
|
||||
|
||||
thread_local! {
|
||||
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
|
||||
}
|
||||
|
||||
/// Returns an ident of the form `__code_N` where `N` is incremented once with every call.
|
||||
pub(crate) fn new_code_ident() -> syn::Ident {
|
||||
CODE_IDENT_COUNT.with(|count| {
|
||||
let ident = format_ident!("__code_{}", *count.borrow());
|
||||
*count.borrow_mut() += 1;
|
||||
ident
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether the type name of `ty` matches `name`.
|
||||
///
|
||||
/// Given some struct at `a::b::c::Foo`, this will return true for `c::Foo`, `b::c::Foo`, or
|
||||
@ -142,6 +155,15 @@ impl<'ty> FieldInnerTy<'ty> {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e.
|
||||
/// that cloning might be required for values moved in the loop body).
|
||||
pub(crate) fn will_iterate(&self) -> bool {
|
||||
match self {
|
||||
FieldInnerTy::Vec(..) => true,
|
||||
FieldInnerTy::Option(..) | FieldInnerTy::None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Option` containing inner type if there is one.
|
||||
pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
|
||||
match self {
|
||||
@ -434,7 +456,12 @@ pub(super) enum SubdiagnosticKind {
|
||||
Suggestion {
|
||||
suggestion_kind: SuggestionKind,
|
||||
applicability: SpannedOption<Applicability>,
|
||||
code: TokenStream,
|
||||
/// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation
|
||||
/// of formatting and diagnostic emission so that `set_arg` calls can happen in-between..
|
||||
code_field: syn::Ident,
|
||||
/// Initialization logic for `code_field`'s variable, e.g.
|
||||
/// `let __formatted_code = /* whatever */;`
|
||||
code_init: TokenStream,
|
||||
},
|
||||
/// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
|
||||
MultipartSuggestion {
|
||||
@ -469,7 +496,8 @@ impl SubdiagnosticKind {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
suggestion_kind,
|
||||
applicability: None,
|
||||
code: TokenStream::new(),
|
||||
code_field: new_code_ident(),
|
||||
code_init: TokenStream::new(),
|
||||
}
|
||||
} else if let Some(suggestion_kind) =
|
||||
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
|
||||
@ -548,9 +576,10 @@ impl SubdiagnosticKind {
|
||||
};
|
||||
|
||||
match (nested_name, &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { .. }) => {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let formatted_str = fields.build_format(&value.value(), value.span());
|
||||
code.set_once(formatted_str, span);
|
||||
let code_init = quote! { let #code_field = #formatted_str; };
|
||||
code.set_once(code_init, span);
|
||||
}
|
||||
(
|
||||
"applicability",
|
||||
@ -582,13 +611,13 @@ impl SubdiagnosticKind {
|
||||
}
|
||||
|
||||
match kind {
|
||||
SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
|
||||
*code_field = if let Some((code, _)) = code {
|
||||
code
|
||||
SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
|
||||
*code_init = if let Some(init) = code.value() {
|
||||
init
|
||||
} else {
|
||||
span_err(span, "suggestion without `code = \"...\"`").emit();
|
||||
quote! { "" }
|
||||
}
|
||||
quote! { let #code_field: String = unreachable!(); }
|
||||
};
|
||||
}
|
||||
SubdiagnosticKind::Label
|
||||
| SubdiagnosticKind::Note
|
||||
@ -620,65 +649,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around `synstructure::BindStyle` which implements `Ord`.
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub(super) struct OrderedBindStyle(pub(super) BindStyle);
|
||||
|
||||
impl OrderedBindStyle {
|
||||
/// Is `BindStyle::Move` or `BindStyle::MoveMut`?
|
||||
pub(super) fn is_move(&self) -> bool {
|
||||
matches!(self.0, BindStyle::Move | BindStyle::MoveMut)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for OrderedBindStyle {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.is_move(), other.is_move()) {
|
||||
// If both `self` and `other` are the same, then ordering is equal.
|
||||
(true, true) | (false, false) => Ordering::Equal,
|
||||
// If `self` is not a move then it should be considered less than `other` (so that
|
||||
// references are sorted first).
|
||||
(false, _) => Ordering::Less,
|
||||
// If `self` is a move then it must be greater than `other` (again, so that references
|
||||
// are sorted first).
|
||||
(true, _) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for OrderedBindStyle {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
||||
/// call (like `span_label`).
|
||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||
field.attrs.is_empty()
|
||||
}
|
||||
|
||||
/// Returns `true` if `field` needs to have code generated in the by-move branch of the
|
||||
/// generated derive rather than the by-ref branch.
|
||||
pub(super) fn bind_style_of_field(field: &Field) -> OrderedBindStyle {
|
||||
let generates_set_arg = should_generate_set_arg(field);
|
||||
let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
|
||||
// FIXME(davidtwco): better support for one field needing to be in the by-move and
|
||||
// by-ref branches.
|
||||
let is_subdiagnostic = field
|
||||
.attrs
|
||||
.iter()
|
||||
.map(|attr| attr.path.segments.last().unwrap().ident.to_string())
|
||||
.any(|attr| attr == "subdiagnostic");
|
||||
|
||||
// `set_arg` calls take their argument by-move..
|
||||
let needs_move = generates_set_arg
|
||||
// If this is a `MultiSpan` field then it needs to be moved to be used by any
|
||||
// attribute..
|
||||
|| is_multispan
|
||||
// If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
|
||||
// unlikely to be `Copy`..
|
||||
|| is_subdiagnostic;
|
||||
|
||||
OrderedBindStyle(if needs_move { BindStyle::Move } else { BindStyle::Ref })
|
||||
}
|
||||
|
@ -1059,6 +1059,43 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_encode_constness(def_kind: DefKind) -> bool {
|
||||
match def_kind {
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
| DefKind::Enum
|
||||
| DefKind::Trait
|
||||
| DefKind::AssocTy
|
||||
| DefKind::Fn
|
||||
| DefKind::Const
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Impl
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
| DefKind::TyAlias => true,
|
||||
DefKind::Variant
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::Field
|
||||
| DefKind::TyParam
|
||||
| DefKind::Mod
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::ConstParam
|
||||
| DefKind::Macro(..)
|
||||
| DefKind::Use
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::ExternCrate => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||
if tcx.def_kind(def_id) != DefKind::AssocFn {
|
||||
return false;
|
||||
@ -1165,6 +1202,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
{
|
||||
record!(self.tables.trait_impl_trait_tys[def_id] <- table);
|
||||
}
|
||||
if should_encode_constness(def_kind) {
|
||||
self.tables.constness.set(def_id.index, tcx.constness(def_id));
|
||||
}
|
||||
}
|
||||
let inherent_impls = tcx.crate_inherent_impls(());
|
||||
for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
|
||||
@ -1192,7 +1232,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
record!(self.tables.variant_data[def_id] <- data);
|
||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
||||
record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
|
||||
assert!(f.did.is_local());
|
||||
f.did.index
|
||||
@ -1220,7 +1259,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
record!(self.tables.variant_data[def_id] <- data);
|
||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
||||
if variant.ctor_kind == CtorKind::Fn {
|
||||
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
|
||||
}
|
||||
@ -1284,7 +1322,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
|
||||
record!(self.tables.repr_options[def_id] <- adt_def.repr());
|
||||
record!(self.tables.variant_data[def_id] <- data);
|
||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
||||
if variant.ctor_kind == CtorKind::Fn {
|
||||
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
|
||||
}
|
||||
@ -1320,7 +1357,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
|
||||
self.tables.constness.set(def_id.index, hir::Constness::NotConst);
|
||||
}
|
||||
ty::AssocKind::Type => {
|
||||
self.encode_explicit_item_bounds(def_id);
|
||||
@ -1345,13 +1381,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
|
||||
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
|
||||
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
|
||||
// Can be inside `impl const Trait`, so using sig.header.constness is not reliable
|
||||
let constness = if self.tcx.is_const_fn_raw(def_id) {
|
||||
hir::Constness::Const
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
};
|
||||
self.tables.constness.set(def_id.index, constness);
|
||||
}
|
||||
ty::AssocKind::Const | ty::AssocKind::Type => {}
|
||||
}
|
||||
@ -1474,7 +1503,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
hir::ItemKind::Fn(ref sig, .., body) => {
|
||||
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
|
||||
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
|
||||
self.tables.constness.set(def_id.index, sig.header.constness);
|
||||
}
|
||||
hir::ItemKind::Macro(ref macro_def, _) => {
|
||||
if macro_def.macro_rules {
|
||||
@ -1495,7 +1523,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
hir::ItemKind::Struct(ref struct_def, _) => {
|
||||
let adt_def = self.tcx.adt_def(def_id);
|
||||
record!(self.tables.repr_options[def_id] <- adt_def.repr());
|
||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
||||
|
||||
// Encode def_ids for each field and method
|
||||
// for methods, write all the stuff get_trait_method
|
||||
@ -1524,9 +1551,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
|
||||
});
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
|
||||
hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
|
||||
self.tables.impl_defaultness.set(def_id.index, *defaultness);
|
||||
self.tables.constness.set(def_id.index, *constness);
|
||||
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id);
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
|
@ -2946,11 +2946,12 @@ impl Location {
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(BasicBlockData<'_>, 144);
|
||||
static_assert_size!(LocalDecl<'_>, 56);
|
||||
static_assert_size!(Statement<'_>, 32);
|
||||
static_assert_size!(StatementKind<'_>, 16);
|
||||
static_assert_size!(Terminator<'_>, 112);
|
||||
static_assert_size!(TerminatorKind<'_>, 96);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -1245,10 +1245,11 @@ pub enum BinOp {
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(AggregateKind<'_>, 40);
|
||||
static_assert_size!(Operand<'_>, 24);
|
||||
static_assert_size!(Place<'_>, 16);
|
||||
static_assert_size!(PlaceElem<'_>, 24);
|
||||
static_assert_size!(Rvalue<'_>, 40);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -848,7 +848,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Block, 56);
|
||||
static_assert_size!(Expr<'_>, 64);
|
||||
static_assert_size!(ExprKind<'_>, 40);
|
||||
@ -856,4 +856,5 @@ mod size_asserts {
|
||||
static_assert_size!(PatKind<'_>, 56);
|
||||
static_assert_size!(Stmt<'_>, 48);
|
||||
static_assert_size!(StmtKind<'_>, 40);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -2668,8 +2668,9 @@ pub struct DestructuredConst<'tcx> {
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(PredicateS<'_>, 48);
|
||||
static_assert_size!(TyS<'_>, 40);
|
||||
static_assert_size!(WithStableHash<TyS<'_>>, 56);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -459,7 +459,8 @@ fn make_token_stream(
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(AttrWrapper, 16);
|
||||
static_assert_size!(LazyAttrTokenStreamImpl, 144);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -1789,20 +1789,25 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
} else {
|
||||
let mut err = self.expected_ident_found();
|
||||
if let Some((ident, _)) = self.token.ident() && ident.as_str() == "let" {
|
||||
self.bump(); // `let`
|
||||
let span = self.prev_token.span.until(self.token.span);
|
||||
if self.eat_keyword_noexpect(kw::Let)
|
||||
&& let removal_span = self.prev_token.span.until(self.token.span)
|
||||
&& let Ok(ident) = self.parse_ident_common(false)
|
||||
// Cancel this error, we don't need it.
|
||||
.map_err(|err| err.cancel())
|
||||
&& self.token.kind == TokenKind::Colon
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"remove the let, the `let` keyword is not allowed in struct field definitions",
|
||||
removal_span,
|
||||
"remove this `let` keyword",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note("the `let` keyword is not allowed in `struct` fields");
|
||||
err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
|
||||
err.emit();
|
||||
self.bump();
|
||||
return Ok(ident);
|
||||
} else {
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
err
|
||||
};
|
||||
|
@ -1,19 +1,15 @@
|
||||
use rustc_errors::AddToDiagnostic;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(query_system::cycle_stack_middle)]
|
||||
pub struct CycleStack {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub desc: String,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for CycleStack {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
diag.span_note(self.span, &format!("...which requires {}...", self.desc));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum HandleCycleError {
|
||||
Error,
|
||||
@ -53,7 +49,7 @@ pub struct Cycle {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub stack_bottom: String,
|
||||
#[subdiagnostic]
|
||||
#[subdiagnostic(eager)]
|
||||
pub cycle_stack: Vec<CycleStack>,
|
||||
#[subdiagnostic]
|
||||
pub stack_count: StackCount,
|
||||
|
@ -4,7 +4,7 @@
|
||||
#![feature(min_specialization)]
|
||||
#![feature(extern_types)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
// #![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -1075,12 +1075,11 @@ mod parse {
|
||||
options! {
|
||||
CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
|
||||
|
||||
// This list is in alphabetical order.
|
||||
//
|
||||
// If you add a new option, please update:
|
||||
// - compiler/rustc_interface/src/tests.rs
|
||||
// - src/doc/rustc/src/codegen-options/index.md
|
||||
|
||||
// tidy-alphabetical-start
|
||||
ar: String = (String::new(), parse_string, [UNTRACKED],
|
||||
"this option is deprecated and does nothing"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
|
||||
@ -1195,9 +1194,8 @@ options! {
|
||||
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
|
||||
"target specific attributes. (`rustc --print target-features` for details). \
|
||||
This feature is unsafe."),
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// This list is in alphabetical order.
|
||||
//
|
||||
// If you add a new option, please update:
|
||||
// - compiler/rustc_interface/src/tests.rs
|
||||
// - src/doc/rustc/src/codegen-options/index.md
|
||||
@ -1206,24 +1204,23 @@ options! {
|
||||
options! {
|
||||
UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
|
||||
|
||||
// This list is in alphabetical order.
|
||||
//
|
||||
// If you add a new option, please update:
|
||||
// - compiler/rustc_interface/src/tests.rs
|
||||
// - src/doc/unstable-book/src/compiler-flags
|
||||
|
||||
// tidy-alphabetical-start
|
||||
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
|
||||
"only allow the listed language features to be enabled in code (space separated)"),
|
||||
always_encode_mir: bool = (false, parse_bool, [TRACKED],
|
||||
"encode MIR of all functions into the crate metadata (default: no)"),
|
||||
assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
|
||||
"make cfg(version) treat the current version as incomplete (default: no)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")]
|
||||
asm_comments: bool = (false, parse_bool, [TRACKED],
|
||||
"generate comments into the assembly (may change behavior) (default: no)"),
|
||||
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||
"assert that the incremental cache is in given state: \
|
||||
either `loaded` or `not-loaded`."),
|
||||
assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
|
||||
"make cfg(version) treat the current version as incomplete (default: no)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
|
||||
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
|
||||
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
|
||||
@ -1256,6 +1253,8 @@ options! {
|
||||
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
|
||||
"print tasks that execute and the color their dep node gets (requires debug build) \
|
||||
(default: no)"),
|
||||
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
|
||||
"set the current output width for diagnostic truncation"),
|
||||
dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
|
||||
"import library generation tool (windows-gnu only)"),
|
||||
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
|
||||
@ -1337,16 +1336,16 @@ options! {
|
||||
"hash spans relative to their parent item for incr. comp. (default: no)"),
|
||||
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
|
||||
"verify incr. comp. hashes of green query instances (default: no)"),
|
||||
inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"control whether `#[inline]` functions are in all CGUs"),
|
||||
inline_llvm: bool = (true, parse_bool, [TRACKED],
|
||||
"enable LLVM inlining (default: yes)"),
|
||||
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable MIR inlining (default: no)"),
|
||||
inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||
"a default MIR inlining threshold (default: 50)"),
|
||||
inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||
"inlining threshold for functions with inline hint (default: 100)"),
|
||||
inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"control whether `#[inline]` functions are in all CGUs"),
|
||||
inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||
"a default MIR inlining threshold (default: 50)"),
|
||||
input_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||
"gather statistics about the input (default: no)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
||||
@ -1363,6 +1362,8 @@ options! {
|
||||
"insert function instrument code for mcount-based tracing (default: no)"),
|
||||
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
|
||||
"keep hygiene data after analysis (default: no)"),
|
||||
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
|
||||
"seed layout randomization"),
|
||||
link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
|
||||
"link native libraries in the linker invocation (default: yes)"),
|
||||
link_only: bool = (false, parse_bool, [TRACKED],
|
||||
@ -1392,11 +1393,11 @@ options! {
|
||||
"use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
|
||||
enabled, overriding all other checks. Passes that are not specified are enabled or \
|
||||
disabled by other flags as usual."),
|
||||
mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
|
||||
"use line numbers relative to the function in mir pretty printing"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
|
||||
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
|
||||
mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
|
||||
"use line numbers relative to the function in mir pretty printing"),
|
||||
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||
"the size at which the `large_assignments` lint starts to be emitted"),
|
||||
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
@ -1419,18 +1420,16 @@ options! {
|
||||
"compile without linking"),
|
||||
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
|
||||
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
|
||||
no_unique_section_names: bool = (false, parse_bool, [TRACKED],
|
||||
"do not use unique names for text and data sections when -Z function-sections is used"),
|
||||
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
|
||||
"prevent automatic injection of the profiler_builtins crate"),
|
||||
no_unique_section_names: bool = (false, parse_bool, [TRACKED],
|
||||
"do not use unique names for text and data sections when -Z function-sections is used"),
|
||||
normalize_docs: bool = (false, parse_bool, [TRACKED],
|
||||
"normalize associated items in rustdoc when generating documentation"),
|
||||
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
||||
"panic strategy for out-of-memory handling"),
|
||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
|
||||
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
|
||||
"set the current output width for diagnostic truncation"),
|
||||
packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
|
||||
"change rlib format to store native libraries as archives"),
|
||||
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
||||
@ -1480,25 +1479,20 @@ options! {
|
||||
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"file path to emit profiling data at runtime when using 'profile' \
|
||||
(default based on relative source path)"),
|
||||
profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
|
||||
"name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
|
||||
profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
|
||||
profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
|
||||
"name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
|
||||
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
|
||||
"enable queries of the dependency graph for regression testing (default: no)"),
|
||||
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
||||
"randomize the layout of types (default: no)"),
|
||||
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
|
||||
"seed layout randomization"),
|
||||
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"whether ELF relocations can be relaxed"),
|
||||
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
|
||||
"choose which RELRO level to use"),
|
||||
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"remap paths under the current working directory to this path prefix"),
|
||||
simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
|
||||
to rust's source base directory. only meant for testing purposes"),
|
||||
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
|
||||
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
@ -1516,27 +1510,41 @@ options! {
|
||||
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||
parse_switch_with_opt_path, [UNTRACKED],
|
||||
"run the self profiler and output the raw event data"),
|
||||
/// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
|
||||
self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
|
||||
"specify the events recorded by the self profiler;
|
||||
for example: `-Z self-profile-events=default,query-keys`
|
||||
all options: none, all, default, generic-activity, query-provider, query-cache-hit
|
||||
query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
|
||||
self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
|
||||
"counter used by the self profiler (default: `wall-time`), one of:
|
||||
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
|
||||
`instructions:u` (retired instructions, userspace-only)
|
||||
`instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
|
||||
),
|
||||
/// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
|
||||
self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
|
||||
"specify the events recorded by the self profiler;
|
||||
for example: `-Z self-profile-events=default,query-keys`
|
||||
all options: none, all, default, generic-activity, query-provider, query-cache-hit
|
||||
query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
|
||||
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"make the current crate share its generic instantiations"),
|
||||
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"show spans for compiler debugging (expr|pat|ty)"),
|
||||
simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
|
||||
to rust's source base directory. only meant for testing purposes"),
|
||||
span_debug: bool = (false, parse_bool, [UNTRACKED],
|
||||
"forward proc_macro::Span's `Debug` impl to `Span`"),
|
||||
/// o/w tests have closure@path
|
||||
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
|
||||
"exclude spans when debug-printing compiler state (default: no)"),
|
||||
split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
|
||||
"provide minimal debug info in the object/executable to facilitate online \
|
||||
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
|
||||
split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
|
||||
"split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
|
||||
(default: `split`)
|
||||
|
||||
`split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
|
||||
file which is ignored by the linker
|
||||
`single`: sections which do not require relocation are written into object file but ignored
|
||||
by the linker"),
|
||||
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
|
||||
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
|
||||
@ -1546,17 +1554,6 @@ options! {
|
||||
"control if mem::uninitialized and mem::zeroed panic on more UB"),
|
||||
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
|
||||
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
|
||||
split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
|
||||
"split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
|
||||
(default: `split`)
|
||||
|
||||
`split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
|
||||
file which is ignored by the linker
|
||||
`single`: sections which do not require relocation are written into object file but ignored
|
||||
by the linker"),
|
||||
split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
|
||||
"provide minimal debug info in the object/executable to facilitate online \
|
||||
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
|
||||
symbol_mangling_version: Option<SymbolManglingVersion> = (None,
|
||||
parse_symbol_mangling_version, [TRACKED],
|
||||
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
|
||||
@ -1565,17 +1562,6 @@ options! {
|
||||
"show extended diagnostic help (default: no)"),
|
||||
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||
"the directory the intermediate files are written to"),
|
||||
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
|
||||
// alongside query results and changes to translation options can affect diagnostics - so
|
||||
// translation options should be tracked.
|
||||
translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
|
||||
"language identifier for diagnostic output"),
|
||||
translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"additional fluent translation to preferentially use (for testing translation)"),
|
||||
translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
|
||||
"emit directionality isolation markers in translated diagnostics"),
|
||||
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"select processor to schedule for (`rustc --print target-cpus` for details)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
|
||||
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable ThinLTO when possible"),
|
||||
@ -1599,6 +1585,15 @@ options! {
|
||||
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
||||
trace_macros: bool = (false, parse_bool, [UNTRACKED],
|
||||
"for every macro invocation, print its name and arguments (default: no)"),
|
||||
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
|
||||
// alongside query results and changes to translation options can affect diagnostics - so
|
||||
// translation options should be tracked.
|
||||
translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"additional fluent translation to preferentially use (for testing translation)"),
|
||||
translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
|
||||
"emit directionality isolation markers in translated diagnostics"),
|
||||
translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
|
||||
"language identifier for diagnostic output"),
|
||||
translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
|
||||
"translate remapped paths into local paths when possible (default: yes)"),
|
||||
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
@ -1607,6 +1602,8 @@ options! {
|
||||
"treat error number `val` that occurs as bug"),
|
||||
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
||||
"in diagnostics, use heuristics to shorten paths referring to items"),
|
||||
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"select processor to schedule for (`rustc --print target-cpus` for details)"),
|
||||
ui_testing: bool = (false, parse_bool, [UNTRACKED],
|
||||
"emit compiler diagnostics in a form suitable for UI testing (default: no)"),
|
||||
uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
|
||||
@ -1647,9 +1644,8 @@ options! {
|
||||
Requires `-Clto[=[fat,yes]]`"),
|
||||
wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
|
||||
"whether to build a wasi command or reactor"),
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// This list is in alphabetical order.
|
||||
//
|
||||
// If you add a new option, please update:
|
||||
// - compiler/rustc_interface/src/tests.rs
|
||||
}
|
||||
|
@ -740,7 +740,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
mod size_asserts {
|
||||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// These are in alphabetical order, which is easy to maintain.
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(ArgAbi<'_, usize>, 56);
|
||||
static_assert_size!(FnAbi<'_, usize>, 80);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -137,77 +137,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
||||
let local_did = def_id.as_local();
|
||||
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
|
||||
|
||||
let constness = match hir_id {
|
||||
Some(hir_id) => match tcx.hir().get(hir_id) {
|
||||
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
||||
if tcx.is_const_default_method(def_id) =>
|
||||
{
|
||||
hir::Constness::Const
|
||||
}
|
||||
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
|
||||
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Const(..), ..
|
||||
})
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind:
|
||||
hir::ImplItemKind::Fn(
|
||||
hir::FnSig {
|
||||
header: hir::FnHeader { constness: hir::Constness::Const, .. },
|
||||
..
|
||||
},
|
||||
..,
|
||||
),
|
||||
..
|
||||
}) => hir::Constness::Const,
|
||||
|
||||
hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
|
||||
..
|
||||
}) => {
|
||||
let parent_hir_id = tcx.hir().get_parent_node(hir_id);
|
||||
match tcx.hir().get(parent_hir_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
||||
..
|
||||
}) => *constness,
|
||||
_ => span_bug!(
|
||||
tcx.def_span(parent_hir_id.owner),
|
||||
"impl item's parent node is not an impl",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind:
|
||||
hir::TraitItemKind::Fn(
|
||||
hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
|
||||
..,
|
||||
),
|
||||
..
|
||||
})
|
||||
| hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
||||
..
|
||||
}) => *constness,
|
||||
|
||||
_ => hir::Constness::NotConst,
|
||||
},
|
||||
None => hir::Constness::NotConst,
|
||||
};
|
||||
|
||||
let unnormalized_env = ty::ParamEnv::new(
|
||||
tcx.intern_predicates(&predicates),
|
||||
traits::Reveal::UserFacing,
|
||||
constness,
|
||||
tcx.constness(def_id),
|
||||
);
|
||||
|
||||
let body_id =
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 4ce51cb7441a6f02b5bf9b07b2eb755c21ab7954
|
||||
Subproject commit c533348edd69f11a8f4225d633a05d7093fddbf3
|
@ -1 +1 @@
|
||||
Subproject commit f53bfa056929217870a5d2df1366d2e7ba35096d
|
||||
Subproject commit 9c73283775466d22208a0b28afcab44db4c0cc10
|
@ -1 +1 @@
|
||||
Subproject commit a7cdac33ca7356ad49d5c2b5e2c5010889b33eee
|
||||
Subproject commit f6ed74f582bddcec73f753eafaab3749c4f7df61
|
@ -1 +1 @@
|
||||
Subproject commit 767a6bd9727a596d7cfdbaeee475e65b2670ea3a
|
||||
Subproject commit 5e7b296d6c345addbd748f242aae28c42555c015
|
@ -1 +1 @@
|
||||
Subproject commit 9a86c0467bbe42056f73fdf5b03fff757d7c4a9b
|
||||
Subproject commit 7518c3445dc02df0d196f5f84e568d633c5141fb
|
@ -563,8 +563,6 @@ h2.location a {
|
||||
.rustdoc .example-wrap {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
.rustdoc .example-wrap {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
/* For the last child of a div, the margin will be taken care of
|
||||
@ -718,7 +716,6 @@ nav.sub {
|
||||
.source nav.sub {
|
||||
margin-left: 32px;
|
||||
}
|
||||
nav.sum { text-align: right; }
|
||||
nav.sub form { display: inline; }
|
||||
|
||||
a {
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
||||
use rustc_data_structures::sync::{Lock, Lrc};
|
||||
use rustc_errors::{
|
||||
emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
|
||||
LazyFallbackBundle,
|
||||
emitter::Emitter,
|
||||
translation::{to_fluent_args, Translate},
|
||||
Applicability, Diagnostic, Handler, LazyFallbackBundle,
|
||||
};
|
||||
use rustc_parse::parse_stream_from_source_str;
|
||||
use rustc_session::parse::ParseSess;
|
||||
@ -193,7 +194,7 @@ impl Emitter for BufferEmitter {
|
||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
|
||||
|
||||
buffer.messages.push(format!("error from rustc: {}", translated_main_message));
|
||||
|
@ -1,8 +1,8 @@
|
||||
-Z allow-features=val -- only allow the listed language features to be enabled in code (space separated)
|
||||
-Z always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no)
|
||||
-Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
|
||||
-Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
|
||||
-Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
|
||||
-Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
|
||||
-Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
|
||||
-Z box-noalias=val -- emit noalias metadata for box (default: yes)
|
||||
-Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
|
||||
@ -17,6 +17,7 @@
|
||||
-Z deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes)
|
||||
-Z dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no)
|
||||
-Z dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no)
|
||||
-Z diagnostic-width=val -- set the current output width for diagnostic truncation
|
||||
-Z dlltool=val -- import library generation tool (windows-gnu only)
|
||||
-Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
|
||||
-Z drop-tracking=val -- enables drop tracking in generators (default: no)
|
||||
@ -54,11 +55,11 @@
|
||||
-Z incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
|
||||
-Z incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
|
||||
-Z incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
|
||||
-Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
|
||||
-Z inline-llvm=val -- enable LLVM inlining (default: yes)
|
||||
-Z inline-mir=val -- enable MIR inlining (default: no)
|
||||
-Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
|
||||
-Z inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
|
||||
-Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
|
||||
-Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
|
||||
-Z input-stats=val -- gather statistics about the input (default: no)
|
||||
-Z instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are:
|
||||
`=all` (implicit value)
|
||||
@ -67,6 +68,7 @@
|
||||
`=off` (default)
|
||||
-Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
|
||||
-Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
|
||||
-Z layout-seed=val -- seed layout randomization
|
||||
-Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
|
||||
-Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
|
||||
-Z llvm-plugins=val -- a list LLVM plugins to enable (space separated)
|
||||
@ -78,8 +80,8 @@
|
||||
-Z meta-stats=val -- gather metadata statistics (default: no)
|
||||
-Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
|
||||
-Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual.
|
||||
-Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing
|
||||
-Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
|
||||
-Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing
|
||||
-Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
|
||||
-Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
|
||||
-Z nll-facts=val -- dump facts from NLL analysis into side files (default: no)
|
||||
@ -91,12 +93,11 @@
|
||||
-Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
|
||||
-Z no-link=val -- compile without linking
|
||||
-Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
|
||||
-Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
|
||||
-Z no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate
|
||||
-Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
|
||||
-Z normalize-docs=val -- normalize associated items in rustdoc when generating documentation
|
||||
-Z oom=val -- panic strategy for out-of-memory handling
|
||||
-Z osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no)
|
||||
-Z diagnostic-width=val -- set the current output width for diagnostic truncation
|
||||
-Z packed-bundled-libs=val -- change rlib format to store native libraries as archives
|
||||
-Z panic-abort-tests=val -- support compiling tests with panic=abort (default: no)
|
||||
-Z panic-in-drop=val -- panic strategy for panics in drops
|
||||
@ -120,15 +121,13 @@
|
||||
-Z profile=val -- insert profiling code (default: no)
|
||||
-Z profile-closures=val -- profile size of closures
|
||||
-Z profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path)
|
||||
-Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
|
||||
-Z profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)
|
||||
-Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
|
||||
-Z query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no)
|
||||
-Z randomize-layout=val -- randomize the layout of types (default: no)
|
||||
-Z layout-seed=val -- seed layout randomization
|
||||
-Z relax-elf-relocations=val -- whether ELF relocations can be relaxed
|
||||
-Z relro-level=val -- choose which RELRO level to use
|
||||
-Z remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix
|
||||
-Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
|
||||
-Z report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
|
||||
-Z sanitizer=val -- use a sanitizer
|
||||
-Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
|
||||
@ -136,22 +135,20 @@
|
||||
-Z saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes)
|
||||
-Z save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no)
|
||||
-Z self-profile=val -- run the self profiler and output the raw event data
|
||||
-Z self-profile-events=val -- specify the events recorded by the self profiler;
|
||||
for example: `-Z self-profile-events=default,query-keys`
|
||||
all options: none, all, default, generic-activity, query-provider, query-cache-hit
|
||||
query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
|
||||
-Z self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of:
|
||||
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
|
||||
`instructions:u` (retired instructions, userspace-only)
|
||||
`instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
|
||||
-Z self-profile-events=val -- specify the events recorded by the self profiler;
|
||||
for example: `-Z self-profile-events=default,query-keys`
|
||||
all options: none, all, default, generic-activity, query-provider, query-cache-hit
|
||||
query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
|
||||
-Z share-generics=val -- make the current crate share its generic instantiations
|
||||
-Z show-span=val -- show spans for compiler debugging (expr|pat|ty)
|
||||
-Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
|
||||
-Z span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span`
|
||||
-Z span-free-formats=val -- exclude spans when debug-printing compiler state (default: no)
|
||||
-Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
|
||||
-Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
|
||||
-Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
|
||||
-Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
|
||||
-Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
|
||||
-Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
|
||||
(default: `split`)
|
||||
|
||||
@ -159,14 +156,13 @@
|
||||
file which is ignored by the linker
|
||||
`single`: sections which do not require relocation are written into object file but ignored
|
||||
by the linker
|
||||
-Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
|
||||
-Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
|
||||
-Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
|
||||
-Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
|
||||
-Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
|
||||
-Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
|
||||
-Z teach=val -- show extended diagnostic help (default: no)
|
||||
-Z temps-dir=val -- the directory the intermediate files are written to
|
||||
-Z translate-lang=val -- language identifier for diagnostic output
|
||||
-Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
|
||||
-Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
|
||||
-Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
|
||||
-Z thinlto=val -- enable ThinLTO when possible
|
||||
-Z thir-unsafeck=val -- use the THIR unsafety checker (default: no)
|
||||
-Z threads=val -- use a thread pool with N threads
|
||||
@ -174,10 +170,14 @@
|
||||
-Z time-passes=val -- measure time of each rustc pass (default: no)
|
||||
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
|
||||
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
|
||||
-Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
|
||||
-Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
|
||||
-Z translate-lang=val -- language identifier for diagnostic output
|
||||
-Z translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes)
|
||||
-Z trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)
|
||||
-Z treat-err-as-bug=val -- treat error number `val` that occurs as bug
|
||||
-Z trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items
|
||||
-Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
|
||||
-Z ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no)
|
||||
-Z uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16)
|
||||
-Z unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no)
|
||||
|
@ -13,7 +13,7 @@ extern crate rustc_span;
|
||||
|
||||
use rustc_errors::{
|
||||
AddToDiagnostic, IntoDiagnostic, Diagnostic, DiagnosticBuilder,
|
||||
ErrorGuaranteed, Handler, fluent
|
||||
ErrorGuaranteed, Handler, fluent, SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::Span;
|
||||
@ -52,7 +52,10 @@ impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
|
||||
pub struct UntranslatableInAddToDiagnostic;
|
||||
|
||||
impl AddToDiagnostic for UntranslatableInAddToDiagnostic {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.note("untranslatable diagnostic");
|
||||
//~^ ERROR diagnostics should be created using translatable messages
|
||||
}
|
||||
@ -61,7 +64,10 @@ impl AddToDiagnostic for UntranslatableInAddToDiagnostic {
|
||||
pub struct TranslatableInAddToDiagnostic;
|
||||
|
||||
impl AddToDiagnostic for TranslatableInAddToDiagnostic {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.note(fluent::compiletest::note);
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: diagnostics should be created using translatable messages
|
||||
--> $DIR/diagnostics.rs:56:14
|
||||
--> $DIR/diagnostics.rs:59:14
|
||||
|
|
||||
LL | diag.note("untranslatable diagnostic");
|
||||
| ^^^^
|
||||
|
||||
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
|
||||
--> $DIR/diagnostics.rs:70:25
|
||||
--> $DIR/diagnostics.rs:76:25
|
||||
|
|
||||
LL | let _diag = handler.struct_err(fluent::compiletest::example);
|
||||
| ^^^^^^^^^^
|
||||
@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
|
||||
--> $DIR/diagnostics.rs:73:25
|
||||
--> $DIR/diagnostics.rs:79:25
|
||||
|
|
||||
LL | let _diag = handler.struct_err("untranslatable diagnostic");
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: diagnostics should be created using translatable messages
|
||||
--> $DIR/diagnostics.rs:73:25
|
||||
--> $DIR/diagnostics.rs:79:25
|
||||
|
|
||||
LL | let _diag = handler.struct_err("untranslatable diagnostic");
|
||||
| ^^^^^^^^^^
|
||||
|
@ -678,3 +678,74 @@ enum ExampleEnum {
|
||||
struct RawIdentDiagnosticArg {
|
||||
pub r#type: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticBad {
|
||||
#[subdiagnostic(bad)]
|
||||
//~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
|
||||
note: Note,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticBadStr {
|
||||
#[subdiagnostic = "bad"]
|
||||
//~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
|
||||
note: Note,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticBadTwice {
|
||||
#[subdiagnostic(bad, bad)]
|
||||
//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
|
||||
note: Note,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticBadLitStr {
|
||||
#[subdiagnostic("bad")]
|
||||
//~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
|
||||
note: Note,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticEagerLint {
|
||||
#[subdiagnostic(eager)]
|
||||
//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
|
||||
note: Note,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticEagerCorrect {
|
||||
#[subdiagnostic(eager)]
|
||||
note: Note,
|
||||
}
|
||||
|
||||
// Check that formatting of `correct` in suggestion doesn't move the binding for that field, making
|
||||
// the `set_arg` call a compile error; and that isn't worked around by moving the `set_arg` call
|
||||
// after the `span_suggestion` call - which breaks eager translation.
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion_short(
|
||||
parser::use_instead,
|
||||
applicability = "machine-applicable",
|
||||
code = "{correct}"
|
||||
)]
|
||||
pub(crate) struct SubdiagnosticWithSuggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
invalid: String,
|
||||
correct: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example)]
|
||||
struct SubdiagnosticEagerSuggestion {
|
||||
#[subdiagnostic(eager)]
|
||||
sub: SubdiagnosticWithSuggestion,
|
||||
}
|
||||
|
@ -533,6 +533,46 @@ LL | #[label]
|
||||
|
|
||||
= help: `#[label]` and `#[suggestion]` can only be applied to fields
|
||||
|
||||
error: `#[subdiagnostic(bad)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:685:21
|
||||
|
|
||||
LL | #[subdiagnostic(bad)]
|
||||
| ^^^
|
||||
|
|
||||
= help: `eager` is the only supported nested attribute for `subdiagnostic`
|
||||
|
||||
error: `#[subdiagnostic = ...]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:693:5
|
||||
|
|
||||
LL | #[subdiagnostic = "bad"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `eager` is the only supported nested attribute for `subdiagnostic`
|
||||
|
||||
error: `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:701:5
|
||||
|
|
||||
LL | #[subdiagnostic(bad, bad)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `eager` is the only supported nested attribute for `subdiagnostic`
|
||||
|
||||
error: `#[subdiagnostic("...")]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:709:21
|
||||
|
|
||||
LL | #[subdiagnostic("bad")]
|
||||
| ^^^^^
|
||||
|
|
||||
= help: `eager` is the only supported nested attribute for `subdiagnostic`
|
||||
|
||||
error: `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:717:5
|
||||
|
|
||||
LL | #[subdiagnostic(eager)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: eager subdiagnostics are not supported on lints
|
||||
|
||||
error: cannot find attribute `nonsense` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:55:3
|
||||
|
|
||||
@ -607,7 +647,7 @@ LL | arg: impl IntoDiagnosticArg,
|
||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 75 previous errors
|
||||
error: aborting due to 80 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0425.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
6
src/test/ui/parser/bad-let-as-field.rs
Normal file
6
src/test/ui/parser/bad-let-as-field.rs
Normal file
@ -0,0 +1,6 @@
|
||||
struct Foo {
|
||||
let: i32,
|
||||
//~^ ERROR expected identifier, found keyword
|
||||
}
|
||||
|
||||
fn main() {}
|
15
src/test/ui/parser/bad-let-as-field.stderr
Normal file
15
src/test/ui/parser/bad-let-as-field.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error: expected identifier, found keyword `let`
|
||||
--> $DIR/bad-let-as-field.rs:2:5
|
||||
|
|
||||
LL | struct Foo {
|
||||
| --- while parsing this struct
|
||||
LL | let: i32,
|
||||
| ^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `let` to use it as an identifier
|
||||
|
|
||||
LL | r#let: i32,
|
||||
| ++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
12
src/test/ui/parser/removed-syntax-field-let-2.rs
Normal file
12
src/test/ui/parser/removed-syntax-field-let-2.rs
Normal file
@ -0,0 +1,12 @@
|
||||
struct Foo {
|
||||
let x: i32,
|
||||
//~^ ERROR expected identifier, found keyword
|
||||
let y: i32,
|
||||
//~^ ERROR expected identifier, found keyword
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Foo {
|
||||
//~^ ERROR missing fields `x` and `y` in initializer of `Foo`
|
||||
};
|
||||
}
|
33
src/test/ui/parser/removed-syntax-field-let-2.stderr
Normal file
33
src/test/ui/parser/removed-syntax-field-let-2.stderr
Normal file
@ -0,0 +1,33 @@
|
||||
error: expected identifier, found keyword `let`
|
||||
--> $DIR/removed-syntax-field-let-2.rs:2:5
|
||||
|
|
||||
LL | let x: i32,
|
||||
| ^^^-
|
||||
| |
|
||||
| expected identifier, found keyword
|
||||
| help: remove this `let` keyword
|
||||
|
|
||||
= note: the `let` keyword is not allowed in `struct` fields
|
||||
= note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
|
||||
|
||||
error: expected identifier, found keyword `let`
|
||||
--> $DIR/removed-syntax-field-let-2.rs:4:5
|
||||
|
|
||||
LL | let y: i32,
|
||||
| ^^^-
|
||||
| |
|
||||
| expected identifier, found keyword
|
||||
| help: remove this `let` keyword
|
||||
|
|
||||
= note: the `let` keyword is not allowed in `struct` fields
|
||||
= note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
|
||||
|
||||
error[E0063]: missing fields `x` and `y` in initializer of `Foo`
|
||||
--> $DIR/removed-syntax-field-let-2.rs:9:13
|
||||
|
|
||||
LL | let _ = Foo {
|
||||
| ^^^ missing `x` and `y`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0063`.
|
@ -2,15 +2,13 @@ error: expected identifier, found keyword `let`
|
||||
--> $DIR/removed-syntax-field-let.rs:2:5
|
||||
|
|
||||
LL | let foo: (),
|
||||
| ^^^ expected identifier, found keyword
|
||||
| ^^^-
|
||||
| |
|
||||
| expected identifier, found keyword
|
||||
| help: remove this `let` keyword
|
||||
|
|
||||
= note: the `let` keyword is not allowed in `struct` fields
|
||||
= note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
|
||||
help: remove the let, the `let` keyword is not allowed in struct field definitions
|
||||
|
|
||||
LL - let foo: (),
|
||||
LL + foo: (),
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
113
src/tools/tidy/src/alphabetical.rs
Normal file
113
src/tools/tidy/src/alphabetical.rs
Normal file
@ -0,0 +1,113 @@
|
||||
//! Checks that a list of items is in alphabetical order
|
||||
//!
|
||||
//! To use, use the following annotation in the code:
|
||||
//! ```rust
|
||||
//! // tidy-alphabetical-start
|
||||
//! fn aaa() {}
|
||||
//! fn eee() {}
|
||||
//! fn z() {}
|
||||
//! // tidy-alphabetical-end
|
||||
//! ```
|
||||
//!
|
||||
//! The following lines are ignored:
|
||||
//! - Lines that are indented with more or less spaces than the first line
|
||||
//! - Lines starting with `//`, `#[`, `)`, `]`, `}` if the comment has the same indentation as
|
||||
//! the first line
|
||||
//!
|
||||
//! If a line ends with an opening bracket, the line is ignored and the next line will have
|
||||
//! its extra indentation ignored.
|
||||
|
||||
use std::{fmt::Display, path::Path};
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
|
||||
fn indentation(line: &str) -> usize {
|
||||
line.find(|c| c != ' ').unwrap_or(0)
|
||||
}
|
||||
|
||||
fn is_close_bracket(c: char) -> bool {
|
||||
matches!(c, ')' | ']' | '}')
|
||||
}
|
||||
|
||||
const START_COMMENT: &str = "// tidy-alphabetical-start";
|
||||
const END_COMMENT: &str = "// tidy-alphabetical-end";
|
||||
|
||||
fn check_section<'a>(
|
||||
file: impl Display,
|
||||
lines: impl Iterator<Item = (usize, &'a str)>,
|
||||
bad: &mut bool,
|
||||
) {
|
||||
let content_lines = lines.take_while(|(_, line)| !line.contains(END_COMMENT));
|
||||
|
||||
let mut prev_line = String::new();
|
||||
let mut first_indent = None;
|
||||
let mut in_split_line = None;
|
||||
|
||||
for (line_idx, line) in content_lines {
|
||||
if line.contains(START_COMMENT) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"{file}:{} found `// tidy-alphabetical-start` expecting `// tidy-alphabetical-end`",
|
||||
line_idx
|
||||
)
|
||||
}
|
||||
|
||||
let indent = first_indent.unwrap_or_else(|| {
|
||||
let indent = indentation(line);
|
||||
first_indent = Some(indent);
|
||||
indent
|
||||
});
|
||||
|
||||
let line = if let Some(prev_split_line) = in_split_line {
|
||||
in_split_line = None;
|
||||
format!("{prev_split_line}{}", line.trim_start())
|
||||
} else {
|
||||
line.to_string()
|
||||
};
|
||||
|
||||
if indentation(&line) != indent {
|
||||
continue;
|
||||
}
|
||||
|
||||
let trimmed_line = line.trim_start_matches(' ');
|
||||
|
||||
if trimmed_line.starts_with("//")
|
||||
|| trimmed_line.starts_with("#[")
|
||||
|| trimmed_line.starts_with(is_close_bracket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.trim_end().ends_with('(') {
|
||||
in_split_line = Some(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ').to_lowercase();
|
||||
|
||||
if trimmed_line.to_lowercase() < prev_line_trimmed_lowercase {
|
||||
tidy_error!(bad, "{file}:{}: line not in alphabetical order", line_idx + 1,);
|
||||
}
|
||||
|
||||
prev_line = line;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
walk(path, &mut filter_dirs, &mut |entry, contents| {
|
||||
let file = &entry.path().display();
|
||||
|
||||
let mut lines = contents.lines().enumerate().peekable();
|
||||
while let Some((_, line)) = lines.next() {
|
||||
if line.contains(START_COMMENT) {
|
||||
check_section(file, &mut lines, bad);
|
||||
if lines.peek().is_none() {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"{file}: reached end of file expecting `// tidy-alphabetical-end`"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -38,6 +38,7 @@ macro_rules! tidy_error {
|
||||
});
|
||||
}
|
||||
|
||||
pub mod alphabetical;
|
||||
pub mod bins;
|
||||
pub mod debug_artifacts;
|
||||
pub mod deps;
|
||||
|
@ -90,6 +90,8 @@ fn main() {
|
||||
check!(edition, &compiler_path);
|
||||
check!(edition, &library_path);
|
||||
|
||||
check!(alphabetical, &compiler_path);
|
||||
|
||||
let collected = {
|
||||
while handles.len() >= concurrency.get() {
|
||||
handles.pop_front().unwrap().join().unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user