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
60 changed files with 958 additions and 460 deletions
|
@ -3039,7 +3039,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(AssocItem, 104);
|
||||||
static_assert_size!(AssocItemKind, 32);
|
static_assert_size!(AssocItemKind, 32);
|
||||||
static_assert_size!(Attribute, 32);
|
static_assert_size!(Attribute, 32);
|
||||||
|
@ -3060,11 +3060,12 @@ mod size_asserts {
|
||||||
static_assert_size!(Local, 72);
|
static_assert_size!(Local, 72);
|
||||||
static_assert_size!(Param, 40);
|
static_assert_size!(Param, 40);
|
||||||
static_assert_size!(Pat, 120);
|
static_assert_size!(Pat, 120);
|
||||||
static_assert_size!(PatKind, 96);
|
|
||||||
static_assert_size!(Path, 40);
|
static_assert_size!(Path, 40);
|
||||||
static_assert_size!(PathSegment, 24);
|
static_assert_size!(PathSegment, 24);
|
||||||
|
static_assert_size!(PatKind, 96);
|
||||||
static_assert_size!(Stmt, 32);
|
static_assert_size!(Stmt, 32);
|
||||||
static_assert_size!(StmtKind, 16);
|
static_assert_size!(StmtKind, 16);
|
||||||
static_assert_size!(Ty, 96);
|
static_assert_size!(Ty, 96);
|
||||||
static_assert_size!(TyKind, 72);
|
static_assert_size!(TyKind, 72);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -889,10 +889,11 @@ where
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(Lit, 12);
|
||||||
static_assert_size!(LitKind, 2);
|
static_assert_size!(LitKind, 2);
|
||||||
static_assert_size!(Nonterminal, 16);
|
static_assert_size!(Nonterminal, 16);
|
||||||
static_assert_size!(Token, 24);
|
static_assert_size!(Token, 24);
|
||||||
static_assert_size!(TokenKind, 16);
|
static_assert_size!(TokenKind, 16);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -646,10 +646,11 @@ impl DelimSpan {
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(AttrTokenStream, 8);
|
||||||
static_assert_size!(AttrTokenTree, 32);
|
static_assert_size!(AttrTokenTree, 32);
|
||||||
static_assert_size!(LazyAttrTokenStream, 8);
|
static_assert_size!(LazyAttrTokenStream, 8);
|
||||||
static_assert_size!(TokenStream, 8);
|
static_assert_size!(TokenStream, 8);
|
||||||
static_assert_size!(TokenTree, 32);
|
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_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||||
|
|
||||||
|
@ -19,7 +22,10 @@ pub struct UseAngleBrackets {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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(
|
diag.multipart_suggestion(
|
||||||
fluent::ast_lowering::use_angle_brackets,
|
fluent::ast_lowering::use_angle_brackets,
|
||||||
vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
|
vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
|
||||||
|
@ -69,7 +75,10 @@ pub enum AssocTyParenthesesSub {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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 {
|
match self {
|
||||||
Self::Empty { parentheses_span } => diag.multipart_suggestion(
|
Self::Empty { parentheses_span } => diag.multipart_suggestion(
|
||||||
fluent::ast_lowering::remove_parentheses,
|
fluent::ast_lowering::remove_parentheses,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Errors emitted by ast_passes.
|
//! 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_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
|
@ -17,7 +17,10 @@ pub struct ForbiddenLet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for ForbiddenLetReason {
|
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 {
|
match self {
|
||||||
Self::GenericForbidden => {}
|
Self::GenericForbidden => {}
|
||||||
Self::NotSupportedOr(span) => {
|
Self::NotSupportedOr(span) => {
|
||||||
|
@ -228,7 +231,10 @@ pub struct ExternBlockSuggestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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 {
|
let start_suggestion = if let Some(abi) = self.abi {
|
||||||
format!("extern \"{}\" {{", abi)
|
format!("extern \"{}\" {{", abi)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,7 +15,10 @@ use rustc_data_structures::profiling::TimingGuard;
|
||||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::emitter::Emitter;
|
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_fs_util::link_or_copy;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_incremental::{
|
use rustc_incremental::{
|
||||||
|
@ -1740,7 +1743,7 @@ impl Translate for SharedEmitter {
|
||||||
|
|
||||||
impl Emitter for SharedEmitter {
|
impl Emitter for SharedEmitter {
|
||||||
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
|
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 {
|
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
||||||
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
||||||
code: diag.code.clone(),
|
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
|
/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
|
||||||
/// `Constness::NotConst`.
|
/// `Constness::NotConst`.
|
||||||
fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
|
fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
|
||||||
let def_id = def_id.expect_local();
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||||
let node = tcx.hir().get_by_def_id(def_id);
|
match tcx.hir().get(hir_id) {
|
||||||
|
|
||||||
match node {
|
|
||||||
hir::Node::Ctor(_) => hir::Constness::Const,
|
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(..), .. }) => {
|
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
|
||||||
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
||||||
// foreign items cannot be evaluated at compile-time.
|
// 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 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`
|
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
||||||
// if it resides in a const trait impl.
|
if tcx.is_const_default_method(def_id) =>
|
||||||
let is_const = is_parent_const_impl_raw(tcx, def_id);
|
{
|
||||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
hir::Constness::Const
|
||||||
} else {
|
}
|
||||||
hir::Constness::NotConst
|
|
||||||
|
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 {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(Immediate, 48);
|
||||||
static_assert_size!(ImmTy<'_>, 64);
|
static_assert_size!(ImmTy<'_>, 64);
|
||||||
static_assert_size!(Operand, 56);
|
static_assert_size!(Operand, 56);
|
||||||
static_assert_size!(OpTy<'_>, 80);
|
static_assert_size!(OpTy<'_>, 80);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -892,10 +892,11 @@ where
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
use rustc_data_structures::static_assert_size;
|
||||||
// These are in alphabetical order, which is easy to maintain.
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(MemPlaceMeta, 24);
|
|
||||||
static_assert_size!(MemPlace, 40);
|
static_assert_size!(MemPlace, 40);
|
||||||
|
static_assert_size!(MemPlaceMeta, 24);
|
||||||
static_assert_size!(MPlaceTy<'_>, 64);
|
static_assert_size!(MPlaceTy<'_>, 64);
|
||||||
static_assert_size!(Place, 40);
|
static_assert_size!(Place, 40);
|
||||||
static_assert_size!(PlaceTy<'_>, 64);
|
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_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_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
|
||||||
|
|
||||||
query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
|
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.
|
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
||||||
fluent_messages! {
|
fluent_messages! {
|
||||||
|
// tidy-alphabetical-start
|
||||||
ast_lowering => "../locales/en-US/ast_lowering.ftl",
|
ast_lowering => "../locales/en-US/ast_lowering.ftl",
|
||||||
ast_passes => "../locales/en-US/ast_passes.ftl",
|
ast_passes => "../locales/en-US/ast_passes.ftl",
|
||||||
attr => "../locales/en-US/attr.ftl",
|
attr => "../locales/en-US/attr.ftl",
|
||||||
|
@ -64,6 +65,7 @@ fluent_messages! {
|
||||||
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
|
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
|
||||||
trait_selection => "../locales/en-US/trait_selection.ftl",
|
trait_selection => "../locales/en-US/trait_selection.ftl",
|
||||||
ty_utils => "../locales/en-US/ty_utils.ftl",
|
ty_utils => "../locales/en-US/ty_utils.ftl",
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
|
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
|
||||||
|
@ -277,6 +279,18 @@ pub enum SubdiagnosticMessage {
|
||||||
/// Non-translatable diagnostic message.
|
/// Non-translatable diagnostic message.
|
||||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||||
Str(String),
|
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
|
/// Identifier of a Fluent message. Instances of this variant are generated by the
|
||||||
/// `Subdiagnostic` derive.
|
/// `Subdiagnostic` derive.
|
||||||
FluentIdentifier(FluentId),
|
FluentIdentifier(FluentId),
|
||||||
|
@ -304,8 +318,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
|
||||||
#[rustc_diagnostic_item = "DiagnosticMessage"]
|
#[rustc_diagnostic_item = "DiagnosticMessage"]
|
||||||
pub enum DiagnosticMessage {
|
pub enum DiagnosticMessage {
|
||||||
/// Non-translatable diagnostic message.
|
/// 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),
|
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
|
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
|
||||||
/// message.
|
/// message.
|
||||||
///
|
///
|
||||||
|
@ -324,6 +350,7 @@ impl DiagnosticMessage {
|
||||||
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
|
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
|
||||||
let attr = match sub {
|
let attr = match sub {
|
||||||
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
|
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
|
||||||
|
SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
|
||||||
SubdiagnosticMessage::FluentIdentifier(id) => {
|
SubdiagnosticMessage::FluentIdentifier(id) => {
|
||||||
return DiagnosticMessage::FluentIdentifier(id, None);
|
return DiagnosticMessage::FluentIdentifier(id, None);
|
||||||
}
|
}
|
||||||
|
@ -332,6 +359,7 @@ impl DiagnosticMessage {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
|
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
|
||||||
|
DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
|
||||||
DiagnosticMessage::FluentIdentifier(id, _) => {
|
DiagnosticMessage::FluentIdentifier(id, _) => {
|
||||||
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
|
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
|
||||||
}
|
}
|
||||||
|
@ -367,6 +395,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
|
||||||
fn into(self) -> SubdiagnosticMessage {
|
fn into(self) -> SubdiagnosticMessage {
|
||||||
match self {
|
match self {
|
||||||
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
|
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
|
||||||
|
DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
|
||||||
DiagnosticMessage::FluentIdentifier(id, None) => {
|
DiagnosticMessage::FluentIdentifier(id, None) => {
|
||||||
SubdiagnosticMessage::FluentIdentifier(id)
|
SubdiagnosticMessage::FluentIdentifier(id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use crate::emitter::FileWithAnnotatedLines;
|
use crate::emitter::FileWithAnnotatedLines;
|
||||||
use crate::snippet::Line;
|
use crate::snippet::Line;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
||||||
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
||||||
|
@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
|
||||||
impl Emitter for AnnotateSnippetEmitterWriter {
|
impl Emitter for AnnotateSnippetEmitterWriter {
|
||||||
/// The entry point for the diagnostics generation
|
/// The entry point for the diagnostics generation
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
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 children = diag.children.clone();
|
||||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
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
|
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
|
||||||
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
||||||
/// diagnostic emission.
|
/// 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
|
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
|
||||||
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
/// 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].
|
/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
|
||||||
#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
|
#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
|
||||||
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
|
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
|
||||||
pub trait AddToDiagnostic {
|
pub trait AddToDiagnostic
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
/// Add a subdiagnostic to an existing diagnostic.
|
/// 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
|
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
|
||||||
|
@ -229,7 +244,7 @@ pub struct Diagnostic {
|
||||||
pub span: MultiSpan,
|
pub span: MultiSpan,
|
||||||
pub children: Vec<SubDiagnostic>,
|
pub children: Vec<SubDiagnostic>,
|
||||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
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
|
/// 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
|
/// 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(),
|
span: MultiSpan::new(),
|
||||||
children: vec![],
|
children: vec![],
|
||||||
suggestions: Ok(vec![]),
|
suggestions: Ok(vec![]),
|
||||||
args: vec![],
|
args: Default::default(),
|
||||||
sort_span: DUMMY_SP,
|
sort_span: DUMMY_SP,
|
||||||
is_lint: false,
|
is_lint: false,
|
||||||
}
|
}
|
||||||
|
@ -917,13 +932,30 @@ impl Diagnostic {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` - see
|
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||||
/// [rustc_macros::Subdiagnostic].
|
/// [rustc_macros::Subdiagnostic]).
|
||||||
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
|
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
|
||||||
subdiagnostic.add_to_diagnostic(self);
|
subdiagnostic.add_to_diagnostic(self);
|
||||||
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 {
|
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
|
||||||
self.span = sp.into();
|
self.span = sp.into();
|
||||||
if let Some(span) = self.span.primary_span() {
|
if let Some(span) = self.span.primary_span() {
|
||||||
|
@ -956,8 +988,11 @@ impl Diagnostic {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(&self) -> &[DiagnosticArg<'static>] {
|
// Exact iteration order of diagnostic arguments shouldn't make a difference to output because
|
||||||
&self.args
|
// 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(
|
pub fn set_arg(
|
||||||
|
@ -965,7 +1000,7 @@ impl Diagnostic {
|
||||||
name: impl Into<Cow<'static, str>>,
|
name: impl Into<Cow<'static, str>>,
|
||||||
arg: impl IntoDiagnosticArg,
|
arg: impl IntoDiagnosticArg,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.args.push((name.into(), arg.into_diagnostic_arg()));
|
self.args.insert(name.into(), arg.into_diagnostic_arg());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,7 +1011,7 @@ impl Diagnostic {
|
||||||
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
|
/// 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
|
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||||
/// passes the user's string along).
|
/// passes the user's string along).
|
||||||
fn subdiagnostic_message_to_diagnostic_message(
|
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||||
&self,
|
&self,
|
||||||
attr: impl Into<SubdiagnosticMessage>,
|
attr: impl Into<SubdiagnosticMessage>,
|
||||||
) -> DiagnosticMessage {
|
) -> DiagnosticMessage {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span};
|
||||||
|
|
||||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
||||||
use crate::styled_buffer::StyledBuffer;
|
use crate::styled_buffer::StyledBuffer;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
||||||
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
||||||
|
@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
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 children = diag.children.clone();
|
||||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
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::emitter::{Emitter, HumanReadableErrorType};
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::DiagnosticId;
|
use crate::DiagnosticId;
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
||||||
|
@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
|
||||||
|
|
||||||
impl Diagnostic {
|
impl Diagnostic {
|
||||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> 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 sugg = diag.suggestions.iter().flatten().map(|sugg| {
|
||||||
let translated_message = je.translate_message(&sugg.msg, &args);
|
let translated_message = je.translate_message(&sugg.msg, &args);
|
||||||
Diagnostic {
|
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;
|
// This is here to not allow mutation of flags;
|
||||||
// as of this writing it's only used in tests in librustc_middle.
|
// as of this writing it's only used in tests in librustc_middle.
|
||||||
pub fn can_emit_warnings(&self) -> bool {
|
pub fn can_emit_warnings(&self) -> bool {
|
||||||
|
|
|
@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_error_messages::FluentArgs;
|
use rustc_error_messages::FluentArgs;
|
||||||
use std::borrow::Cow;
|
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 {
|
pub trait Translate {
|
||||||
/// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
|
/// 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`
|
/// 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.
|
/// unavailable for the requested locale.
|
||||||
fn fallback_fluent_bundle(&self) -> &FluentBundle;
|
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.
|
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
|
||||||
fn translate_messages(
|
fn translate_messages(
|
||||||
&self,
|
&self,
|
||||||
|
@ -43,7 +55,9 @@ pub trait Translate {
|
||||||
) -> Cow<'_, str> {
|
) -> Cow<'_, str> {
|
||||||
trace!(?message, ?args);
|
trace!(?message, ?args);
|
||||||
let (identifier, attr) = match message {
|
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),
|
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -412,8 +412,6 @@ declare_features! (
|
||||||
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
|
(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
|
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
||||||
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
(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.
|
/// Allows using `..=X` as a patterns in slices.
|
||||||
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
|
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
|
||||||
/// Allows `if let` guard in match arms.
|
/// 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"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
// These are in alphabetical order, which is easy to maintain.
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(Block<'_>, 48);
|
static_assert_size!(Block<'_>, 48);
|
||||||
static_assert_size!(Body<'_>, 32);
|
static_assert_size!(Body<'_>, 32);
|
||||||
static_assert_size!(Expr<'_>, 64);
|
static_assert_size!(Expr<'_>, 64);
|
||||||
|
@ -3533,9 +3533,9 @@ mod size_asserts {
|
||||||
static_assert_size!(Local<'_>, 64);
|
static_assert_size!(Local<'_>, 64);
|
||||||
static_assert_size!(Param<'_>, 32);
|
static_assert_size!(Param<'_>, 32);
|
||||||
static_assert_size!(Pat<'_>, 72);
|
static_assert_size!(Pat<'_>, 72);
|
||||||
static_assert_size!(PatKind<'_>, 48);
|
|
||||||
static_assert_size!(Path<'_>, 40);
|
static_assert_size!(Path<'_>, 40);
|
||||||
static_assert_size!(PathSegment<'_>, 48);
|
static_assert_size!(PathSegment<'_>, 48);
|
||||||
|
static_assert_size!(PatKind<'_>, 48);
|
||||||
static_assert_size!(QPath<'_>, 24);
|
static_assert_size!(QPath<'_>, 24);
|
||||||
static_assert_size!(Res, 12);
|
static_assert_size!(Res, 12);
|
||||||
static_assert_size!(Stmt<'_>, 32);
|
static_assert_size!(Stmt<'_>, 32);
|
||||||
|
@ -3544,4 +3544,5 @@ mod size_asserts {
|
||||||
static_assert_size!(TraitItemKind<'_>, 48);
|
static_assert_size!(TraitItemKind<'_>, 48);
|
||||||
static_assert_size!(Ty<'_>, 48);
|
static_assert_size!(Ty<'_>, 48);
|
||||||
static_assert_size!(TyKind<'_>, 32);
|
static_assert_size!(TyKind<'_>, 32);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use hir::GenericParamKind;
|
use hir::GenericParamKind;
|
||||||
use rustc_errors::{
|
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 as hir;
|
||||||
use rustc_hir::{FnRetTy, Ty};
|
use rustc_hir::{FnRetTy, Ty};
|
||||||
|
@ -229,7 +230,10 @@ pub enum RegionOriginNote<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for RegionOriginNote<'_> {
|
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 mut label_or_note = |span, msg: DiagnosticMessage| {
|
||||||
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
|
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();
|
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 {
|
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 {
|
match self {
|
||||||
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
||||||
diag.span_label(param_span, fluent::infer::declared_different);
|
diag.span_label(param_span, fluent::infer::declared_different);
|
||||||
|
@ -340,7 +347,10 @@ pub struct AddLifetimeParamsSuggestion<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
|
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 mut mk_suggestion = || {
|
||||||
let (
|
let (
|
||||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
|
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
|
||||||
|
@ -439,7 +449,10 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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
|
self.unmet_requirements
|
||||||
.push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
|
.push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
|
||||||
diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
|
diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
|
||||||
|
@ -451,7 +464,10 @@ pub struct ImplNote {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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 {
|
match self.impl_span {
|
||||||
Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
|
Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
|
||||||
None => diag.note(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
|
// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
|
||||||
impl AddToDiagnostic for TraitSubdiag {
|
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 {
|
match self {
|
||||||
TraitSubdiag::Note { span } => {
|
TraitSubdiag::Note { span } => {
|
||||||
diag.span_note(span, "this has an implicit `'static` lifetime requirement");
|
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 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_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::{symbol::kw, Span};
|
use rustc_span::{symbol::kw, Span};
|
||||||
|
|
||||||
|
@ -159,7 +161,10 @@ impl RegionExplanation<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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 {
|
if let Some(span) = self.desc.span {
|
||||||
diag.span_note(span, fluent::infer::region_explanation);
|
diag.span_note(span, fluent::infer::region_explanation);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -540,7 +540,7 @@ fn test_codegen_options_tracking_hash() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
|
// 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!(ar, String::from("abc"));
|
||||||
untracked!(codegen_units, Some(42));
|
untracked!(codegen_units, Some(42));
|
||||||
untracked!(default_linker_libraries, true);
|
untracked!(default_linker_libraries, true);
|
||||||
|
@ -556,6 +556,7 @@ fn test_codegen_options_tracking_hash() {
|
||||||
untracked!(rpath, true);
|
untracked!(rpath, true);
|
||||||
untracked!(save_temps, true);
|
untracked!(save_temps, true);
|
||||||
untracked!(strip, Strip::Debuginfo);
|
untracked!(strip, Strip::Debuginfo);
|
||||||
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
macro_rules! tracked {
|
macro_rules! tracked {
|
||||||
($name: ident, $non_default_value: expr) => {
|
($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.
|
// 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!(code_model, Some(CodeModel::Large));
|
||||||
tracked!(control_flow_guard, CFGuard::Checks);
|
tracked!(control_flow_guard, CFGuard::Checks);
|
||||||
tracked!(debug_assertions, Some(true));
|
tracked!(debug_assertions, Some(true));
|
||||||
|
@ -577,8 +578,8 @@ fn test_codegen_options_tracking_hash() {
|
||||||
tracked!(force_unwind_tables, Some(true));
|
tracked!(force_unwind_tables, Some(true));
|
||||||
tracked!(inline_threshold, Some(0xf007ba11));
|
tracked!(inline_threshold, Some(0xf007ba11));
|
||||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
||||||
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
|
||||||
tracked!(link_dead_code, Some(true));
|
tracked!(link_dead_code, Some(true));
|
||||||
|
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
||||||
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
||||||
tracked!(lto, LtoCli::Fat);
|
tracked!(lto, LtoCli::Fat);
|
||||||
tracked!(metadata, vec![String::from("A"), String::from("B")]);
|
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!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
|
||||||
tracked!(target_cpu, Some(String::from("abc")));
|
tracked!(target_cpu, Some(String::from("abc")));
|
||||||
tracked!(target_feature, String::from("all the features, all of them"));
|
tracked!(target_feature, String::from("all the features, all of them"));
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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.
|
// 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.
|
// tidy-alphabetical-start
|
||||||
tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
|
|
||||||
tracked!(
|
tracked!(
|
||||||
real_rust_source_base_dir,
|
real_rust_source_base_dir,
|
||||||
Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
|
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]
|
#[test]
|
||||||
|
@ -641,7 +644,7 @@ fn test_unstable_options_tracking_hash() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
|
// 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!(assert_incr_state, Some(String::from("loaded")));
|
||||||
untracked!(deduplicate_diagnostics, false);
|
untracked!(deduplicate_diagnostics, false);
|
||||||
untracked!(dep_tasks, true);
|
untracked!(dep_tasks, true);
|
||||||
|
@ -678,12 +681,12 @@ fn test_unstable_options_tracking_hash() {
|
||||||
untracked!(perf_stats, true);
|
untracked!(perf_stats, true);
|
||||||
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
|
// `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!(pre_link_args, vec![String::from("abc"), String::from("def")]);
|
||||||
untracked!(profile_closures, true);
|
|
||||||
untracked!(print_llvm_passes, true);
|
untracked!(print_llvm_passes, true);
|
||||||
untracked!(print_mono_items, Some(String::from("abc")));
|
untracked!(print_mono_items, Some(String::from("abc")));
|
||||||
untracked!(print_type_sizes, true);
|
untracked!(print_type_sizes, true);
|
||||||
untracked!(proc_macro_backtrace, true);
|
untracked!(proc_macro_backtrace, true);
|
||||||
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
|
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
|
||||||
|
untracked!(profile_closures, true);
|
||||||
untracked!(query_dep_graph, true);
|
untracked!(query_dep_graph, true);
|
||||||
untracked!(save_analysis, true);
|
untracked!(save_analysis, true);
|
||||||
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
|
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
|
||||||
|
@ -701,6 +704,7 @@ fn test_unstable_options_tracking_hash() {
|
||||||
untracked!(unstable_options, true);
|
untracked!(unstable_options, true);
|
||||||
untracked!(validate_mir, true);
|
untracked!(validate_mir, true);
|
||||||
untracked!(verbose, true);
|
untracked!(verbose, true);
|
||||||
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
macro_rules! tracked {
|
macro_rules! tracked {
|
||||||
($name: ident, $non_default_value: expr) => {
|
($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.
|
// 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!(allow_features, Some(vec![String::from("lang_items")]));
|
||||||
tracked!(always_encode_mir, true);
|
tracked!(always_encode_mir, true);
|
||||||
tracked!(asm_comments, true);
|
tracked!(asm_comments, true);
|
||||||
|
@ -733,10 +737,10 @@ fn test_unstable_options_tracking_hash() {
|
||||||
tracked!(debug_macros, true);
|
tracked!(debug_macros, true);
|
||||||
tracked!(dep_info_omit_d_target, true);
|
tracked!(dep_info_omit_d_target, true);
|
||||||
tracked!(drop_tracking, true);
|
tracked!(drop_tracking, true);
|
||||||
tracked!(export_executable_symbols, true);
|
|
||||||
tracked!(dual_proc_macros, true);
|
tracked!(dual_proc_macros, true);
|
||||||
tracked!(dwarf_version, Some(5));
|
tracked!(dwarf_version, Some(5));
|
||||||
tracked!(emit_thin_lto, false);
|
tracked!(emit_thin_lto, false);
|
||||||
|
tracked!(export_executable_symbols, true);
|
||||||
tracked!(fewer_names, Some(true));
|
tracked!(fewer_names, Some(true));
|
||||||
tracked!(force_unstable_if_unmarked, true);
|
tracked!(force_unstable_if_unmarked, true);
|
||||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||||
|
@ -759,8 +763,8 @@ fn test_unstable_options_tracking_hash() {
|
||||||
tracked!(mutable_noalias, Some(true));
|
tracked!(mutable_noalias, Some(true));
|
||||||
tracked!(no_generate_arange_section, true);
|
tracked!(no_generate_arange_section, true);
|
||||||
tracked!(no_link, true);
|
tracked!(no_link, true);
|
||||||
tracked!(no_unique_section_names, true);
|
|
||||||
tracked!(no_profiler_runtime, true);
|
tracked!(no_profiler_runtime, true);
|
||||||
|
tracked!(no_unique_section_names, true);
|
||||||
tracked!(oom, OomStrategy::Panic);
|
tracked!(oom, OomStrategy::Panic);
|
||||||
tracked!(osx_rpath_install_name, true);
|
tracked!(osx_rpath_install_name, true);
|
||||||
tracked!(packed_bundled_libs, true);
|
tracked!(packed_bundled_libs, true);
|
||||||
|
@ -773,8 +777,8 @@ fn test_unstable_options_tracking_hash() {
|
||||||
tracked!(print_fuel, Some("abc".to_string()));
|
tracked!(print_fuel, Some("abc".to_string()));
|
||||||
tracked!(profile, true);
|
tracked!(profile, true);
|
||||||
tracked!(profile_emit, Some(PathBuf::from("abc")));
|
tracked!(profile_emit, Some(PathBuf::from("abc")));
|
||||||
tracked!(profiler_runtime, "abc".to_string());
|
|
||||||
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
||||||
|
tracked!(profiler_runtime, "abc".to_string());
|
||||||
tracked!(relax_elf_relocations, Some(true));
|
tracked!(relax_elf_relocations, Some(true));
|
||||||
tracked!(relro_level, Some(RelroLevel::Full));
|
tracked!(relro_level, Some(RelroLevel::Full));
|
||||||
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
||||||
|
@ -803,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
|
||||||
tracked!(verify_llvm_ir, true);
|
tracked!(verify_llvm_ir, true);
|
||||||
tracked!(virtual_function_elimination, true);
|
tracked!(virtual_function_elimination, true);
|
||||||
tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
|
tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
|
||||||
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
macro_rules! tracked_no_crate_hash {
|
macro_rules! tracked_no_crate_hash {
|
||||||
($name: ident, $non_default_value: expr) => {
|
($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_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
@ -23,7 +26,10 @@ pub enum OverruledAttributeSub {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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 {
|
match self {
|
||||||
OverruledAttributeSub::DefaultSource { id } => {
|
OverruledAttributeSub::DefaultSource { id } => {
|
||||||
diag.note(fluent::lint::default_source);
|
diag.note(fluent::lint::default_source);
|
||||||
|
@ -88,7 +94,10 @@ pub struct RequestedLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddToDiagnostic for 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.note(fluent::lint::requested_level);
|
||||||
diag.set_arg(
|
diag.set_arg(
|
||||||
"level",
|
"level",
|
||||||
|
|
|
@ -10,27 +10,31 @@ use synstructure::Structure;
|
||||||
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
||||||
pub(crate) struct DiagnosticDerive<'a> {
|
pub(crate) struct DiagnosticDerive<'a> {
|
||||||
structure: Structure<'a>,
|
structure: Structure<'a>,
|
||||||
handler: syn::Ident,
|
|
||||||
builder: DiagnosticDeriveBuilder,
|
builder: DiagnosticDeriveBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DiagnosticDerive<'a> {
|
impl<'a> DiagnosticDerive<'a> {
|
||||||
pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
|
pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
|
builder: DiagnosticDeriveBuilder {
|
||||||
handler,
|
diag,
|
||||||
|
kind: DiagnosticDeriveKind::Diagnostic { handler },
|
||||||
|
},
|
||||||
structure,
|
structure,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
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 implementation = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||||
let preamble = builder.preamble(&variant);
|
let preamble = builder.preamble(&variant);
|
||||||
let body = builder.body(&variant);
|
let body = builder.body(&variant);
|
||||||
|
|
||||||
let diag = &builder.parent.diag;
|
let diag = &builder.parent.diag;
|
||||||
|
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
let init = match builder.slug.value_ref() {
|
let init = match builder.slug.value_ref() {
|
||||||
None => {
|
None => {
|
||||||
span_err(builder.span, "diagnostic slug not specified")
|
span_err(builder.span, "diagnostic slug not specified")
|
||||||
|
@ -48,14 +52,17 @@ impl<'a> DiagnosticDerive<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let formatting_init = &builder.formatting_init;
|
||||||
quote! {
|
quote! {
|
||||||
#init
|
#init
|
||||||
|
#formatting_init
|
||||||
#preamble
|
#preamble
|
||||||
#body
|
#body
|
||||||
#diag
|
#diag
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
|
||||||
structure.gen_impl(quote! {
|
structure.gen_impl(quote! {
|
||||||
gen impl<'__diagnostic_handler_sess, G>
|
gen impl<'__diagnostic_handler_sess, G>
|
||||||
rustc_errors::IntoDiagnostic<'__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 body = builder.body(&variant);
|
||||||
|
|
||||||
let diag = &builder.parent.diag;
|
let diag = &builder.parent.diag;
|
||||||
|
let formatting_init = &builder.formatting_init;
|
||||||
quote! {
|
quote! {
|
||||||
#preamble
|
#preamble
|
||||||
|
#formatting_init
|
||||||
#body
|
#body
|
||||||
#diag
|
#diag
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
|
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||||
// HACK(wafflelapkin): initialize slug (???)
|
// Collect the slug by generating the preamble.
|
||||||
let _preamble = builder.preamble(&variant);
|
let _ = builder.preamble(&variant);
|
||||||
|
|
||||||
match builder.slug.value_ref() {
|
match builder.slug.value_ref() {
|
||||||
None => {
|
None => {
|
||||||
|
@ -125,7 +133,10 @@ impl<'a> LintDiagnosticDerive<'a> {
|
||||||
let diag = &builder.diag;
|
let diag = &builder.diag;
|
||||||
structure.gen_impl(quote! {
|
structure.gen_impl(quote! {
|
||||||
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
|
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;
|
use rustc_errors::IntoDiagnosticArg;
|
||||||
#implementation
|
#implementation
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ use crate::diagnostics::error::{
|
||||||
DiagnosticDeriveError,
|
DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
use crate::diagnostics::utils::{
|
||||||
bind_style_of_field, build_field_mapping, report_error_if_not_applied_to_span,
|
build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
|
||||||
report_type_error, should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo,
|
should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
|
||||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
@ -17,9 +17,9 @@ use syn::{
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
|
|
||||||
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
|
/// 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 {
|
pub(crate) enum DiagnosticDeriveKind {
|
||||||
Diagnostic,
|
Diagnostic { handler: syn::Ident },
|
||||||
LintDiagnostic,
|
LintDiagnostic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
|
||||||
/// The parent builder for the entire type.
|
/// The parent builder for the entire type.
|
||||||
pub parent: &'parent DiagnosticDeriveBuilder,
|
pub parent: &'parent DiagnosticDeriveBuilder,
|
||||||
|
|
||||||
|
/// Initialization of format strings for code suggestions.
|
||||||
|
pub formatting_init: TokenStream,
|
||||||
|
|
||||||
/// Span of the struct or the enum variant.
|
/// Span of the struct or the enum variant.
|
||||||
pub span: proc_macro::Span,
|
pub span: proc_macro::Span,
|
||||||
|
|
||||||
|
@ -88,19 +91,7 @@ impl DiagnosticDeriveBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for variant in structure.variants_mut() {
|
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||||
// 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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let variants = structure.each_variant(|variant| {
|
let variants = structure.each_variant(|variant| {
|
||||||
let span = match structure.ast().data {
|
let span = match structure.ast().data {
|
||||||
syn::Data::Struct(..) => span,
|
syn::Data::Struct(..) => span,
|
||||||
|
@ -112,6 +103,7 @@ impl DiagnosticDeriveBuilder {
|
||||||
parent: &self,
|
parent: &self,
|
||||||
span,
|
span,
|
||||||
field_map: build_field_mapping(variant),
|
field_map: build_field_mapping(variant),
|
||||||
|
formatting_init: TokenStream::new(),
|
||||||
slug: None,
|
slug: None,
|
||||||
code: 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
|
/// Generates calls to `span_label` and similar functions based on the attributes on fields or
|
||||||
/// calls to `set_arg` when no attributes are present.
|
/// 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 {
|
pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
|
||||||
let mut body = quote! {};
|
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.extend(self.generate_field_attrs_code(binding));
|
||||||
}
|
}
|
||||||
body
|
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 {
|
fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
|
||||||
let field = binding_info.ast();
|
let field = binding_info.ast();
|
||||||
let field_binding = &binding_info.binding;
|
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);
|
let inner_ty = FieldInnerTy::from_type(&field.ty);
|
||||||
|
|
||||||
field
|
field
|
||||||
|
@ -304,10 +297,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
let (binding, needs_destructure) = if needs_clone {
|
let (binding, needs_destructure) = if needs_clone {
|
||||||
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
||||||
(quote! { #field_binding.clone() }, false)
|
(quote! { #field_binding.clone() }, false)
|
||||||
} else if needs_move {
|
|
||||||
(quote! { #field_binding }, true)
|
|
||||||
} else {
|
} else {
|
||||||
(quote! { *#field_binding }, true)
|
(quote! { #field_binding }, true)
|
||||||
};
|
};
|
||||||
|
|
||||||
let generated_code = self
|
let generated_code = self
|
||||||
|
@ -340,18 +331,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
let diag = &self.parent.diag;
|
let diag = &self.parent.diag;
|
||||||
let meta = attr.parse_meta()?;
|
let meta = attr.parse_meta()?;
|
||||||
|
|
||||||
if let Meta::Path(_) = meta {
|
let ident = &attr.path.segments.last().unwrap().ident;
|
||||||
let ident = &attr.path.segments.last().unwrap().ident;
|
let name = ident.to_string();
|
||||||
let name = ident.to_string();
|
match (&meta, name.as_str()) {
|
||||||
let name = name.as_str();
|
// Don't need to do anything - by virtue of the attribute existing, the
|
||||||
match name {
|
// `set_arg` call will not be generated.
|
||||||
"skip_arg" => {
|
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
|
||||||
// Don't need to do anything - by virtue of the attribute existing, the
|
(Meta::Path(_), "primary_span") => {
|
||||||
// `set_arg` call will not be generated.
|
match self.parent.kind {
|
||||||
return Ok(quote! {});
|
DiagnosticDeriveKind::Diagnostic { .. } => {
|
||||||
}
|
|
||||||
"primary_span" => match self.parent.kind {
|
|
||||||
DiagnosticDeriveKind::Diagnostic => {
|
|
||||||
report_error_if_not_applied_to_span(attr, &info)?;
|
report_error_if_not_applied_to_span(attr, &info)?;
|
||||||
|
|
||||||
return Ok(quote! {
|
return Ok(quote! {
|
||||||
|
@ -363,10 +351,50 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
|
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)?;
|
let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
|
||||||
|
@ -389,7 +417,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
SubdiagnosticKind::Suggestion {
|
SubdiagnosticKind::Suggestion {
|
||||||
suggestion_kind,
|
suggestion_kind,
|
||||||
applicability: static_applicability,
|
applicability: static_applicability,
|
||||||
code,
|
code_field,
|
||||||
|
code_init,
|
||||||
} => {
|
} => {
|
||||||
let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
|
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 });
|
.unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
|
||||||
let style = suggestion_kind.to_suggestion_style();
|
let style = suggestion_kind.to_suggestion_style();
|
||||||
|
|
||||||
|
self.formatting_init.extend(code_init);
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#diag.span_suggestion_with_style(
|
#diag.span_suggestion_with_style(
|
||||||
#span_field,
|
#span_field,
|
||||||
rustc_errors::fluent::#slug,
|
rustc_errors::fluent::#slug,
|
||||||
#code,
|
#code_field,
|
||||||
#applicability,
|
#applicability,
|
||||||
#style
|
#style
|
||||||
);
|
);
|
||||||
|
@ -451,7 +481,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
|
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
|
||||||
ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
|
ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
|
||||||
let binding = &info.binding.binding;
|
let binding = &info.binding.binding;
|
||||||
Ok((quote!(*#binding), None))
|
Ok((quote!(#binding), None))
|
||||||
}
|
}
|
||||||
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
|
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
|
||||||
Type::Tuple(tup) => {
|
Type::Tuple(tup) => {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
|
||||||
pub(crate) use fluent::fluent_messages;
|
pub(crate) use fluent::fluent_messages;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::format_ident;
|
use quote::format_ident;
|
||||||
use subdiagnostic::SubdiagnosticDerive;
|
use subdiagnostic::SubdiagnosticDeriveBuilder;
|
||||||
use synstructure::Structure;
|
use synstructure::Structure;
|
||||||
|
|
||||||
/// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
|
/// 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 });
|
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
|
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,
|
DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
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,
|
report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
||||||
SpannedOption, SubdiagnosticKind,
|
SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
|
@ -15,19 +15,19 @@ use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
|
|
||||||
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
||||||
pub(crate) struct SubdiagnosticDerive<'a> {
|
pub(crate) struct SubdiagnosticDeriveBuilder {
|
||||||
structure: Structure<'a>,
|
|
||||||
diag: syn::Ident,
|
diag: syn::Ident,
|
||||||
|
f: syn::Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SubdiagnosticDerive<'a> {
|
impl SubdiagnosticDeriveBuilder {
|
||||||
pub(crate) fn new(structure: Structure<'a>) -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
let diag = format_ident!("diag");
|
let diag = format_ident!("diag");
|
||||||
Self { structure, diag }
|
let f = format_ident!("f");
|
||||||
|
Self { diag, f }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream {
|
||||||
let SubdiagnosticDerive { mut structure, diag } = self;
|
|
||||||
let implementation = {
|
let implementation = {
|
||||||
let ast = structure.ast();
|
let ast = structure.ast();
|
||||||
let span = ast.span().unwrap();
|
let span = ast.span().unwrap();
|
||||||
|
@ -53,10 +53,11 @@ impl<'a> SubdiagnosticDerive<'a> {
|
||||||
|
|
||||||
structure.bind_with(|_| synstructure::BindStyle::Move);
|
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||||
let variants_ = structure.each_variant(|variant| {
|
let variants_ = structure.each_variant(|variant| {
|
||||||
let mut builder = SubdiagnosticDeriveBuilder {
|
let mut builder = SubdiagnosticDeriveVariantBuilder {
|
||||||
diag: &diag,
|
parent: &self,
|
||||||
variant,
|
variant,
|
||||||
span,
|
span,
|
||||||
|
formatting_init: TokenStream::new(),
|
||||||
fields: build_field_mapping(variant),
|
fields: build_field_mapping(variant),
|
||||||
span_field: None,
|
span_field: None,
|
||||||
applicability: 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! {
|
let ret = structure.gen_impl(quote! {
|
||||||
gen impl rustc_errors::AddToDiagnostic for @Self {
|
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};
|
use rustc_errors::{Applicability, IntoDiagnosticArg};
|
||||||
#implementation
|
#implementation
|
||||||
}
|
}
|
||||||
|
@ -88,15 +97,18 @@ impl<'a> SubdiagnosticDerive<'a> {
|
||||||
/// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
|
/// 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
|
/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
|
||||||
/// double mut borrow later on.
|
/// double mut borrow later on.
|
||||||
struct SubdiagnosticDeriveBuilder<'a> {
|
struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||||
/// The identifier to use for the generated `DiagnosticBuilder` instance.
|
/// 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).
|
/// Info for the current variant (or the type if not an enum).
|
||||||
variant: &'a VariantInfo<'a>,
|
variant: &'a VariantInfo<'a>,
|
||||||
/// Span for the entire type.
|
/// Span for the entire type.
|
||||||
span: proc_macro::Span,
|
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
|
/// Store a map of field name to its corresponding field. This is built on construction of the
|
||||||
/// derive builder.
|
/// derive builder.
|
||||||
fields: FieldMap,
|
fields: FieldMap,
|
||||||
|
@ -112,7 +124,7 @@ struct SubdiagnosticDeriveBuilder<'a> {
|
||||||
has_suggestion_parts: bool,
|
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> {
|
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||||
self.fields.get(field)
|
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> {
|
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||||
let mut kind_slugs = vec![];
|
let mut kind_slugs = vec![];
|
||||||
|
|
||||||
|
@ -187,7 +199,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
let ast = binding.ast();
|
let ast = binding.ast();
|
||||||
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
|
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();
|
let ident = ast.ident.as_ref().unwrap();
|
||||||
// strip `r#` prefix, if present
|
// strip `r#` prefix, if present
|
||||||
let ident = format_ident!("{}", ident);
|
let ident = format_ident!("{}", ident);
|
||||||
|
@ -222,7 +234,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let generated = self
|
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());
|
.unwrap_or_else(|v| v.to_compile_error());
|
||||||
|
|
||||||
inner_ty.with(binding, generated)
|
inner_ty.with(binding, generated)
|
||||||
|
@ -235,13 +247,18 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
kind_stats: KindsStatistics,
|
kind_stats: KindsStatistics,
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
info: FieldInfo<'_>,
|
info: FieldInfo<'_>,
|
||||||
|
clone_suggestion_code: bool,
|
||||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let meta = attr.parse_meta()?;
|
let meta = attr.parse_meta()?;
|
||||||
match meta {
|
match meta {
|
||||||
Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
|
Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
|
||||||
Meta::List(list @ MetaList { .. }) => {
|
Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
|
||||||
self.generate_field_code_inner_list(kind_stats, attr, info, list)
|
kind_stats,
|
||||||
}
|
attr,
|
||||||
|
info,
|
||||||
|
list,
|
||||||
|
clone_suggestion_code,
|
||||||
|
),
|
||||||
_ => throw_invalid_attr!(attr, &meta),
|
_ => throw_invalid_attr!(attr, &meta),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,6 +362,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
info: FieldInfo<'_>,
|
info: FieldInfo<'_>,
|
||||||
list: MetaList,
|
list: MetaList,
|
||||||
|
clone_suggestion_code: bool,
|
||||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let span = attr.span().unwrap();
|
let span = attr.span().unwrap();
|
||||||
let ident = &list.path.segments.last().unwrap().ident;
|
let ident = &list.path.segments.last().unwrap().ident;
|
||||||
|
@ -382,7 +400,8 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
match nested_name {
|
match nested_name {
|
||||||
"code" => {
|
"code" => {
|
||||||
let formatted_str = self.build_format(&value.value(), value.span());
|
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| {
|
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||||
diag.help("`code` is the only valid nested attribute")
|
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 = \"...\"`")
|
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
|
||||||
.emit();
|
.emit();
|
||||||
return Ok(quote! {});
|
return Ok(quote! {});
|
||||||
};
|
};
|
||||||
let binding = info.binding;
|
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| {
|
_ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
|
||||||
let mut span_attrs = vec![];
|
let mut span_attrs = vec![];
|
||||||
|
@ -442,13 +467,23 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
|
|
||||||
let span_field = self.span_field.value_ref();
|
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();
|
let mut calls = TokenStream::new();
|
||||||
for (kind, slug) in kind_slugs {
|
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 name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||||
let message = quote! { rustc_errors::fluent::#slug };
|
|
||||||
let call = match kind {
|
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
|
let applicability = applicability
|
||||||
.value()
|
.value()
|
||||||
.map(|a| quote! { #a })
|
.map(|a| quote! { #a })
|
||||||
|
@ -457,8 +492,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
|
|
||||||
if let Some(span) = span_field {
|
if let Some(span) = span_field {
|
||||||
let style = suggestion_kind.to_suggestion_style();
|
let style = suggestion_kind.to_suggestion_style();
|
||||||
|
quote! { #diag.#name(#span, #message, #code_field, #applicability, #style); }
|
||||||
quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
|
|
||||||
} else {
|
} else {
|
||||||
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
|
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
|
||||||
quote! { unreachable!(); }
|
quote! { unreachable!(); }
|
||||||
|
@ -499,6 +533,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
calls.extend(call);
|
calls.extend(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,11 +545,13 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
|
||||||
.map(|binding| self.generate_field_set_arg(binding))
|
.map(|binding| self.generate_field_set_arg(binding))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let formatting_init = &self.formatting_init;
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#init
|
#init
|
||||||
|
#formatting_init
|
||||||
#attr_args
|
#attr_args
|
||||||
#calls
|
|
||||||
#plain_args
|
#plain_args
|
||||||
|
#calls
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,29 @@ use crate::diagnostics::error::{
|
||||||
use proc_macro::Span;
|
use proc_macro::Span;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use std::cmp::Ordering;
|
use std::cell::RefCell;
|
||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
|
use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
|
||||||
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
|
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
|
||||||
use synstructure::{BindStyle, BindingInfo, VariantInfo};
|
use synstructure::{BindingInfo, VariantInfo};
|
||||||
|
|
||||||
use super::error::invalid_nested_attr;
|
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`.
|
/// 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
|
/// 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!();
|
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.
|
/// Returns `Option` containing inner type if there is one.
|
||||||
pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
|
pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -434,7 +456,12 @@ pub(super) enum SubdiagnosticKind {
|
||||||
Suggestion {
|
Suggestion {
|
||||||
suggestion_kind: SuggestionKind,
|
suggestion_kind: SuggestionKind,
|
||||||
applicability: SpannedOption<Applicability>,
|
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}]`
|
/// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
|
||||||
MultipartSuggestion {
|
MultipartSuggestion {
|
||||||
|
@ -469,7 +496,8 @@ impl SubdiagnosticKind {
|
||||||
SubdiagnosticKind::Suggestion {
|
SubdiagnosticKind::Suggestion {
|
||||||
suggestion_kind,
|
suggestion_kind,
|
||||||
applicability: None,
|
applicability: None,
|
||||||
code: TokenStream::new(),
|
code_field: new_code_ident(),
|
||||||
|
code_init: TokenStream::new(),
|
||||||
}
|
}
|
||||||
} else if let Some(suggestion_kind) =
|
} else if let Some(suggestion_kind) =
|
||||||
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
|
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
|
||||||
|
@ -548,9 +576,10 @@ impl SubdiagnosticKind {
|
||||||
};
|
};
|
||||||
|
|
||||||
match (nested_name, &mut kind) {
|
match (nested_name, &mut kind) {
|
||||||
("code", SubdiagnosticKind::Suggestion { .. }) => {
|
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||||
let formatted_str = fields.build_format(&value.value(), value.span());
|
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",
|
"applicability",
|
||||||
|
@ -582,13 +611,13 @@ impl SubdiagnosticKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
|
SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
|
||||||
*code_field = if let Some((code, _)) = code {
|
*code_init = if let Some(init) = code.value() {
|
||||||
code
|
init
|
||||||
} else {
|
} else {
|
||||||
span_err(span, "suggestion without `code = \"...\"`").emit();
|
span_err(span, "suggestion without `code = \"...\"`").emit();
|
||||||
quote! { "" }
|
quote! { let #code_field: String = unreachable!(); }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
SubdiagnosticKind::Label
|
SubdiagnosticKind::Label
|
||||||
| SubdiagnosticKind::Note
|
| 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
|
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
||||||
/// call (like `span_label`).
|
/// call (like `span_label`).
|
||||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||||
field.attrs.is_empty()
|
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 {
|
fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||||
if tcx.def_kind(def_id) != DefKind::AssocFn {
|
if tcx.def_kind(def_id) != DefKind::AssocFn {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1165,6 +1202,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
record!(self.tables.trait_impl_trait_tys[def_id] <- table);
|
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(());
|
let inherent_impls = tcx.crate_inherent_impls(());
|
||||||
for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
|
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);
|
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| {
|
record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
|
||||||
assert!(f.did.is_local());
|
assert!(f.did.is_local());
|
||||||
f.did.index
|
f.did.index
|
||||||
|
@ -1220,7 +1259,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
record!(self.tables.variant_data[def_id] <- data);
|
record!(self.tables.variant_data[def_id] <- data);
|
||||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
|
||||||
if variant.ctor_kind == CtorKind::Fn {
|
if variant.ctor_kind == CtorKind::Fn {
|
||||||
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
|
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.repr_options[def_id] <- adt_def.repr());
|
||||||
record!(self.tables.variant_data[def_id] <- data);
|
record!(self.tables.variant_data[def_id] <- data);
|
||||||
self.tables.constness.set(def_id.index, hir::Constness::Const);
|
|
||||||
if variant.ctor_kind == CtorKind::Fn {
|
if variant.ctor_kind == CtorKind::Fn {
|
||||||
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
|
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.asyncness.set(def_id.index, m_sig.header.asyncness);
|
||||||
self.tables.constness.set(def_id.index, hir::Constness::NotConst);
|
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type => {
|
||||||
self.encode_explicit_item_bounds(def_id);
|
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!() };
|
let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
|
||||||
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
|
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));
|
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 => {}
|
ty::AssocKind::Const | ty::AssocKind::Type => {}
|
||||||
}
|
}
|
||||||
|
@ -1474,7 +1503,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
hir::ItemKind::Fn(ref sig, .., body) => {
|
hir::ItemKind::Fn(ref sig, .., body) => {
|
||||||
self.tables.asyncness.set(def_id.index, sig.header.asyncness);
|
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));
|
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, _) => {
|
hir::ItemKind::Macro(ref macro_def, _) => {
|
||||||
if macro_def.macro_rules {
|
if macro_def.macro_rules {
|
||||||
|
@ -1495,7 +1523,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
hir::ItemKind::Struct(ref struct_def, _) => {
|
hir::ItemKind::Struct(ref struct_def, _) => {
|
||||||
let adt_def = self.tcx.adt_def(def_id);
|
let adt_def = self.tcx.adt_def(def_id);
|
||||||
record!(self.tables.repr_options[def_id] <- adt_def.repr());
|
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
|
// Encode def_ids for each field and method
|
||||||
// for methods, write all the stuff get_trait_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(),
|
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.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);
|
let trait_ref = self.tcx.impl_trait_ref(def_id);
|
||||||
if let Some(trait_ref) = trait_ref {
|
if let Some(trait_ref) = trait_ref {
|
||||||
|
|
|
@ -2946,11 +2946,12 @@ impl Location {
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(BasicBlockData<'_>, 144);
|
||||||
static_assert_size!(LocalDecl<'_>, 56);
|
static_assert_size!(LocalDecl<'_>, 56);
|
||||||
static_assert_size!(Statement<'_>, 32);
|
static_assert_size!(Statement<'_>, 32);
|
||||||
static_assert_size!(StatementKind<'_>, 16);
|
static_assert_size!(StatementKind<'_>, 16);
|
||||||
static_assert_size!(Terminator<'_>, 112);
|
static_assert_size!(Terminator<'_>, 112);
|
||||||
static_assert_size!(TerminatorKind<'_>, 96);
|
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"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
// These are in alphabetical order, which is easy to maintain.
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(AggregateKind<'_>, 40);
|
static_assert_size!(AggregateKind<'_>, 40);
|
||||||
static_assert_size!(Operand<'_>, 24);
|
static_assert_size!(Operand<'_>, 24);
|
||||||
static_assert_size!(Place<'_>, 16);
|
static_assert_size!(Place<'_>, 16);
|
||||||
static_assert_size!(PlaceElem<'_>, 24);
|
static_assert_size!(PlaceElem<'_>, 24);
|
||||||
static_assert_size!(Rvalue<'_>, 40);
|
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"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
// These are in alphabetical order, which is easy to maintain.
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(Block, 56);
|
static_assert_size!(Block, 56);
|
||||||
static_assert_size!(Expr<'_>, 64);
|
static_assert_size!(Expr<'_>, 64);
|
||||||
static_assert_size!(ExprKind<'_>, 40);
|
static_assert_size!(ExprKind<'_>, 40);
|
||||||
|
@ -856,4 +856,5 @@ mod size_asserts {
|
||||||
static_assert_size!(PatKind<'_>, 56);
|
static_assert_size!(PatKind<'_>, 56);
|
||||||
static_assert_size!(Stmt<'_>, 48);
|
static_assert_size!(Stmt<'_>, 48);
|
||||||
static_assert_size!(StmtKind<'_>, 40);
|
static_assert_size!(StmtKind<'_>, 40);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -2668,8 +2668,9 @@ pub struct DestructuredConst<'tcx> {
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(PredicateS<'_>, 48);
|
||||||
static_assert_size!(TyS<'_>, 40);
|
static_assert_size!(TyS<'_>, 40);
|
||||||
static_assert_size!(WithStableHash<TyS<'_>>, 56);
|
static_assert_size!(WithStableHash<TyS<'_>>, 56);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,7 +459,8 @@ fn make_token_stream(
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(AttrWrapper, 16);
|
||||||
static_assert_size!(LazyAttrTokenStreamImpl, 144);
|
static_assert_size!(LazyAttrTokenStreamImpl, 144);
|
||||||
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -1789,20 +1789,25 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut err = self.expected_ident_found();
|
let mut err = self.expected_ident_found();
|
||||||
if let Some((ident, _)) = self.token.ident() && ident.as_str() == "let" {
|
if self.eat_keyword_noexpect(kw::Let)
|
||||||
self.bump(); // `let`
|
&& let removal_span = self.prev_token.span.until(self.token.span)
|
||||||
let 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(
|
err.span_suggestion(
|
||||||
span,
|
removal_span,
|
||||||
"remove the let, the `let` keyword is not allowed in struct field definitions",
|
"remove this `let` keyword",
|
||||||
String::new(),
|
String::new(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
err.note("the `let` keyword is not allowed in `struct` fields");
|
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.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
|
||||||
err.emit();
|
err.emit();
|
||||||
self.bump();
|
|
||||||
return Ok(ident);
|
return Ok(ident);
|
||||||
|
} else {
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
use rustc_errors::AddToDiagnostic;
|
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[note(query_system::cycle_stack_middle)]
|
||||||
pub struct CycleStack {
|
pub struct CycleStack {
|
||||||
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub desc: String,
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum HandleCycleError {
|
pub enum HandleCycleError {
|
||||||
Error,
|
Error,
|
||||||
|
@ -53,7 +49,7 @@ pub struct Cycle {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub stack_bottom: String,
|
pub stack_bottom: String,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic(eager)]
|
||||||
pub cycle_stack: Vec<CycleStack>,
|
pub cycle_stack: Vec<CycleStack>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub stack_count: StackCount,
|
pub stack_count: StackCount,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
// #![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -1075,12 +1075,11 @@ mod parse {
|
||||||
options! {
|
options! {
|
||||||
CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
|
CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
|
||||||
|
|
||||||
// This list is in alphabetical order.
|
|
||||||
//
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
// - src/doc/rustc/src/codegen-options/index.md
|
// - src/doc/rustc/src/codegen-options/index.md
|
||||||
|
|
||||||
|
// tidy-alphabetical-start
|
||||||
ar: String = (String::new(), parse_string, [UNTRACKED],
|
ar: String = (String::new(), parse_string, [UNTRACKED],
|
||||||
"this option is deprecated and does nothing"),
|
"this option is deprecated and does nothing"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
|
#[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_feature: String = (String::new(), parse_target_feature, [TRACKED],
|
||||||
"target specific attributes. (`rustc --print target-features` for details). \
|
"target specific attributes. (`rustc --print target-features` for details). \
|
||||||
This feature is unsafe."),
|
This feature is unsafe."),
|
||||||
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
// This list is in alphabetical order.
|
|
||||||
//
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
// - src/doc/rustc/src/codegen-options/index.md
|
// - src/doc/rustc/src/codegen-options/index.md
|
||||||
|
@ -1206,24 +1204,23 @@ options! {
|
||||||
options! {
|
options! {
|
||||||
UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
|
UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
|
||||||
|
|
||||||
// This list is in alphabetical order.
|
|
||||||
//
|
|
||||||
// If you add a new option, please update:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
// - src/doc/unstable-book/src/compiler-flags
|
// - src/doc/unstable-book/src/compiler-flags
|
||||||
|
|
||||||
|
// tidy-alphabetical-start
|
||||||
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
|
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
|
||||||
"only allow the listed language features to be enabled in code (space separated)"),
|
"only allow the listed language features to be enabled in code (space separated)"),
|
||||||
always_encode_mir: bool = (false, parse_bool, [TRACKED],
|
always_encode_mir: bool = (false, parse_bool, [TRACKED],
|
||||||
"encode MIR of all functions into the crate metadata (default: no)"),
|
"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")]
|
#[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")]
|
||||||
asm_comments: bool = (false, parse_bool, [TRACKED],
|
asm_comments: bool = (false, parse_bool, [TRACKED],
|
||||||
"generate comments into the assembly (may change behavior) (default: no)"),
|
"generate comments into the assembly (may change behavior) (default: no)"),
|
||||||
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||||
"assert that the incremental cache is in given state: \
|
"assert that the incremental cache is in given state: \
|
||||||
either `loaded` or `not-loaded`."),
|
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")]
|
#[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
|
||||||
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
|
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
|
||||||
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
|
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
|
||||||
|
@ -1256,6 +1253,8 @@ options! {
|
||||||
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
|
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"print tasks that execute and the color their dep node gets (requires debug build) \
|
"print tasks that execute and the color their dep node gets (requires debug build) \
|
||||||
(default: no)"),
|
(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],
|
dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
|
||||||
"import library generation tool (windows-gnu only)"),
|
"import library generation tool (windows-gnu only)"),
|
||||||
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
|
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)"),
|
"hash spans relative to their parent item for incr. comp. (default: no)"),
|
||||||
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
|
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"verify incr. comp. hashes of green query instances (default: no)"),
|
"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],
|
inline_llvm: bool = (true, parse_bool, [TRACKED],
|
||||||
"enable LLVM inlining (default: yes)"),
|
"enable LLVM inlining (default: yes)"),
|
||||||
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"enable MIR inlining (default: no)"),
|
"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],
|
inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||||
"inlining threshold for functions with inline hint (default: 100)"),
|
"inlining threshold for functions with inline hint (default: 100)"),
|
||||||
inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||||
"control whether `#[inline]` functions are in all CGUs"),
|
"a default MIR inlining threshold (default: 50)"),
|
||||||
input_stats: bool = (false, parse_bool, [UNTRACKED],
|
input_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"gather statistics about the input (default: no)"),
|
"gather statistics about the input (default: no)"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
#[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)"),
|
"insert function instrument code for mcount-based tracing (default: no)"),
|
||||||
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
|
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"keep hygiene data after analysis (default: no)"),
|
"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: bool = (true, parse_bool, [UNTRACKED],
|
||||||
"link native libraries in the linker invocation (default: yes)"),
|
"link native libraries in the linker invocation (default: yes)"),
|
||||||
link_only: bool = (false, parse_bool, [TRACKED],
|
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 \
|
"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 \
|
enabled, overriding all other checks. Passes that are not specified are enabled or \
|
||||||
disabled by other flags as usual."),
|
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")]
|
#[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_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 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],
|
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
|
||||||
"the size at which the `large_assignments` lint starts to be emitted"),
|
"the size at which the `large_assignments` lint starts to be emitted"),
|
||||||
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
|
@ -1419,18 +1420,16 @@ options! {
|
||||||
"compile without linking"),
|
"compile without linking"),
|
||||||
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
|
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
|
||||||
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
|
"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],
|
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
|
||||||
"prevent automatic injection of the profiler_builtins crate"),
|
"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_docs: bool = (false, parse_bool, [TRACKED],
|
||||||
"normalize associated items in rustdoc when generating documentation"),
|
"normalize associated items in rustdoc when generating documentation"),
|
||||||
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
||||||
"panic strategy for out-of-memory handling"),
|
"panic strategy for out-of-memory handling"),
|
||||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||||
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
|
"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],
|
packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
|
||||||
"change rlib format to store native libraries as archives"),
|
"change rlib format to store native libraries as archives"),
|
||||||
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
||||||
|
@ -1480,25 +1479,20 @@ options! {
|
||||||
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||||
"file path to emit profiling data at runtime when using 'profile' \
|
"file path to emit profiling data at runtime when using 'profile' \
|
||||||
(default based on relative source path)"),
|
(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],
|
profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||||
"use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
|
"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],
|
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"enable queries of the dependency graph for regression testing (default: no)"),
|
"enable queries of the dependency graph for regression testing (default: no)"),
|
||||||
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
randomize_layout: bool = (false, parse_bool, [TRACKED],
|
||||||
"randomize the layout of types (default: no)"),
|
"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],
|
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"whether ELF relocations can be relaxed"),
|
"whether ELF relocations can be relaxed"),
|
||||||
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
|
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
|
||||||
"choose which RELRO level to use"),
|
"choose which RELRO level to use"),
|
||||||
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||||
"remap paths under the current working directory to this path prefix"),
|
"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],
|
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
|
||||||
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
||||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||||
|
@ -1516,27 +1510,41 @@ options! {
|
||||||
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||||
parse_switch_with_opt_path, [UNTRACKED],
|
parse_switch_with_opt_path, [UNTRACKED],
|
||||||
"run the self profiler and output the raw event data"),
|
"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],
|
self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
|
||||||
"counter used by the self profiler (default: `wall-time`), one of:
|
"counter used by the self profiler (default: `wall-time`), one of:
|
||||||
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
|
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
|
||||||
`instructions:u` (retired instructions, userspace-only)
|
`instructions:u` (retired instructions, userspace-only)
|
||||||
`instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
|
`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],
|
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"make the current crate share its generic instantiations"),
|
"make the current crate share its generic instantiations"),
|
||||||
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
|
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||||
"show spans for compiler debugging (expr|pat|ty)"),
|
"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],
|
span_debug: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"forward proc_macro::Span's `Debug` impl to `Span`"),
|
"forward proc_macro::Span's `Debug` impl to `Span`"),
|
||||||
/// o/w tests have closure@path
|
/// o/w tests have closure@path
|
||||||
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
|
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"exclude spans when debug-printing compiler state (default: no)"),
|
"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],
|
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
|
||||||
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
|
"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")]
|
#[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"),
|
"control if mem::uninitialized and mem::zeroed panic on more UB"),
|
||||||
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
|
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
|
||||||
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
|
"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,
|
symbol_mangling_version: Option<SymbolManglingVersion> = (None,
|
||||||
parse_symbol_mangling_version, [TRACKED],
|
parse_symbol_mangling_version, [TRACKED],
|
||||||
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
|
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
|
||||||
|
@ -1565,17 +1562,6 @@ options! {
|
||||||
"show extended diagnostic help (default: no)"),
|
"show extended diagnostic help (default: no)"),
|
||||||
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||||
"the directory the intermediate files are written to"),
|
"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")]
|
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
|
||||||
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"enable ThinLTO when possible"),
|
"enable ThinLTO when possible"),
|
||||||
|
@ -1599,6 +1585,15 @@ options! {
|
||||||
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
||||||
trace_macros: bool = (false, parse_bool, [UNTRACKED],
|
trace_macros: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"for every macro invocation, print its name and arguments (default: no)"),
|
"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_path_to_local_path: bool = (true, parse_bool, [TRACKED],
|
||||||
"translate remapped paths into local paths when possible (default: yes)"),
|
"translate remapped paths into local paths when possible (default: yes)"),
|
||||||
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
|
@ -1607,6 +1602,8 @@ options! {
|
||||||
"treat error number `val` that occurs as bug"),
|
"treat error number `val` that occurs as bug"),
|
||||||
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
||||||
"in diagnostics, use heuristics to shorten paths referring to items"),
|
"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],
|
ui_testing: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"emit compiler diagnostics in a form suitable for UI testing (default: no)"),
|
"emit compiler diagnostics in a form suitable for UI testing (default: no)"),
|
||||||
uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
|
uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
|
||||||
|
@ -1647,9 +1644,8 @@ options! {
|
||||||
Requires `-Clto[=[fat,yes]]`"),
|
Requires `-Clto[=[fat,yes]]`"),
|
||||||
wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
|
wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
|
||||||
"whether to build a wasi command or reactor"),
|
"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:
|
// If you add a new option, please update:
|
||||||
// - compiler/rustc_interface/src/tests.rs
|
// - compiler/rustc_interface/src/tests.rs
|
||||||
}
|
}
|
||||||
|
|
|
@ -740,7 +740,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
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!(ArgAbi<'_, usize>, 56);
|
||||||
static_assert_size!(FnAbi<'_, usize>, 80);
|
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 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 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(
|
let unnormalized_env = ty::ParamEnv::new(
|
||||||
tcx.intern_predicates(&predicates),
|
tcx.intern_predicates(&predicates),
|
||||||
traits::Reveal::UserFacing,
|
traits::Reveal::UserFacing,
|
||||||
constness,
|
tcx.constness(def_id),
|
||||||
);
|
);
|
||||||
|
|
||||||
let body_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 {
|
.rustdoc .example-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
.rustdoc .example-wrap {
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
/* For the last child of a div, the margin will be taken care of
|
/* For the last child of a div, the margin will be taken care of
|
||||||
|
@ -718,7 +716,6 @@ nav.sub {
|
||||||
.source nav.sub {
|
.source nav.sub {
|
||||||
margin-left: 32px;
|
margin-left: 32px;
|
||||||
}
|
}
|
||||||
nav.sum { text-align: right; }
|
|
||||||
nav.sub form { display: inline; }
|
nav.sub form { display: inline; }
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
|
emitter::Emitter,
|
||||||
LazyFallbackBundle,
|
translation::{to_fluent_args, Translate},
|
||||||
|
Applicability, Diagnostic, Handler, LazyFallbackBundle,
|
||||||
};
|
};
|
||||||
use rustc_parse::parse_stream_from_source_str;
|
use rustc_parse::parse_stream_from_source_str;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
|
@ -193,7 +194,7 @@ impl Emitter for BufferEmitter {
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||||
let mut buffer = self.buffer.borrow_mut();
|
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);
|
let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
|
||||||
|
|
||||||
buffer.messages.push(format!("error from rustc: {}", translated_main_message));
|
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 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 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 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 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 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 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
|
-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 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-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 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 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 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)
|
-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-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-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 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-llvm=val -- enable LLVM inlining (default: yes)
|
||||||
-Z inline-mir=val -- enable MIR inlining (default: no)
|
-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-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 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:
|
-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)
|
`=all` (implicit value)
|
||||||
|
@ -67,6 +68,7 @@
|
||||||
`=off` (default)
|
`=off` (default)
|
||||||
-Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
|
-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 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-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 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)
|
-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 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-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-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-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 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 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)
|
-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-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
|
||||||
-Z no-link=val -- compile without linking
|
-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-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-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 normalize-docs=val -- normalize associated items in rustdoc when generating documentation
|
||||||
-Z oom=val -- panic strategy for out-of-memory handling
|
-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 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 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-abort-tests=val -- support compiling tests with panic=abort (default: no)
|
||||||
-Z panic-in-drop=val -- panic strategy for panics in drops
|
-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=val -- insert profiling code (default: no)
|
||||||
-Z profile-closures=val -- profile size of closures
|
-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 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 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 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 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 relax-elf-relocations=val -- whether ELF relocations can be relaxed
|
||||||
-Z relro-level=val -- choose which RELRO level to use
|
-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 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 report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
|
||||||
-Z sanitizer=val -- use a sanitizer
|
-Z sanitizer=val -- use a sanitizer
|
||||||
-Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
|
-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 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 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=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:
|
-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`)
|
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
|
||||||
`instructions:u` (retired instructions, userspace-only)
|
`instructions:u` (retired instructions, userspace-only)
|
||||||
`instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
|
`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 share-generics=val -- make the current crate share its generic instantiations
|
||||||
-Z show-span=val -- show spans for compiler debugging (expr|pat|ty)
|
-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-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 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 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 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-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
|
-Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
|
||||||
(default: `split`)
|
(default: `split`)
|
||||||
|
|
||||||
|
@ -159,14 +156,13 @@
|
||||||
file which is ignored by the linker
|
file which is ignored by the linker
|
||||||
`single`: sections which do not require relocation are written into object file but ignored
|
`single`: sections which do not require relocation are written into object file but ignored
|
||||||
by the linker
|
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 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 teach=val -- show extended diagnostic help (default: no)
|
||||||
-Z temps-dir=val -- the directory the intermediate files are written to
|
-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 thinlto=val -- enable ThinLTO when possible
|
||||||
-Z thir-unsafeck=val -- use the THIR unsafety checker (default: no)
|
-Z thir-unsafeck=val -- use the THIR unsafety checker (default: no)
|
||||||
-Z threads=val -- use a thread pool with N threads
|
-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 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 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 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 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 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 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 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 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 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)
|
-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::{
|
use rustc_errors::{
|
||||||
AddToDiagnostic, IntoDiagnostic, Diagnostic, DiagnosticBuilder,
|
AddToDiagnostic, IntoDiagnostic, Diagnostic, DiagnosticBuilder,
|
||||||
ErrorGuaranteed, Handler, fluent
|
ErrorGuaranteed, Handler, fluent, SubdiagnosticMessage,
|
||||||
};
|
};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -52,7 +52,10 @@ impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
|
||||||
pub struct UntranslatableInAddToDiagnostic;
|
pub struct UntranslatableInAddToDiagnostic;
|
||||||
|
|
||||||
impl AddToDiagnostic for 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");
|
diag.note("untranslatable diagnostic");
|
||||||
//~^ ERROR diagnostics should be created using translatable messages
|
//~^ ERROR diagnostics should be created using translatable messages
|
||||||
}
|
}
|
||||||
|
@ -61,7 +64,10 @@ impl AddToDiagnostic for UntranslatableInAddToDiagnostic {
|
||||||
pub struct TranslatableInAddToDiagnostic;
|
pub struct TranslatableInAddToDiagnostic;
|
||||||
|
|
||||||
impl AddToDiagnostic for 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);
|
diag.note(fluent::compiletest::note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: diagnostics should be created using translatable messages
|
error: diagnostics should be created using translatable messages
|
||||||
--> $DIR/diagnostics.rs:56:14
|
--> $DIR/diagnostics.rs:59:14
|
||||||
|
|
|
|
||||||
LL | diag.note("untranslatable diagnostic");
|
LL | diag.note("untranslatable diagnostic");
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
|
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);
|
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
|
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");
|
LL | let _diag = handler.struct_err("untranslatable diagnostic");
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: diagnostics should be created using translatable messages
|
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");
|
LL | let _diag = handler.struct_err("untranslatable diagnostic");
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
@ -678,3 +678,74 @@ enum ExampleEnum {
|
||||||
struct RawIdentDiagnosticArg {
|
struct RawIdentDiagnosticArg {
|
||||||
pub r#type: String,
|
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
|
= 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
|
error: cannot find attribute `nonsense` in this scope
|
||||||
--> $DIR/diagnostic-derive.rs:55:3
|
--> $DIR/diagnostic-derive.rs:55:3
|
||||||
|
|
|
|
||||||
|
@ -607,7 +647,7 @@ LL | arg: impl IntoDiagnosticArg,
|
||||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
| ^^^^^^^^^^^^^^^^^ 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)
|
= 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.
|
Some errors have detailed explanations: E0277, E0425.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
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
|
--> $DIR/removed-syntax-field-let.rs:2:5
|
||||||
|
|
|
|
||||||
LL | let foo: (),
|
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: 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
|
= 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
|
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 bins;
|
||||||
pub mod debug_artifacts;
|
pub mod debug_artifacts;
|
||||||
pub mod deps;
|
pub mod deps;
|
||||||
|
|
|
@ -90,6 +90,8 @@ fn main() {
|
||||||
check!(edition, &compiler_path);
|
check!(edition, &compiler_path);
|
||||||
check!(edition, &library_path);
|
check!(edition, &library_path);
|
||||||
|
|
||||||
|
check!(alphabetical, &compiler_path);
|
||||||
|
|
||||||
let collected = {
|
let collected = {
|
||||||
while handles.len() >= concurrency.get() {
|
while handles.len() >= concurrency.get() {
|
||||||
handles.pop_front().unwrap().join().unwrap();
|
handles.pop_front().unwrap().join().unwrap();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue