Auto merge of #122111 - matthiaskrgr:rollup-qq4v6gs, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #113518 (bootstrap/libtest: print test name eagerly on failure even with `verbose-tests=false` / `--quiet`)
 - #117199 (Change the documented implicit value of `-C instrument-coverage` to `=yes`)
 - #121190 (avoid overlapping privacy suggestion for single nested imports)
 - #121382 (Rework `untranslatable_diagnostic` lint)
 - #121959 (Removing absolute path in proc-macro)
 - #122038 (Fix linting paths with qself in `unused_qualifications`)
 - #122051 (cleanup: remove zero-offset GEP)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-03-06 21:39:53 +00:00
commit 7d3702e472
61 changed files with 678 additions and 200 deletions

View File

@ -1,6 +1,9 @@
use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt::{self, Write};
use std::iter;
use std::ops::Bound;
use std::ops::Deref;
use std::{borrow::Borrow, cmp, iter, ops::Bound};
use rustc_index::Idx;
use tracing::debug;
@ -32,7 +35,7 @@ where
pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>;
fn delayed_bug(&self, txt: String);
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>);
fn current_data_layout(&self) -> Self::TargetDataLayoutRef;
fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(

View File

@ -22,6 +22,7 @@ use std::collections::hash_map::Entry;
use std::fmt::Write;
impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn lower_inline_asm(
&mut self,
sp: Span,

View File

@ -1513,6 +1513,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
let yielded =
opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));

View File

@ -2272,6 +2272,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.expr_block(block)
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
match c.value.kind {
ExprKind::Underscore => {

View File

@ -17,6 +17,7 @@ use crate::errors;
macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
}
}};
@ -34,6 +35,7 @@ macro_rules! gate {
macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, $name, $span, $explain).emit();
}
}};
@ -73,6 +75,7 @@ struct PostExpansionVisitor<'a> {
}
impl<'a> PostExpansionVisitor<'a> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) {
let ast::StrLit { symbol_unescaped, span, .. } = abi;
@ -579,6 +582,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!"
{
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
.emit();
} else {

View File

@ -516,6 +516,7 @@ pub struct Condition {
}
/// Tests if a cfg-pattern matches the cfg set
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn cfg_matches(
cfg: &ast::MetaItem,
sess: &Session,
@ -566,6 +567,7 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
@ -592,6 +594,7 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn eval_condition(
cfg: &ast::MetaItem,
sess: &Session,

View File

@ -76,6 +76,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// LL | for (key, value) in dict {
/// | ^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub(super) fn add_moved_or_invoked_closure_note(
&self,
location: Location,
@ -585,6 +586,7 @@ impl UseSpans<'_> {
}
/// Add a span label to the arguments of the closure, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn args_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
@ -598,6 +600,7 @@ impl UseSpans<'_> {
/// Add a span label to the use of the captured variable, if it exists.
/// only adds label to the `path_span`
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_path_only_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
@ -635,6 +638,7 @@ impl UseSpans<'_> {
}
/// Add a subdiagnostic to the use of the captured variable, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_subdiag(
self,
dcx: &rustc_errors::DiagCtxt,
@ -1008,6 +1012,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.borrow_spans(span, borrow.reserve_location)
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn explain_captures(
&mut self,
err: &mut Diag<'_>,

View File

@ -201,6 +201,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// For generic associated types (GATs) which implied 'static requirement
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
// and the span which bounded to the trait for adding 'static lifetime suggestion
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn suggest_static_lifetime_for_gat_from_hrtb(
&self,
diag: &mut Diag<'_>,
@ -254,9 +256,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
hrtb_bounds.iter().for_each(|bound| {
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_note(
*trait_span,
"due to current limitations in the borrow checker, this implies a `'static` lifetime"
@ -580,6 +579,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_fnmut_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@ -761,6 +761,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
/// | is returning data with lifetime `'b`
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
let ErrorConstraintInfo {
fr,
@ -822,6 +823,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add_static_impl_trait_suggestion(
&self,
diag: &mut Diag<'_>,
@ -972,6 +975,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#[instrument(skip(self, err), level = "debug")]
fn suggest_constrain_dyn_trait_in_impl(
&self,
@ -1034,6 +1039,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
let map = self.infcx.tcx.hir();
let body_id = map.body_owned_by(self.mir_def_id());

View File

@ -94,8 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
if let OperandValue::Immediate(v) = cg_elem.val {
let zero = bx.const_usize(0);
let start = dest.project_index(bx, zero).llval;
let start = dest.llval;
let size = bx.const_usize(dest.layout.size.bytes());
// Use llvm.memset.p0i8.* to initialize all zero arrays

View File

@ -62,6 +62,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err(
&ccx.tcx.sess,
@ -556,6 +557,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
Status::Unstable(sym::const_mut_refs)
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err(
&ccx.tcx.sess,
@ -589,6 +591,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess,
@ -632,6 +635,7 @@ pub mod ty {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err(
&ccx.tcx.sess,

View File

@ -97,6 +97,7 @@ impl Expander {
/// **Note:** This function doesn't interpret argument 0 in any special way.
/// If this function is intended to be used with command line arguments,
/// `argv[0]` must be removed prior to calling it manually.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> {
let mut expander = Expander::default();
for arg in at_args {

View File

@ -4,6 +4,7 @@
//!
//! This API is completely unstable and subject to change.
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]

View File

@ -598,6 +598,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
///
/// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) {
assert!(
@ -631,6 +632,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_labels,
/// Labels all the given spans with the provided label.
/// See [`Self::span_label()`] for more information.
#[rustc_lint_diagnostics]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
for span in spans {
self.span_label(span, label.to_string());
@ -638,6 +640,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
#[rustc_lint_diagnostics]
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.span(after);
@ -653,6 +656,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
}
#[rustc_lint_diagnostics]
pub fn note_expected_found(
&mut self,
expected_label: &dyn fmt::Display,
@ -663,6 +667,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
}
#[rustc_lint_diagnostics]
pub fn note_expected_found_extra(
&mut self,
expected_label: &dyn fmt::Display,
@ -705,6 +710,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
}
#[rustc_lint_diagnostics]
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
StringPart::normal(format!("`{name}` from trait: `")),
@ -722,12 +728,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
#[rustc_lint_diagnostics]
fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
self
}
/// This is like [`Diag::note()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new());
self
@ -748,6 +756,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints the span with a note above it.
/// This is like [`Diag::note_once()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
@ -786,12 +795,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} }
/// This is like [`Diag::help()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceHelp, msg, MultiSpan::new());
self
}
/// Add a help message attached to this diagnostic with a customizable highlighted message.
#[rustc_lint_diagnostics]
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
self
@ -812,12 +823,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Disallow attaching suggestions this diagnostic.
/// Any suggestions attached e.g. with the `span_suggestion_*` methods
/// (before and after the call to `disable_suggestions`) will be ignored.
#[rustc_lint_diagnostics]
pub fn disable_suggestions(&mut self) -> &mut Self {
self.suggestions = Err(SuggestionsDisabled);
self
}
/// Helper for pushing to `self.suggestions`, if available (not disable).
#[rustc_lint_diagnostics]
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions {
for part in &subst.parts {
@ -838,6 +851,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_multipart_suggestion,
/// Show a suggestion that has multiple parts to it.
/// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -854,6 +868,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic.
/// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -869,6 +884,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
}
/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -911,6 +927,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability.
#[rustc_lint_diagnostics]
pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -943,6 +960,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// * may contain a name of a function, variable, or type, but not whole expressions
///
/// See `CodeSuggestion` for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion(
&mut self,
sp: Span,
@ -961,6 +979,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} }
/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
@ -986,6 +1005,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestion_verbose,
/// Always show the suggested change.
#[rustc_lint_diagnostics]
pub fn span_suggestion_verbose(
&mut self,
sp: Span,
@ -1006,6 +1026,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestions,
/// Prints out a message with multiple suggested edits of the code.
/// See also [`Diag::span_suggestion()`].
#[rustc_lint_diagnostics]
pub fn span_suggestions(
&mut self,
sp: Span,
@ -1022,6 +1043,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
)
} }
#[rustc_lint_diagnostics]
pub fn span_suggestions_with_style(
&mut self,
sp: Span,
@ -1052,6 +1074,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints out a message with multiple suggested edits of the code, where each edit consists of
/// multiple parts.
/// See also [`Diag::multipart_suggestion()`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -1098,6 +1121,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// inline, it will only show the message and not the suggestion.
///
/// See `CodeSuggestion` for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion_short(
&mut self,
sp: Span,
@ -1121,6 +1145,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability.
#[rustc_lint_diagnostics]
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
@ -1165,6 +1190,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// [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).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(
&mut self,
dcx: &crate::DiagCtxt,
@ -1180,6 +1206,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
@ -1188,6 +1215,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage });
self
@ -1195,6 +1223,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_code,
/// Add an error code.
#[rustc_lint_diagnostics]
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
@ -1202,6 +1231,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_primary_message,
/// Add a primary message.
#[rustc_lint_diagnostics]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
@ -1209,6 +1239,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_arg,
/// Add an argument.
#[rustc_lint_diagnostics]
pub fn arg(
&mut self,
name: impl Into<DiagArgName>,

View File

@ -1101,32 +1101,36 @@ impl DiagCtxt {
// Functions beginning with `struct_`/`create_` create a diagnostic. Other
// functions create and emit a diagnostic all in one go.
impl DiagCtxt {
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn struct_bug(&self, msg: impl Into<DiagMessage>) -> Diag<'_, BugAbort> {
Diag::new(self, Bug, msg)
pub fn struct_bug(&self, msg: impl Into<Cow<'static, str>>) -> Diag<'_, BugAbort> {
Diag::new(self, Bug, msg.into())
}
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn bug(&self, msg: impl Into<DiagMessage>) -> ! {
pub fn bug(&self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit()
}
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn struct_span_bug(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
msg: impl Into<Cow<'static, str>>,
) -> Diag<'_, BugAbort> {
self.struct_bug(msg).with_span(span)
}
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
self.struct_span_bug(span, msg).emit()
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_span_bug(span, msg.into()).emit()
}
#[track_caller]
@ -1240,24 +1244,28 @@ impl DiagCtxt {
}
/// Ensures that an error is printed. See `Level::DelayedBug`.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
//
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn delayed_bug(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
pub fn delayed_bug(&self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
}
/// Ensures that an error is printed. See `Level::DelayedBug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_err`, `span_warn`, etc.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
//
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn span_delayed_bug(
&self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
msg: impl Into<Cow<'static, str>>,
) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
}
#[rustc_lint_diagnostics]

View File

@ -1493,6 +1493,8 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
};
if crate_matches {
// FIXME: make this translatable
#[allow(rustc::untranslatable_diagnostic)]
sess.psess.buffer_lint_with_diagnostic(
PROC_MACRO_BACK_COMPAT,
item.ident.span,

View File

@ -239,6 +239,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
@ -273,6 +274,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn expand_cfg_attr_item(
&self,
attr: &Attribute,
@ -371,6 +373,7 @@ impl<'a> StripUnconfigured<'a> {
}
/// If attributes are not allowed on expressions, emit an error for `attr`
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if self.features.is_some_and(|features| !features.stmt_expr_attributes)
@ -384,7 +387,6 @@ impl<'a> StripUnconfigured<'a> {
);
if attr.is_doc_comment() {
#[allow(rustc::untranslatable_diagnostic)]
err.help("`///` is for documentation comments. For a plain comment, use `//`.");
}

View File

@ -783,6 +783,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
})
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
let kind = match item {
Annotatable::Item(_)
@ -825,6 +826,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind {
ItemKind::Mod(_, mod_kind)
@ -1689,6 +1691,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let features = self.cx.ecfg.features;
let mut attrs = attrs.iter().peekable();

View File

@ -5,6 +5,7 @@
#![feature(associated_type_defaults)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(macro_metavar_expr)]
#![feature(map_try_insert)]
#![feature(proc_macro_diagnostic)]

View File

@ -517,6 +517,9 @@ impl server::FreeFunctions for Rustc<'_, '_> {
Diag::new(&self.psess().dcx, diagnostic.level.to_internal(), message);
diag.span(MultiSpan::from_spans(diagnostic.spans));
for child in diagnostic.children {
// This message comes from another diagnostic, and we are just reconstructing the
// diagnostic, so there's no need for translation.
#[allow(rustc::untranslatable_diagnostic)]
diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans));
}
diag.emit();

View File

@ -178,6 +178,7 @@ impl<T: Write> Write for Shared<T> {
}
}
#[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
create_default_session_globals_then(|| {
let (handler, source_map, output) = create_test_handler();
@ -192,7 +193,6 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
println!("text: {:?}", source_map.span_to_snippet(span));
}
#[allow(rustc::untranslatable_diagnostic)]
handler.span_err(msp, "foo");
assert!(

View File

@ -695,8 +695,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
// Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints
// to assist in changes to diagnostic APIs.
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
// APIs. Any function with this attribute will be checked by that lint.
rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future).

View File

@ -320,6 +320,7 @@ pub struct Config {
// JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
trace!("run_compiler");

View File

@ -590,7 +590,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(force_frame_pointers, Some(false));
tracked!(force_unwind_tables, Some(true));
tracked!(inline_threshold, Some(0xf007ba11));
tracked!(instrument_coverage, InstrumentCoverage::All);
tracked!(instrument_coverage, InstrumentCoverage::Yes);
tracked!(link_dead_code, Some(true));
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);

View File

@ -160,6 +160,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
})
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
match unsafe { load_symbol_from_dylib::<MakeBackendFn>(path, "__rustc_codegen_backend") } {
Ok(backend_sym) => backend_sym,
@ -227,6 +228,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
})
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn get_codegen_sysroot(
early_dcx: &EarlyDiagCtxt,
maybe_sysroot: &Option<PathBuf>,
@ -319,6 +321,7 @@ fn get_codegen_sysroot(
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn check_attr_crate_type(
sess: &Session,
attrs: &[ast::Attribute],

View File

@ -621,12 +621,13 @@ pub trait LintContext {
/// Note that this function should only be called for [`LintExpectationId`]s
/// retrieved from the current lint pass. Buffered or manually created ids can
/// cause ICEs.
#[rustc_lint_diagnostics]
fn fulfill_expectation(&self, expectation: LintExpectationId) {
// We need to make sure that submitted expectation ids are correctly fulfilled suppressed
// and stored between compilation sessions. To not manually do these steps, we simply create
// a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal
// expected lint diagnostic.
// a dummy diagnostic and emit it as usual, which will be suppressed and stored like a
// normal expected lint diagnostic.
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
self.sess()
.dcx()
.struct_expect(

View File

@ -10,7 +10,7 @@ use rustc_ast as ast;
use rustc_hir::def::Res;
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
use rustc_middle::ty;
use rustc_middle::ty::{self, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol};
@ -338,10 +338,11 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
}
declare_tool_lint! {
/// The `untranslatable_diagnostic` lint detects diagnostics created
/// without using translatable Fluent strings.
/// The `untranslatable_diagnostic` lint detects messages passed to functions with `impl
/// Into<{D,Subd}iagMessage` parameters without using translatable Fluent strings.
///
/// More details on translatable diagnostics can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
/// More details on translatable diagnostics can be found
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
Deny,
"prevent creation of diagnostics which cannot be translated",
@ -349,11 +350,13 @@ declare_tool_lint! {
}
declare_tool_lint! {
/// The `diagnostic_outside_of_impl` lint detects diagnostics created manually,
/// and inside an `IntoDiagnostic`/`AddToDiagnostic` implementation,
/// or a `#[derive(Diagnostic)]`/`#[derive(Subdiagnostic)]` expansion.
/// The `diagnostic_outside_of_impl` lint detects calls to functions annotated with
/// `#[rustc_lint_diagnostics]` that are outside an `IntoDiagnostic`, `AddToDiagnostic`, or
/// `DecorateLint` impl, or a `#[derive(Diagnostic)]`, `#[derive(Subdiagnostic)]`,
/// `#[derive(DecorateLint)]` expansion.
///
/// More details on diagnostics implementations can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
/// More details on diagnostics implementations can be found
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
Deny,
"prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls",
@ -364,54 +367,130 @@ declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE
impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
debug!(?span, ?def_id, ?args);
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args)
// Only check function calls and method calls.
let (span, def_id, fn_gen_args, call_tys) = match expr.kind {
ExprKind::Call(callee, args) => {
match cx.typeck_results().node_type(callee.hir_id).kind() {
&ty::FnDef(def_id, fn_gen_args) => {
let call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
(callee.span, def_id, fn_gen_args, call_tys)
}
_ => return, // occurs for fns passed as args
}
}
ExprKind::MethodCall(segment, _recv, args, _span) => {
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
let fn_gen_args = cx.typeck_results().node_args(expr.hir_id);
let mut call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
(segment.ident.span, def_id, fn_gen_args, call_tys)
}
_ => return,
};
// Is the callee marked with `#[rustc_lint_diagnostics]`?
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
.ok()
.flatten()
.is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
if !has_attr {
return;
}
let mut found_parent_with_attr = false;
let mut found_impl = false;
for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
if let Some(owner_did) = hir_id.as_owner() {
found_parent_with_attr = found_parent_with_attr
|| cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics);
}
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint)
{
found_impl = true;
break;
}
}
debug!(?found_impl);
if !found_parent_with_attr && !found_impl {
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
}
let mut found_diagnostic_message = false;
for ty in args.types() {
debug!(?ty);
// Closure: is the type `{D,Subd}iagMessage`?
let is_diag_message = |ty: MiddleTy<'_>| {
if let Some(adt_def) = ty.ty_adt_def()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage)
{
found_diagnostic_message = true;
true
} else {
false
}
};
// Does the callee have a `impl Into<{D,Subd}iagMessage>` parameter? (There should be at
// most one.)
let mut impl_into_diagnostic_message_param = None;
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
for (i, &param_ty) in fn_sig.inputs().iter().enumerate() {
if let ty::Param(p) = param_ty.kind() {
// It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`.
for pred in predicates.iter() {
if let Some(trait_pred) = pred.as_trait_clause()
&& let trait_ref = trait_pred.skip_binder().trait_ref
&& trait_ref.self_ty() == param_ty // correct predicate for the param?
&& cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id)
&& let ty1 = trait_ref.args.type_at(1)
&& is_diag_message(ty1)
{
if impl_into_diagnostic_message_param.is_some() {
cx.tcx.dcx().span_bug(
span,
"can't handle multiple `impl Into<{D,Sub}iagMessage>` params",
);
}
impl_into_diagnostic_message_param = Some((i, p.name));
}
}
}
}
// Is the callee interesting?
if !has_attr && impl_into_diagnostic_message_param.is_none() {
return;
}
// Is the parent method marked with `#[rustc_lint_diagnostics]`?
let mut parent_has_attr = false;
for (hir_id, _parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
if let Some(owner_did) = hir_id.as_owner()
&& cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics)
{
parent_has_attr = true;
break;
}
}
debug!(?found_diagnostic_message);
if !found_parent_with_attr && !found_diagnostic_message {
cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
// Calls to `#[rustc_lint_diagnostics]`-marked functions should only occur:
// - inside an impl of `IntoDiagnostic`, `AddToDiagnostic`, or `DecorateLint`, or
// - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`.
//
// Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
if has_attr && !parent_has_attr {
let mut is_inside_appropriate_impl = false;
for (_hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(
name,
sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint
)
{
is_inside_appropriate_impl = true;
break;
}
}
debug!(?is_inside_appropriate_impl);
if !is_inside_appropriate_impl {
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
}
}
// Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
// with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
// `UNTRANSLATABLE_DIAGNOSTIC` lint.
if let Some((param_i, param_i_p_name)) = impl_into_diagnostic_message_param {
// Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
let arg_ty = call_tys[param_i];
let is_translatable = is_diag_message(arg_ty)
|| matches!(arg_ty.kind(), ty::Param(p) if p.name == param_i_p_name);
if !is_translatable {
cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
}
}
}
}
@ -425,7 +504,7 @@ declare_tool_lint! {
report_in_external_macro: true
}
declare_lint_pass!(BadOptAccess => [ BAD_OPT_ACCESS ]);
declare_lint_pass!(BadOptAccess => [BAD_OPT_ACCESS]);
impl LateLintPass<'_> for BadOptAccess {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {

View File

@ -104,6 +104,7 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
];
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
return;

View File

@ -724,6 +724,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
};
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) {
let sess = self.sess;
for (attr_index, attr) in attrs.iter().enumerate() {

View File

@ -947,6 +947,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file
let span = krate.spans.inner_span.shrink_to_lo();

View File

@ -93,6 +93,7 @@ struct Collector<'tcx> {
}
impl<'tcx> Collector<'tcx> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn process_module(&mut self, module: &ForeignModule) {
let ForeignModule { def_id, abi, ref foreign_items } = *module;
let def_id = def_id.expect_local();

View File

@ -17,6 +17,7 @@ use rustc_target::abi::call::FnAbi;
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
use std::borrow::Cow;
use std::cmp;
use std::fmt;
use std::num::NonZero;
@ -268,7 +269,7 @@ pub struct LayoutCx<'tcx, C> {
impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
type TargetDataLayoutRef = &'tcx TargetDataLayout;
fn delayed_bug(&self, txt: String) {
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
self.tcx.dcx().delayed_bug(txt);
}

View File

@ -13,7 +13,7 @@ use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use crate::ty::{List, ParamEnv};
use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
use rustc_errors::{DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan};
use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
@ -1543,7 +1543,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_error_with_message<S: Into<MultiSpan>>(
tcx: TyCtxt<'tcx>,
span: S,
msg: impl Into<DiagMessage>,
msg: impl Into<Cow<'static, str>>,
) -> Ty<'tcx> {
let reported = tcx.dcx().span_delayed_bug(span, msg);
Ty::new(tcx, Error(reported))

View File

@ -1074,6 +1074,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
/// of one item. Read the documentation of [`check_doc_inline`] for more information.
///
/// [`check_doc_inline`]: Self::check_doc_inline
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_doc_attrs(
&self,
attr: &Attribute,
@ -1756,6 +1757,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
/// Checks if the `#[repr]` attributes on `item` are valid.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_repr(
&self,
attrs: &[Attribute],
@ -2328,6 +2330,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
if let Some(hir_sig) = hir_sig {
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
match terr {
TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
if let Some(ty) = hir_sig.decl.inputs.get(idx) {

View File

@ -77,6 +77,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
}
/// Emits an error when an unsupported expression is found in a const context.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
let Self { tcx, def_id, const_kind } = *self;

View File

@ -114,6 +114,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
if let Some((def_id, _)) = visitor.start_fn {
Some((def_id.to_def_id(), EntryFnType::Start))

View File

@ -1736,7 +1736,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'a>) {
let PrivacyError { ident, binding, outermost_res, parent_scope, dedup_span } =
let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
*privacy_error;
let res = binding.res();
@ -1775,7 +1775,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&import_suggestions,
Instead::Yes,
FoundUse::Yes,
DiagMode::Import,
DiagMode::Import { append: single_nested },
vec![],
"",
);
@ -2701,7 +2701,11 @@ pub(crate) enum DiagMode {
/// The binding is part of a pattern
Pattern,
/// The binding is part of a use statement
Import,
Import {
/// `true` mean add the tips afterward for case `use a::{b,c}`,
/// rather than replacing within.
append: bool,
},
}
pub(crate) fn import_candidates(
@ -2726,6 +2730,8 @@ pub(crate) fn import_candidates(
);
}
type PathString<'a> = (String, &'a str, Option<DefId>, &'a Option<String>, bool);
/// When an entity with a given name is not available in scope, we search for
/// entities with that name in all crates. This method allows outputting the
/// results of this search in a programmer-friendly way. If any entities are
@ -2746,10 +2752,8 @@ fn show_candidates(
return false;
}
let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>, bool)> =
Vec::new();
let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>, bool)> =
Vec::new();
let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
candidates.iter().for_each(|c| {
if c.accessible {
@ -2811,6 +2815,15 @@ fn show_candidates(
err.note(note.clone());
}
let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
msg.push(':');
for candidate in accessible_path_strings {
msg.push('\n');
msg.push_str(&candidate.0);
}
};
if let Some(span) = use_placement_span {
let (add_use, trailing) = match mode {
DiagMode::Pattern => {
@ -2822,7 +2835,7 @@ fn show_candidates(
);
return true;
}
DiagMode::Import => ("", ""),
DiagMode::Import { .. } => ("", ""),
DiagMode::Normal => ("use ", ";\n"),
};
for candidate in &mut accessible_path_strings {
@ -2839,13 +2852,22 @@ fn show_candidates(
format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0);
}
err.span_suggestions_with_style(
span,
msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
SuggestionStyle::ShowAlways,
);
match mode {
DiagMode::Import { append: true, .. } => {
append_candidates(&mut msg, accessible_path_strings);
err.span_help(span, msg);
}
_ => {
err.span_suggestions_with_style(
span,
msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
SuggestionStyle::ShowAlways,
);
}
}
if let [first, .., last] = &path[..] {
let sp = first.ident.span.until(last.ident.span);
// Our suggestion is empty, so make sure the span is not empty (or we'd ICE).
@ -2860,17 +2882,11 @@ fn show_candidates(
}
}
} else {
msg.push(':');
for candidate in accessible_path_strings {
msg.push('\n');
msg.push_str(&candidate.0);
}
append_candidates(&mut msg, accessible_path_strings);
err.help(msg);
}
true
} else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagMode::Import)) {
} else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagMode::Import { .. })) {
let prefix =
if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
if let [(name, descr, def_id, note, _)] = &inaccessible_path_strings[..] {

View File

@ -868,7 +868,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.into_iter()
.find_map(|binding| if binding == ignore_binding { None } else { binding });
if let Some(Finalize { path_span, report_private, used, .. }) = finalize {
if let Some(Finalize { path_span, report_private, used, root_span, .. }) = finalize {
let Some(binding) = binding else {
return Err((Determined, Weak::No));
};
@ -881,6 +881,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
dedup_span: path_span,
outermost_res: None,
parent_scope: *parent_scope,
single_nested: path_span != root_span,
});
} else {
return Err((Determined, Weak::No));

View File

@ -715,7 +715,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&mut diag,
Some(err.span),
candidates,
DiagMode::Import,
DiagMode::Import { append: false },
(source != target)
.then(|| format!(" as {target}"))
.as_deref()

View File

@ -3953,6 +3953,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
self.r.record_partial_res(node_id, partial_res);
self.resolve_elided_lifetimes_in_path(partial_res, path, source, path_span);
self.lint_unused_qualifications(path, ns, finalize);
}
partial_res
@ -4145,39 +4146,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
};
if path.iter().all(|seg| !seg.ident.span.from_expansion()) {
let end_pos =
path.iter().position(|seg| seg.has_generic_args).map_or(path.len(), |pos| pos + 1);
let unqualified =
path[..end_pos].iter().enumerate().skip(1).rev().find_map(|(i, seg)| {
// Preserve the current namespace for the final path segment, but use the type
// namespace for all preceding segments
//
// e.g. for `std::env::args` check the `ValueNS` for `args` but the `TypeNS` for
// `std` and `env`
//
// If the final path segment is beyond `end_pos` all the segments to check will
// use the type namespace
let ns = if i + 1 == path.len() { ns } else { TypeNS };
let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
(res == binding.res()).then_some(seg)
});
if let Some(unqualified) = unqualified {
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::UNUSED_QUALIFICATIONS,
finalize.node_id,
finalize.path_span,
"unnecessary qualification",
lint::BuiltinLintDiag::UnusedQualifications {
removal_span: finalize.path_span.until(unqualified.ident.span),
},
);
}
}
Ok(Some(result))
}
@ -4656,6 +4624,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.r.doc_link_traits_in_scope = doc_link_traits_in_scope;
}
}
fn lint_unused_qualifications(&mut self, path: &[Segment], ns: Namespace, finalize: Finalize) {
if path.iter().any(|seg| seg.ident.span.from_expansion()) {
return;
}
let end_pos =
path.iter().position(|seg| seg.has_generic_args).map_or(path.len(), |pos| pos + 1);
let unqualified = path[..end_pos].iter().enumerate().skip(1).rev().find_map(|(i, seg)| {
// Preserve the current namespace for the final path segment, but use the type
// namespace for all preceding segments
//
// e.g. for `std::env::args` check the `ValueNS` for `args` but the `TypeNS` for
// `std` and `env`
//
// If the final path segment is beyond `end_pos` all the segments to check will
// use the type namespace
let ns = if i + 1 == path.len() { ns } else { TypeNS };
let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
(res == binding.res()).then_some(seg)
});
if let Some(unqualified) = unqualified {
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::UNUSED_QUALIFICATIONS,
finalize.node_id,
finalize.path_span,
"unnecessary qualification",
lint::BuiltinLintDiag::UnusedQualifications {
removal_span: path[0].ident.span.until(unqualified.ident.span),
},
);
}
}
}
/// Walks the whole crate in DFS order, visiting each item, counting the declared number of

View File

@ -729,6 +729,8 @@ struct PrivacyError<'a> {
dedup_span: Span,
outermost_res: Option<(Res, Ident)>,
parent_scope: ParentScope<'a>,
/// Is the format `use a::{b,c}`?
single_nested: bool,
}
#[derive(Debug)]

View File

@ -1,6 +1,8 @@
//! Contains infrastructure for configuring the compiler, including parsing
//! command-line options.
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub use crate::options::*;
use crate::errors::FileWriteFail;
@ -146,8 +148,10 @@ pub enum LtoCli {
/// unless the function has type parameters.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum InstrumentCoverage {
/// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
All,
/// `-C instrument-coverage=no` (or `off`, `false` etc.)
No,
/// `-C instrument-coverage` or `-C instrument-coverage=yes`
Yes,
/// Additionally, instrument branches and output branch coverage.
/// `-Zunstable-options -C instrument-coverage=branch`
Branch,
@ -155,8 +159,6 @@ pub enum InstrumentCoverage {
ExceptUnusedGenerics,
/// `-Zunstable-options -C instrument-coverage=except-unused-functions`
ExceptUnusedFunctions,
/// `-C instrument-coverage=off` (or `no`, etc.)
Off,
}
/// Settings for `-Z instrument-xray` flag.
@ -2468,9 +2470,7 @@ pub fn parse_externs(
));
let adjusted_name = name.replace('-', "_");
if is_ascii_ident(&adjusted_name) {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
error.help(format!(
"consider replacing the dashes with underscores: `{adjusted_name}`"
));
@ -2722,7 +2722,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
// This is what prevents them from being used on stable compilers.
match cg.instrument_coverage {
// Stable values:
InstrumentCoverage::All | InstrumentCoverage::Off => {}
InstrumentCoverage::Yes | InstrumentCoverage::No => {}
// Unstable values:
InstrumentCoverage::Branch
| InstrumentCoverage::ExceptUnusedFunctions
@ -2736,7 +2736,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
}
}
if cg.instrument_coverage != InstrumentCoverage::Off {
if cg.instrument_coverage != InstrumentCoverage::No {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_dcx.early_fatal(
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \

View File

@ -320,6 +320,7 @@ macro_rules! redirect_field {
type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_options<O: Default>(
early_dcx: &EarlyDiagCtxt,
matches: &getopts::Matches,
@ -394,8 +395,7 @@ mod desc {
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub const parse_instrument_coverage: &str =
"`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`";
pub const parse_instrument_coverage: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions`";
pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
@ -918,18 +918,18 @@ mod parse {
if v.is_some() {
let mut bool_arg = false;
if parse_bool(&mut bool_arg, v) {
*slot = if bool_arg { InstrumentCoverage::All } else { InstrumentCoverage::Off };
*slot = if bool_arg { InstrumentCoverage::Yes } else { InstrumentCoverage::No };
return true;
}
}
let Some(v) = v else {
*slot = InstrumentCoverage::All;
*slot = InstrumentCoverage::Yes;
return true;
};
*slot = match v {
"all" => InstrumentCoverage::All,
"all" => InstrumentCoverage::Yes,
"branch" => InstrumentCoverage::Branch,
"except-unused-generics" | "except_unused_generics" => {
InstrumentCoverage::ExceptUnusedGenerics
@ -937,7 +937,7 @@ mod parse {
"except-unused-functions" | "except_unused_functions" => {
InstrumentCoverage::ExceptUnusedFunctions
}
"off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
"0" => InstrumentCoverage::No,
_ => return false,
};
true
@ -1444,15 +1444,15 @@ options! {
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
"set the threshold for inlining a function"),
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::Off, parse_instrument_coverage, [TRACKED],
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
"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)
`=branch`
`=except-unused-generics`
`=except-unused-functions`
`=off` (default)"),
`=no` `=n` `=off` `=false` (default)
`=yes` `=y` `=on` `=true` (implicit value)
`=branch` (unstable)
`=except-unused-generics` (unstable)
`=except-unused-functions` (unstable)"),
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to append to the linker invocation (can be used several times)"),
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],

View File

@ -168,6 +168,7 @@ pub fn add_feature_diagnostics<G: EmissionGuarantee>(
/// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer
/// `add_feature_diagnostics`.
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
err: &mut Diag<'_, G>,
sess: &Session,

View File

@ -61,6 +61,7 @@ impl SearchPath {
(PathKind::All, path)
};
if path.is_empty() {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
early_dcx.early_fatal("empty search path given via `-L`");
}

View File

@ -312,6 +312,7 @@ impl Session {
) -> Diag<'a> {
let mut err = self.dcx().create_err(err);
if err.code.is_none() {
#[allow(rustc::diagnostic_outside_of_impl)]
err.code(E0658);
}
add_feature_diagnostics(&mut err, self, feature);
@ -352,7 +353,7 @@ impl Session {
}
pub fn instrument_coverage(&self) -> bool {
self.opts.cg.instrument_coverage() != InstrumentCoverage::Off
self.opts.cg.instrument_coverage() != InstrumentCoverage::No
}
pub fn instrument_coverage_branch(&self) -> bool {
@ -898,19 +899,6 @@ impl Session {
}
pub fn should_prefer_remapped_for_codegen(&self) -> bool {
// bail out, if any of the requested crate types aren't:
// "compiled executables or libraries"
for crate_type in &self.opts.crate_types {
match crate_type {
CrateType::Executable
| CrateType::Dylib
| CrateType::Rlib
| CrateType::Staticlib
| CrateType::Cdylib => continue,
CrateType::ProcMacro => return false,
}
}
let has_split_debuginfo = match self.split_debuginfo() {
SplitDebuginfo::Off => false,
SplitDebuginfo::Packed => true,
@ -1022,6 +1010,7 @@ fn default_emitter(
// JUSTIFICATION: literally session construction
#[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn build_session(
early_dcx: EarlyDiagCtxt,
sopts: config::Options,

View File

@ -23,6 +23,7 @@ pub(crate) struct TerseFormatter<T> {
max_name_len: usize,
test_count: usize,
test_column: usize,
total_test_count: usize,
}
@ -39,6 +40,7 @@ impl<T: Write> TerseFormatter<T> {
max_name_len,
is_multithreaded,
test_count: 0,
test_column: 0,
total_test_count: 0, // initialized later, when write_run_start is called
}
}
@ -47,8 +49,20 @@ impl<T: Write> TerseFormatter<T> {
self.write_short_result(".", term::color::GREEN)
}
pub fn write_failed(&mut self) -> io::Result<()> {
self.write_short_result("F", term::color::RED)
pub fn write_failed(&mut self, name: &str) -> io::Result<()> {
// Put failed tests on their own line and include the test name, so that it's faster
// to see which test failed without having to wait for them all to run.
// normally, we write the progress unconditionally, even if the previous line was cut short.
// but if this is the very first column, no short results will have been printed and we'll end up with *only* the progress on the line.
// avoid this.
if self.test_column != 0 {
self.write_progress()?;
}
self.test_count += 1;
self.write_plain(format!("{name} --- "))?;
self.write_pretty("FAILED", term::color::RED)?;
self.write_plain("\n")
}
pub fn write_ignored(&mut self) -> io::Result<()> {
@ -65,15 +79,22 @@ impl<T: Write> TerseFormatter<T> {
color: term::color::Color,
) -> io::Result<()> {
self.write_pretty(result, color)?;
if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
self.test_count += 1;
self.test_column += 1;
if self.test_column % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
// We insert a new line regularly in order to flush the
// screen when dealing with line-buffered output (e.g., piping to
// `stamp` in the rust CI).
let out = format!(" {}/{}\n", self.test_count + 1, self.total_test_count);
self.write_plain(out)?;
self.write_progress()?;
}
self.test_count += 1;
Ok(())
}
fn write_progress(&mut self) -> io::Result<()> {
let out = format!(" {}/{}\n", self.test_count, self.total_test_count);
self.write_plain(out)?;
self.test_column = 0;
Ok(())
}
@ -213,7 +234,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
match *result {
TestResult::TrOk => self.write_ok(),
TestResult::TrFailed | TestResult::TrFailedMsg(_) | TestResult::TrTimedFail => {
self.write_failed()
self.write_failed(desc.name.as_slice())
}
TestResult::TrIgnored => self.write_ignored(),
TestResult::TrBench(ref bs) => {

View File

@ -166,7 +166,7 @@ impl<'a> Renderer<'a> {
println!();
}
fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) {
fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) {
if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 {
if let Some(total) = self.tests_count {
let total = total.to_string();
@ -178,7 +178,7 @@ impl<'a> Renderer<'a> {
}
self.terse_tests_in_line += 1;
self.builder.colored_stdout(|stdout| outcome.write_short(stdout)).unwrap();
self.builder.colored_stdout(|stdout| outcome.write_short(stdout, &test.name)).unwrap();
let _ = std::io::stdout().flush();
}
@ -300,7 +300,7 @@ enum Outcome<'a> {
}
impl Outcome<'_> {
fn write_short(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> {
fn write_short(&self, writer: &mut dyn WriteColor, name: &str) -> Result<(), std::io::Error> {
match self {
Outcome::Ok => {
writer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
@ -311,8 +311,11 @@ impl Outcome<'_> {
write!(writer, "b")?;
}
Outcome::Failed => {
// Put failed tests on their own line and include the test name, so that it's faster
// to see which test failed without having to wait for them all to run.
writeln!(writer)?;
writer.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
write!(writer, "F")?;
writeln!(writer, "{name} ... F")?;
}
Outcome::Ignored { .. } => {
writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?;

View File

@ -331,10 +331,29 @@ $ llvm-cov report \
## `-C instrument-coverage=<options>`
- `-C instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-C instrument-coverage`, with no value.)
- `-C instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-C instrument-coverage` option.)
- `-Zunstable-options -C instrument-coverage=except-unused-generics`: Instrument all functions except unused generics.
- `-Zunstable-options -C instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions.
- `-C instrument-coverage=no` (or `n`/`off`/`false`):
Don't enable coverage instrumentation. No functions will be instrumented for coverage.
- This is the same as not using the `-C instrument-coverage` flag at all.
- `-C instrument-coverage=yes` (or `y`/`on`/`true`):
Enable coverage instrumentation with the default behaviour.
Currently this instruments all functions, including unused functions and unused generics.
- This is the same as `-C instrument-coverage` with no value.
### Other values
- `-C instrument-coverage=all`:
Currently an alias for `yes`, but may behave differently in the future if
more fine-grained coverage options are added.
Using this value is currently not recommended.
### Unstable values
- `-Z unstable-options -C instrument-coverage=branch`:
Placeholder for potential branch coverage support in the future.
- `-Z unstable-options -C instrument-coverage=except-unused-generics`:
Instrument all functions except unused generics.
- `-Z unstable-options -C instrument-coverage=except-unused-functions`:
Instrument only used (called) functions and instantiated generic functions.
## Other references

View File

@ -1,5 +1,6 @@
//! Compute the binary representation of a type
use std::borrow::Cow;
use std::fmt;
use base_db::salsa::Cycle;
@ -114,8 +115,8 @@ struct LayoutCx<'a> {
impl<'a> LayoutCalculator for LayoutCx<'a> {
type TargetDataLayoutRef = &'a TargetDataLayout;
fn delayed_bug(&self, txt: String) {
never!("{}", txt);
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
never!("{}", txt.into());
}
fn current_data_layout(&self) -> &'a TargetDataLayout {

View File

@ -360,6 +360,7 @@ mod tests {
}
fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> DiagInner {
#[allow(rustc::untranslatable_diagnostic)] // no translation needed for empty string
let mut diag = DiagInner::new(level, "");
diag.messages.clear();
if let Some(span) = span {

View File

@ -14,8 +14,8 @@ extern crate rustc_session;
extern crate rustc_span;
use rustc_errors::{
AddToDiagnostic, Diag, EmissionGuarantee, DiagCtxt, IntoDiagnostic, Level,
SubdiagMessageOp,
AddToDiagnostic, DecorateLint, Diag, DiagCtxt, DiagInner, DiagMessage, EmissionGuarantee,
IntoDiagnostic, Level, SubdiagMessageOp,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@ -78,6 +78,31 @@ impl AddToDiagnostic for TranslatableInAddToDiagnostic {
}
}
pub struct UntranslatableInDecorateLint;
impl<'a> DecorateLint<'a, ()> for UntranslatableInDecorateLint {
fn decorate_lint<'b, >(self, diag: &'b mut Diag<'a, ()>) {
diag.note("untranslatable diagnostic");
//~^ ERROR diagnostics should be created using translatable messages
}
fn msg(&self) -> DiagMessage {
unreachable!();
}
}
pub struct TranslatableInDecorateLint;
impl<'a> DecorateLint<'a, ()> for TranslatableInDecorateLint {
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
diag.note(crate::fluent_generated::no_crate_note);
}
fn msg(&self) -> DiagMessage {
unreachable!();
}
}
pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) {
let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
//~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
@ -87,9 +112,11 @@ pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) {
//~^^ ERROR diagnostics should be created using translatable messages
}
// Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted.
// Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted for
// `diagnostic_outside_of_impl`.
#[rustc_lint_diagnostics]
pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) {
#[allow(rustc::untranslatable_diagnostic)]
let _diag = dcx.struct_err("untranslatable diagnostic"); // okay!
}

View File

@ -16,8 +16,14 @@ error: diagnostics should be created using translatable messages
LL | diag.note("untranslatable diagnostic");
| ^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:85:14
|
LL | diag.note("untranslatable diagnostic");
| ^^^^
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
--> $DIR/diagnostics.rs:82:21
--> $DIR/diagnostics.rs:107:21
|
LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^
@ -29,16 +35,16 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
--> $DIR/diagnostics.rs:85:21
--> $DIR/diagnostics.rs:110:21
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:85:21
--> $DIR/diagnostics.rs:110:21
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^
error: aborting due to 5 previous errors
error: aborting due to 6 previous errors

View File

@ -0,0 +1,16 @@
// https://github.com/rust-lang/rust/issues/114884
mod mod1 {
pub trait TraitA {}
}
mod mod2 {
mod sub_mod {
use super::super::mod1::TraitA;
}
}
use mod2::{sub_mod::TraitA};
//~^ ERROR: module `sub_mod` is private
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0603]: module `sub_mod` is private
--> $DIR/append-import-suggestion.rs:13:12
|
LL | use mod2::{sub_mod::TraitA};
| ^^^^^^^ private module
|
help: consider importing this trait instead:
mod1::TraitA
--> $DIR/append-import-suggestion.rs:13:12
|
LL | use mod2::{sub_mod::TraitA};
| ^^^^^^^^^^^^^^^
note: the module `sub_mod` is defined here
--> $DIR/append-import-suggestion.rs:8:5
|
LL | mod sub_mod {
| ^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0603`.

View File

@ -1,2 +1,2 @@
error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
error: incorrect value `bad-value` for codegen option `instrument-coverage` - either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions` was expected

View File

@ -1,2 +1,2 @@
error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
error: incorrect value `` for codegen option `instrument-coverage` - either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions` was expected

View File

@ -24,6 +24,9 @@ fn main() {
use std::fmt;
let _: fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
let _ = <bool as Default>::default(); // issue #121999
//~^ ERROR: unnecessary qualification
macro_rules! m { ($a:ident, $b:ident) => {
$crate::foo::bar(); // issue #37357
::foo::bar(); // issue #38682

View File

@ -24,6 +24,9 @@ fn main() {
use std::fmt;
let _: std::fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
let _ = <bool as ::std::default::Default>::default(); // issue #121999
//~^ ERROR: unnecessary qualification
macro_rules! m { ($a:ident, $b:ident) => {
$crate::foo::bar(); // issue #37357
::foo::bar(); // issue #38682

View File

@ -87,5 +87,17 @@ LL - let _: std::fmt::Result = Ok(());
LL + let _: fmt::Result = Ok(());
|
error: aborting due to 7 previous errors
error: unnecessary qualification
--> $DIR/lint-qualification.rs:27:13
|
LL | let _ = <bool as ::std::default::Default>::default(); // issue #121999
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the unnecessary path segments
|
LL - let _ = <bool as ::std::default::Default>::default(); // issue #121999
LL + let _ = <bool as Default>::default(); // issue #121999
|
error: aborting due to 8 previous errors

View File

@ -0,0 +1,125 @@
//@ compile-flags: --test
//@ run-fail
//@ run-flags: --test-threads=1 --quiet
//@ check-run-results
//@ exec-env:RUST_BACKTRACE=0
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
//@ ignore-emscripten no threads support
//@ needs-unwind
#[test]
fn abc() {
panic!();
}
#[test]
fn foo() {
panic!();
}
#[test]
fn foo2() {
panic!();
}
// run a whole bunch of tests so we can see what happens when we go over 88 columns
#[test] fn f0() {}
#[test] fn f1() {}
#[test] fn f2() {}
#[test] fn f3() {}
#[test] fn f4() {}
#[test] fn f5() {}
#[test] fn f6() {}
#[test] fn f7() {}
#[test] fn f8() {}
#[test] fn f9() {}
#[test] fn f10() {}
#[test] fn f11() {}
#[test] fn f12() {}
#[test] fn f13() {}
#[test] fn f14() {}
#[test] fn f15() {}
#[test] fn f16() {}
#[test] fn f17() {}
#[test] fn f18() {}
#[test] fn f19() {}
#[test] fn f20() {}
#[test] fn f21() {}
#[test] fn f22() {}
#[test] fn f23() {}
#[test] fn f24() {}
#[test] fn f25() {}
#[test] fn f26() {}
#[test] fn f27() {}
#[test] fn f28() {}
#[test] fn f29() {}
#[test] fn f30() {}
#[test] fn f31() {}
#[test] fn f32() {}
#[test] fn f33() {}
#[test] fn f34() {}
#[test] fn f35() {}
#[test] fn f36() {}
#[test] fn f37() {}
#[test] fn f38() {}
#[test] fn f39() {}
#[test] fn f40() {}
#[test] fn f41() {}
#[test] fn f42() {}
#[test] fn f43() {}
#[test] fn f44() {}
#[test] fn f45() {}
#[test] fn f46() {}
#[test] fn f47() {}
#[test] fn f48() {}
#[test] fn f49() {}
#[test] fn f50() {}
#[test] fn f51() {}
#[test] fn f52() {}
#[test] fn f53() {}
#[test] fn f54() {}
#[test] fn f55() {}
#[test] fn f56() {}
#[test] fn f57() {}
#[test] fn f58() {}
#[test] fn f59() {}
#[test] fn f60() {}
#[test] fn f61() {}
#[test] fn f62() {}
#[test] fn f63() {}
#[test] fn f64() {}
#[test] fn f65() {}
#[test] fn f66() {}
#[test] fn f67() {}
#[test] fn f68() {}
#[test] fn f69() {}
#[test] fn f70() {}
#[test] fn f71() {}
#[test] fn f72() {}
#[test] fn f73() {}
#[test] fn f74() {}
#[test] fn f75() {}
#[test] fn f76() {}
#[test] fn f77() {}
#[test] fn f78() {}
#[test] fn f79() {}
#[test] fn f80() {}
#[test] fn f81() {}
#[test] fn f82() {}
#[test] fn f83() {}
#[test] fn f84() {}
#[test] fn f85() {}
#[test] fn f86() {}
#[test] fn f87() {}
#[test] fn f88() {}
#[test] fn f89() {}
#[test] fn f90() {}
#[test] fn f91() {}
#[test] fn f92() {}
#[test] fn f93() {}
#[test] fn f94() {}
#[test] fn f95() {}
#[test] fn f96() {}
#[test] fn f97() {}
#[test] fn f98() {}
#[test] fn f99() {}

View File

@ -0,0 +1,31 @@
running 103 tests
abc --- FAILED
....................................................................................... 88/103
............. 101/103
foo --- FAILED
foo2 --- FAILED
failures:
---- abc stdout ----
thread 'abc' panicked at $DIR/terse.rs:12:5:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
---- foo stdout ----
thread 'foo' panicked at $DIR/terse.rs:17:5:
explicit panic
---- foo2 stdout ----
thread 'foo2' panicked at $DIR/terse.rs:22:5:
explicit panic
failures:
abc
foo
foo2
test result: FAILED. 100 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME